Add Wyatt Continuous Deployment as Sub package #236
| @ -1,26 +1,21 @@ | |||||||
| // // Copyright (C) 2022 WYATT GROUP | // Copyright (C) 2024 WYATT GROUP | ||||||
| // // Please see the AUTHORS file for details. | // Please see the AUTHORS file for details. | ||||||
| // // | // | ||||||
| // // This program is free software: you can redistribute it and/or modify | // This program is free software: you can redistribute it and/or modify | ||||||
| // // it under the terms of the GNU General Public License as published by | // it under the terms of the GNU General Public License as published by | ||||||
| // // the Free Software Foundation, either version 3 of the License, or | // the Free Software Foundation, either version 3 of the License, or | ||||||
| // // any later version. | // any later version. | ||||||
| // // | // | ||||||
| // // This program is distributed in the hope that it will be useful, | // This program is distributed in the hope that it will be useful, | ||||||
| // // but WITHOUT ANY WARRANTY; without even the implied warranty of | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
| // // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
| // // GNU General Public License for more details. | // GNU General Public License for more details. | ||||||
| // // | // | ||||||
| // // You should have received a copy of the GNU General Public License | // You should have received a copy of the GNU General Public License | ||||||
| // // along with this program. If not, see <https://www.gnu.org/licenses/>. | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
| 
 |  | ||||||
| // // ignore_for_file: avoid_positional_boolean_parameters |  | ||||||
| 
 | 
 | ||||||
| import 'dart:async'; | import 'dart:async'; | ||||||
| 
 | 
 | ||||||
| part 'future_result.dart'; |  | ||||||
| part 'future_or_result.dart'; |  | ||||||
| part 'result.dart'; |  | ||||||
| part 'option.dart'; | part 'option.dart'; | ||||||
| 
 | 
 | ||||||
| mixin _Left<LeftType, RightType> on _EitherBase<LeftType, RightType> {} | mixin _Left<LeftType, RightType> on _EitherBase<LeftType, RightType> {} | ||||||
| @ -35,7 +30,9 @@ class _EitherBaseException implements Exception { | |||||||
|   String toString() => '_EitherException: $message'; |   String toString() => '_EitherException: $message'; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @Deprecated('Use Dart pattern matching instead') | ||||||
| abstract class _EitherBase<LeftType, RightType> { | abstract class _EitherBase<LeftType, RightType> { | ||||||
|  |   @Deprecated('Use Dart pattern matching instead') | ||||||
|   const _EitherBase(); |   const _EitherBase(); | ||||||
| 
 | 
 | ||||||
|   bool get _isLeft => this is _Left<LeftType, RightType>; |   bool get _isLeft => this is _Left<LeftType, RightType>; | ||||||
| @ -56,20 +53,20 @@ abstract class _EitherBase<LeftType, RightType> { | |||||||
|     if (U == LeftType) { |     if (U == LeftType) { | ||||||
|       return _fold<LeftType>( |       return _fold<LeftType>( | ||||||
|         (value) => value, |         (value) => value, | ||||||
|         (right) => throw const ResultException( |         (right) => throw Exception( | ||||||
|           'Illegal use. You should check left value before calling', |           'Illegal use. You should check left value before calling', | ||||||
|         ), |         ), | ||||||
|       ) as U; |       ) as U; | ||||||
|     } |     } | ||||||
|     if (U == RightType) { |     if (U == RightType) { | ||||||
|       return _fold<RightType>( |       return _fold<RightType>( | ||||||
|         (left) => throw const ResultException( |         (left) => throw Exception( | ||||||
|           'Illegal use. You should check right value before calling', |           'Illegal use. You should check right value before calling', | ||||||
|         ), |         ), | ||||||
|         (value) => value, |         (value) => value, | ||||||
|       ) as U; |       ) as U; | ||||||
|     } |     } | ||||||
|     throw ResultException( |     throw Exception( | ||||||
|       'Illegal use. You should use $LeftType or $RightType type', |       'Illegal use. You should use $LeftType or $RightType type', | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| @ -78,20 +75,20 @@ abstract class _EitherBase<LeftType, RightType> { | |||||||
|     if (U == LeftType) { |     if (U == LeftType) { | ||||||
|       return _foldAsync<LeftType>( |       return _foldAsync<LeftType>( | ||||||
|         Future.value, |         Future.value, | ||||||
|         (right) => throw const ResultException( |         (right) => throw Exception( | ||||||
|           'Illegal use. You should check left value before calling', |           'Illegal use. You should check left value before calling', | ||||||
|         ), |         ), | ||||||
|       ) as Future<U>; |       ) as Future<U>; | ||||||
|     } |     } | ||||||
|     if (U == RightType) { |     if (U == RightType) { | ||||||
|       return _foldAsync<RightType>( |       return _foldAsync<RightType>( | ||||||
|         (left) => throw const ResultException( |         (left) => throw Exception( | ||||||
|           'Illegal use. You should check right value before calling', |           'Illegal use. You should check right value before calling', | ||||||
|         ), |         ), | ||||||
|         Future.value, |         Future.value, | ||||||
|       ) as Future<U>; |       ) as Future<U>; | ||||||
|     } |     } | ||||||
|     throw ResultException( |     throw Exception( | ||||||
|       'Illegal use. You should use $LeftType or $RightType type', |       'Illegal use. You should use $LeftType or $RightType type', | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP | // Copyright (C) 2024 WYATT GROUP | ||||||
| // Please see the AUTHORS file for details. | // Please see the AUTHORS file for details. | ||||||
| // | // | ||||||
| // This program is free software: you can redistribute it and/or modify | // This program is free software: you can redistribute it and/or modify | ||||||
| @ -41,8 +41,10 @@ class OptionException extends _EitherBaseException { | |||||||
| /// if value not present) and ifPresent() (execute a block of code if the | /// if value not present) and ifPresent() (execute a block of code if the | ||||||
| /// value is present). | /// value is present). | ||||||
| /// {@endtemplate} | /// {@endtemplate} | ||||||
|  | @Deprecated('Use Dart pattern matching instead') | ||||||
| abstract class Option<T> extends _EitherBase<T, void> { | abstract class Option<T> extends _EitherBase<T, void> { | ||||||
|   /// {@macro option} |   /// {@macro option} | ||||||
|  |   @Deprecated('Use Dart pattern matching instead') | ||||||
|   const Option._(); |   const Option._(); | ||||||
| 
 | 
 | ||||||
|   /// Represents the left side of [Option] class. |   /// Represents the left side of [Option] class. | ||||||
|  | |||||||
| @ -1,325 +0,0 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP |  | ||||||
| // Please see the AUTHORS file for details. |  | ||||||
| // |  | ||||||
| // This program is free software: you can redistribute it and/or modify |  | ||||||
| // it under the terms of the GNU General Public License as published by |  | ||||||
| // the Free Software Foundation, either version 3 of the License, or |  | ||||||
| // any later version. |  | ||||||
| // |  | ||||||
| // This program is distributed in the hope that it will be useful, |  | ||||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
| // GNU General Public License for more details. |  | ||||||
| // |  | ||||||
| // You should have received a copy of the GNU General Public License |  | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. |  | ||||||
| 
 |  | ||||||
| // ignore_for_file: avoid_positional_boolean_parameters |  | ||||||
| 
 |  | ||||||
| part of 'either_base.dart'; |  | ||||||
| 
 |  | ||||||
| /// {@template result_exception} |  | ||||||
| /// [ResultException] is sometimes threw by [Result] objects. |  | ||||||
| /// |  | ||||||
| /// ```dart |  | ||||||
| /// throw ResultException('Emergency failure!'); |  | ||||||
| /// ``` |  | ||||||
| /// {@endtemplate} |  | ||||||
| class ResultException extends _EitherBaseException { |  | ||||||
|   /// {@macro result_exception} |  | ||||||
|   const ResultException(super.message); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   String toString() => 'ResultException: $message'; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// {@template result} |  | ||||||
| /// [Result] type is coming from functional languages where exceptions are |  | ||||||
| /// (rightfully) considered a side-effect, and therefore not appropriate to |  | ||||||
| /// pass domain errors. Mind the difference between different kinds of errors: |  | ||||||
| /// Some of them belong to domain, others don't. |  | ||||||
| /// |  | ||||||
| /// *E.g. null reference exception or index out of bounds |  | ||||||
| /// are not related to domain - they rather indicate a defect.* |  | ||||||
| /// |  | ||||||
| /// Either is defined as a generic type with two branches |  | ||||||
| /// - success with [T] |  | ||||||
| /// - failure with [E] |  | ||||||
| /// |  | ||||||
| /// It can appear in two forms, where |  | ||||||
| /// it contains an object of [Ok], or where it contains an object |  | ||||||
| /// of [Err]. It cannot appear in both states at once, or in none of them. |  | ||||||
| /// Therefore, if one possesses an [Result] instance, it either contains a |  | ||||||
| /// successfully produced result, or contains an error object. |  | ||||||
| /// {@endtemplate} |  | ||||||
| abstract class Result<T, E> extends _EitherBase<T, E> { |  | ||||||
|   /// {@macro result} |  | ||||||
|   const Result._(); |  | ||||||
| 
 |  | ||||||
|   /// Represents the left side of [Result] class. |  | ||||||
|   bool get isOk => _isLeft; |  | ||||||
| 
 |  | ||||||
|   /// Represents the right side of [Result] class. |  | ||||||
|   bool get isErr => _isRight; |  | ||||||
| 
 |  | ||||||
|   /// Get nullable [Ok] value, and discarding the error, if any. |  | ||||||
|   T? get ok => _left; |  | ||||||
| 
 |  | ||||||
|   /// Get nullable [Err] value, and discarding the success value, if any. |  | ||||||
|   E? get err => _right; |  | ||||||
| 
 |  | ||||||
|   /// Get [U] value, may throw an exception. |  | ||||||
|   U unwrap<U>() => _unwrap<U>(); |  | ||||||
| 
 |  | ||||||
|   /// Get **async** [U] value, may throw an exception. |  | ||||||
|   Future<U> unwrapAsync<U>() => _unwrapAsync<U>(); |  | ||||||
| 
 |  | ||||||
|   /// Fold [Ok] and [Err] into the value of one type |  | ||||||
|   U fold<U>( |  | ||||||
|     U Function(T value) valueTransformer, |  | ||||||
|     U Function(E error) errorTransformer, |  | ||||||
|   ) => |  | ||||||
|       _fold( |  | ||||||
|         (left) => valueTransformer(left), |  | ||||||
|         (right) => errorTransformer(right), |  | ||||||
|       ); |  | ||||||
| 
 |  | ||||||
|   /// Fold [Ok] and [Err] **asynchronously** into the value of one type |  | ||||||
|   Future<U> foldAsync<U>( |  | ||||||
|     Future<U> Function(T value) valueTransformer, |  | ||||||
|     Future<U> Function(E error) errorTransformer, |  | ||||||
|   ) => |  | ||||||
|       _foldAsync( |  | ||||||
|         (left) => valueTransformer(left), |  | ||||||
|         (right) => errorTransformer(right), |  | ||||||
|       ); |  | ||||||
| 
 |  | ||||||
|   /// Swap [Ok] and [Err] |  | ||||||
|   Result<E, T> swap() => fold(Err.new, Ok.new); |  | ||||||
| 
 |  | ||||||
|   /// Returns [res] if the [Result] is [Ok], otherwise returns |  | ||||||
|   /// the [Err] value of this. |  | ||||||
|   Result<U, E> and<U>(Result<U, E> res) => _and<U>(res) as Result<U, E>; |  | ||||||
| 
 |  | ||||||
|   /// Returns [res] if the [Result] is [Err], otherwise returns |  | ||||||
|   /// the [Ok] value of this. |  | ||||||
|   Result<T, F> or<F>(Result<T, F> res) => _or<F>(res) as Result<T, F>; |  | ||||||
| 
 |  | ||||||
|   /// Returns true if the result is an [Ok] or [Err] value containing |  | ||||||
|   /// the given value/error. |  | ||||||
|   bool contains<U>(U x) => _contains(x); |  | ||||||
| 
 |  | ||||||
|   /// Returns the contained [Ok] value. Throw [ResultException] on [Err] with |  | ||||||
|   /// its content. |  | ||||||
|   T expect(String msg) => _expect(msg); |  | ||||||
| 
 |  | ||||||
|   /// Returns the contained [Err] value. Throw [ResultException] on [Ok] with |  | ||||||
|   /// its content. |  | ||||||
|   E expectErr(String msg) => _expectErr(msg); |  | ||||||
| 
 |  | ||||||
|   /// Maps a [Result<T, E>] to [Result<U, E>] by applying a function to a |  | ||||||
|   /// contained [Ok] value, leaving an [Err] value untouched. |  | ||||||
|   Result<U, E> map<U>(U Function(T value) mapper) => |  | ||||||
|       _map(mapper) as Result<U, E>; |  | ||||||
| 
 |  | ||||||
|   /// Maps a [Result<T, E>] to [Result<U, E>] by applying an **async** function |  | ||||||
|   /// to a contained [Ok] value, leaving an [Err] value untouched. |  | ||||||
|   Future<Result<U, E>> mapAsync<U>(Future<U> Function(T value) mapper) => |  | ||||||
|       _mapAsync(mapper) as Future<Result<U, E>>; |  | ||||||
| 
 |  | ||||||
|   /// Maps a [Result<T, E>] to [Result<T, F>] by applying a function to a |  | ||||||
|   /// contained [Err] value, leaving an [Ok] value untouched. |  | ||||||
|   Result<T, F> mapErr<F>(F Function(E error) mapper) => |  | ||||||
|       _mapErr(mapper) as Result<T, F>; |  | ||||||
| 
 |  | ||||||
|   /// Maps a [Result<T, E>] to [Result<U, E>] by applying an **async** function |  | ||||||
|   /// to a contained [Err] value, leaving an [Ok] value untouched. |  | ||||||
|   Future<Result<T, F>> mapErrAsync<F>(Future<F> Function(E error) mapper) => |  | ||||||
|       _mapErrAsync(mapper) as Future<Result<T, F>>; |  | ||||||
| 
 |  | ||||||
|   /// Transforms a [Result<T, E>] to [Result<U, F>] by applying functions to |  | ||||||
|   /// contained [Ok] and [Err] values. |  | ||||||
|   Result<U, F> either<U, F>( |  | ||||||
|     U Function(T value) valueTransformer, |  | ||||||
|     F Function(E error) errorTransformer, |  | ||||||
|   ) => |  | ||||||
|       _either<U, F>(valueTransformer, errorTransformer) as Result<U, F>; |  | ||||||
| 
 |  | ||||||
|   /// Transforms a [Result<T, E>] to [Result<U, F>] by applying **async** |  | ||||||
|   /// functions to contained [Ok] and [Err] values. |  | ||||||
|   Future<Result<U, F>> eitherAsync<U, F>( |  | ||||||
|     Future<U> Function(T value) valueTransformer, |  | ||||||
|     Future<F> Function(E error) errorTransformer, |  | ||||||
|   ) => |  | ||||||
|       _eitherAsync<U, F>(valueTransformer, errorTransformer) |  | ||||||
|           as Future<Result<U, F>>; |  | ||||||
| 
 |  | ||||||
|   /// Constructs a new [Result] from a function that might throw |  | ||||||
|   static Result<T, E> tryCatch<T, E, Error extends Object>( |  | ||||||
|     T Function() tryFn, |  | ||||||
|     E Function(Error error) onError, |  | ||||||
|   ) { |  | ||||||
|     try { |  | ||||||
|       return Ok(tryFn()); |  | ||||||
|     } on Error catch (e) { |  | ||||||
|       return Err(onError(e)); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// Constructs a new [Result] from an **async** function that might throw |  | ||||||
|   static Future<Result<T, E>> tryCatchAsync<T, E, Error extends Object>( |  | ||||||
|     Future<T> Function() tryFn, |  | ||||||
|     E Function(Error error) onError, |  | ||||||
|   ) async { |  | ||||||
|     try { |  | ||||||
|       return Ok(await tryFn()); |  | ||||||
|     } on Error catch (e) { |  | ||||||
|       return Err(onError(e)); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// If the condition is satify then return [value] in |  | ||||||
|   /// [Ok] else [error] in [Err] |  | ||||||
|   static Result<T, E> conditional<T, E>( |  | ||||||
|     bool test, |  | ||||||
|     T value, |  | ||||||
|     E error, |  | ||||||
|   ) => |  | ||||||
|       test ? Ok(value) : Err(error); |  | ||||||
| 
 |  | ||||||
|   /// If the condition is satify then return *command* [value] |  | ||||||
|   /// in [Ok] else [error] in [Err] |  | ||||||
|   static Result<T, E> conditionalLazy<T, E>( |  | ||||||
|     bool test, |  | ||||||
|     T Function() value, |  | ||||||
|     E Function() error, |  | ||||||
|   ) => |  | ||||||
|       test ? Ok(value()) : Err(error()); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// {@template ok} |  | ||||||
| /// Contains the success value of a [Result] |  | ||||||
| /// |  | ||||||
| /// {@macro result} |  | ||||||
| /// {@endtemplate} |  | ||||||
| class Ok<T, E> extends Result<T, E> with _Left<T, E> { |  | ||||||
|   /// {@macro ok} |  | ||||||
|   const Ok(this.value) : super._(); |  | ||||||
|   final T value; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   U _fold<U>(U Function(T left) fnL, U Function(E right) fnR) => fnL(value); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<U> _foldAsync<U>( |  | ||||||
|     Future<U> Function(T left) fnL, |  | ||||||
|     Future<U> Function(E right) fnR, |  | ||||||
|   ) => |  | ||||||
|       fnL(value); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Result<U, E> _and<U>(_EitherBase<U, E> res) => res as Result<U, E>; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Result<T, F> _or<F>(_EitherBase<T, F> res) => this as Result<T, F>; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   bool _contains<U>(U x) => value == x; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   T _expect(String msg) => value; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   E _expectErr(String msg) => throw ResultException('$msg: $value'); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Result<U, E> _map<U>(U Function(T value) mapper) => Ok(mapper(value)); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<Result<U, E>> _mapAsync<U>(Future<U> Function(T value) mapper) => |  | ||||||
|       mapper(value).then(Ok.new); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Result<T, F> _mapErr<F>(F Function(E error) mapper) => Ok(value); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<Result<T, F>> _mapErrAsync<F>(Future<F> Function(E error) mapper) => |  | ||||||
|       Future.value(Ok(value)); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Result<U, F> _either<U, F>( |  | ||||||
|     U Function(T value) fnL, |  | ||||||
|     F Function(E error) fnR, |  | ||||||
|   ) => |  | ||||||
|       Ok(fnL(value)); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<Result<U, F>> _eitherAsync<U, F>( |  | ||||||
|     Future<U> Function(T value) fnL, |  | ||||||
|     Future<F> Function(E error) fnR, |  | ||||||
|   ) => |  | ||||||
|       fnL(value).then(Ok.new); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// {@template err} |  | ||||||
| /// Contains the error value of a [Result] |  | ||||||
| /// |  | ||||||
| /// {@macro result} |  | ||||||
| /// {@endtemplate} |  | ||||||
| class Err<T, E> extends Result<T, E> with _Right<T, E> { |  | ||||||
|   /// {@macro err} |  | ||||||
|   const Err(this.error) : super._(); |  | ||||||
|   final E error; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   U _fold<U>(U Function(T left) fnL, U Function(E right) fnR) => fnR(error); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<U> _foldAsync<U>( |  | ||||||
|     Future<U> Function(T left) fnL, |  | ||||||
|     Future<U> Function(E right) fnR, |  | ||||||
|   ) => |  | ||||||
|       fnR(error); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Result<U, E> _and<U>(_EitherBase<U, E> res) => this as Result<U, E>; |  | ||||||
|   @override |  | ||||||
|   Result<T, F> _or<F>(_EitherBase<T, F> res) => res as Result<T, F>; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   bool _contains<U>(U x) => error == x; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   T _expect(String msg) => throw ResultException('$msg: $error'); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   E _expectErr(String msg) => error; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Result<U, E> _map<U>(U Function(T value) mapper) => Err(error); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<Result<U, E>> _mapAsync<U>(Future<U> Function(T value) mapper) => |  | ||||||
|       Future.value(Err(error)); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Result<T, F> _mapErr<F>(F Function(E error) mapper) => Err(mapper(error)); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<Result<T, F>> _mapErrAsync<F>(Future<F> Function(E error) mapper) => |  | ||||||
|       mapper(error).then(Err.new); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Result<U, F> _either<U, F>( |  | ||||||
|     U Function(T value) fnL, |  | ||||||
|     F Function(E error) fnR, |  | ||||||
|   ) => |  | ||||||
|       Err(fnR(error)); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<Result<U, F>> _eitherAsync<U, F>( |  | ||||||
|     Future<U> Function(T value) fnL, |  | ||||||
|     Future<F> Function(E error) fnR, |  | ||||||
|   ) => |  | ||||||
|       fnR(error).then(Err.new); |  | ||||||
| } |  | ||||||
| @ -37,13 +37,10 @@ extension IterableIntExtension on Iterable<int>? { | |||||||
|     switch (to) { |     switch (to) { | ||||||
|       case Encoding.utf8: |       case Encoding.utf8: | ||||||
|         str = utf8.decode(this?.toList() ?? []); |         str = utf8.decode(this?.toList() ?? []); | ||||||
|         break; |  | ||||||
|       case Encoding.utf16: |       case Encoding.utf16: | ||||||
|         str = String.fromCharCodes(this ?? []); |         str = String.fromCharCodes(this ?? []); | ||||||
|         break; |  | ||||||
|       case Encoding.base64: |       case Encoding.base64: | ||||||
|         str = base64.encode(this?.toList() ?? []); |         str = base64.encode(this?.toList() ?? []); | ||||||
|         break; |  | ||||||
|       case Encoding.base16: |       case Encoding.base16: | ||||||
|         str = List.generate( |         str = List.generate( | ||||||
|           (this ?? []).length, |           (this ?? []).length, | ||||||
|  | |||||||
| @ -33,13 +33,10 @@ extension StringExtension on String? { | |||||||
|     switch (from) { |     switch (from) { | ||||||
|       case Encoding.utf8: |       case Encoding.utf8: | ||||||
|         bytes = utf8.encode(this ?? '').toTypedList(); |         bytes = utf8.encode(this ?? '').toTypedList(); | ||||||
|         break; |  | ||||||
|       case Encoding.utf16: |       case Encoding.utf16: | ||||||
|         bytes = (this ?? '').runes.toList().toTypedList(); |         bytes = (this ?? '').runes.toList().toTypedList(); | ||||||
|         break; |  | ||||||
|       case Encoding.base64: |       case Encoding.base64: | ||||||
|         bytes = base64.decode(this ?? ''); |         bytes = base64.decode(this ?? ''); | ||||||
|         break; |  | ||||||
|       case Encoding.base16: |       case Encoding.base16: | ||||||
|         assert( |         assert( | ||||||
|           (this ?? '').length.isEven, |           (this ?? '').length.isEven, | ||||||
|  | |||||||
| @ -21,8 +21,10 @@ extension PairExtension<T> on Pair<T, T> { | |||||||
| /// {@template pair} | /// {@template pair} | ||||||
| /// [Pair] is a simple object which contains pair of two values. | /// [Pair] is a simple object which contains pair of two values. | ||||||
| /// {@endtemplate} | /// {@endtemplate} | ||||||
|  | @Deprecated('Use Dart built-in record type instead') | ||||||
| class Pair<L, R> { | class Pair<L, R> { | ||||||
|   /// {@macro pair} |   /// {@macro pair} | ||||||
|  |   @Deprecated('Use Dart built-in record type instead') | ||||||
|   const Pair(this.left, this.right); |   const Pair(this.left, this.right); | ||||||
|   final L? left; |   final L? left; | ||||||
|   final R? right; |   final R? right; | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP | // Copyright (C) 2024 WYATT GROUP | ||||||
| // Please see the AUTHORS file for details. | // Please see the AUTHORS file for details. | ||||||
| // | // | ||||||
| // This program is free software: you can redistribute it and/or modify | // This program is free software: you can redistribute it and/or modify | ||||||
| @ -14,7 +14,9 @@ | |||||||
| // You should have received a copy of the GNU General Public License | // You should have received a copy of the GNU General Public License | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
| 
 | 
 | ||||||
| part of 'either_base.dart'; | import 'dart:async'; | ||||||
|  | 
 | ||||||
|  | import 'package:wyatt_type_utils/src/result/result.dart'; | ||||||
| 
 | 
 | ||||||
| extension FutureOrResultExtension<T, E> on FutureOr<Result<T, E>> { | extension FutureOrResultExtension<T, E> on FutureOr<Result<T, E>> { | ||||||
|   /// Represents the left side of [Result] class. |   /// Represents the left side of [Result] class. | ||||||
| @ -72,13 +74,13 @@ extension FutureOrResultExtension<T, E> on FutureOr<Result<T, E>> { | |||||||
|   Future<bool> contains<U>(U x) => |   Future<bool> contains<U>(U x) => | ||||||
|       Future.value(this).then((result) => result.contains(x)); |       Future.value(this).then((result) => result.contains(x)); | ||||||
| 
 | 
 | ||||||
|   /// Returns the contained [Ok] value. Throw [ResultException] on [Err] with |   /// Returns the contained [Ok] value. Throw [ResultException] on | ||||||
|   /// its content. |   /// [Err] with its content. | ||||||
|   Future<T> expect(String msg) => |   Future<T> expect(String msg) => | ||||||
|       Future.value(this).then((result) => result.expect(msg)); |       Future.value(this).then((result) => result.expect(msg)); | ||||||
| 
 | 
 | ||||||
|   /// Returns the contained [Err] value. Throw [ResultException] on [Ok] with |   /// Returns the contained [Err] value. Throw [ResultException] on | ||||||
|   /// its content. |   /// [Ok] with its content. | ||||||
|   Future<E> expectErr(String msg) => |   Future<E> expectErr(String msg) => | ||||||
|       Future.value(this).then((result) => result.expectErr(msg)); |       Future.value(this).then((result) => result.expectErr(msg)); | ||||||
| 
 | 
 | ||||||
| @ -1,4 +1,4 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP | // Copyright (C) 2024 WYATT GROUP | ||||||
| // Please see the AUTHORS file for details. | // Please see the AUTHORS file for details. | ||||||
| // | // | ||||||
| // This program is free software: you can redistribute it and/or modify | // This program is free software: you can redistribute it and/or modify | ||||||
| @ -14,7 +14,7 @@ | |||||||
| // You should have received a copy of the GNU General Public License | // You should have received a copy of the GNU General Public License | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
| 
 | 
 | ||||||
| part of 'either_base.dart'; | import 'package:wyatt_type_utils/src/result/result.dart'; | ||||||
| 
 | 
 | ||||||
| extension FutureResultExtension<T, E> on Future<Result<T, E>> { | extension FutureResultExtension<T, E> on Future<Result<T, E>> { | ||||||
|   /// Represents the left side of [Result] class. |   /// Represents the left side of [Result] class. | ||||||
| @ -62,12 +62,12 @@ extension FutureResultExtension<T, E> on Future<Result<T, E>> { | |||||||
|   /// the given value/error. |   /// the given value/error. | ||||||
|   Future<bool> contains<U>(U x) => then((result) => result.contains(x)); |   Future<bool> contains<U>(U x) => then((result) => result.contains(x)); | ||||||
| 
 | 
 | ||||||
|   /// Returns the contained [Ok] value. Throw [ResultException] on [Err] with |   /// Returns the contained [Ok] value. Throw [ResultException] on | ||||||
|   /// its content. |   /// [Err] with its content. | ||||||
|   Future<T> expect(String msg) => then((result) => result.expect(msg)); |   Future<T> expect(String msg) => then((result) => result.expect(msg)); | ||||||
| 
 | 
 | ||||||
|   /// Returns the contained [Err] value. Throw [ResultException] on [Ok] with |   /// Returns the contained [Err] value. Throw [ResultException] on | ||||||
|   /// its content. |   /// [Ok] with its content. | ||||||
|   Future<E> expectErr(String msg) => then((result) => result.expectErr(msg)); |   Future<E> expectErr(String msg) => then((result) => result.expectErr(msg)); | ||||||
| 
 | 
 | ||||||
|   /// Maps a [Result<T, E>] to [Result<U, E>] by applying a function to a |   /// Maps a [Result<T, E>] to [Result<U, E>] by applying a function to a | ||||||
							
								
								
									
										346
									
								
								packages/wyatt_type_utils/lib/src/result/result.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										346
									
								
								packages/wyatt_type_utils/lib/src/result/result.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,346 @@ | |||||||
|  | // Copyright (C) 2024 WYATT GROUP | ||||||
|  | // Please see the AUTHORS file for details. | ||||||
|  | // | ||||||
|  | // This program is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or | ||||||
|  | // any later version. | ||||||
|  | // | ||||||
|  | // This program is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  | // GNU General Public License for more details. | ||||||
|  | // | ||||||
|  | // You should have received a copy of the GNU General Public License | ||||||
|  | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
|  | 
 | ||||||
|  | // ignore_for_file: avoid_equals_and_hash_code_on_mutable_classes | ||||||
|  | 
 | ||||||
|  | import 'package:sealed_result/sealed_result.dart' as sealed; | ||||||
|  | 
 | ||||||
|  | export 'future_or_result.dart'; | ||||||
|  | export 'future_result.dart'; | ||||||
|  | 
 | ||||||
|  | class ResultException extends sealed.ResultException { | ||||||
|  |   const ResultException(String super.message); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// {@template result} | ||||||
|  | /// [Result] type is coming from functional languages where exceptions are | ||||||
|  | /// (rightfully) considered a side-effect, and therefore not appropriate to | ||||||
|  | /// pass domain errors. Mind the difference between different kinds of errors: | ||||||
|  | /// Some of them belong to domain, others don't. | ||||||
|  | /// | ||||||
|  | /// *E.g. null reference exception or index out of bounds | ||||||
|  | /// are not related to domain - they rather indicate a defect.* | ||||||
|  | /// | ||||||
|  | /// Either is defined as a generic type with two branches | ||||||
|  | /// - success with [Success] | ||||||
|  | /// - failure with [Failure] | ||||||
|  | /// | ||||||
|  | /// It can appear in two forms, where | ||||||
|  | /// it contains an object of [Ok], or where it contains an object | ||||||
|  | /// of [Err]. It cannot appear in both states at once, or in none of them. | ||||||
|  | /// Therefore, if one possesses an [Result] instance, it either contains a | ||||||
|  | /// successfully produced result, or contains an error object. | ||||||
|  | /// {@endtemplate} | ||||||
|  | class Result<Success, Failure> { | ||||||
|  |   /// {@macro result} | ||||||
|  |   const Result._(this._result); | ||||||
|  | 
 | ||||||
|  |   factory Result.ok(Success value) => Ok(value); | ||||||
|  |   factory Result.err(Failure value) => Err(value); | ||||||
|  |   factory Result.error(Failure value) => Err(value); | ||||||
|  |   factory Result.success(Success value) => Ok(value); | ||||||
|  |   factory Result.failure(Failure value) => Err(value); | ||||||
|  | 
 | ||||||
|  |   final sealed.Result<Success, Failure> _result; | ||||||
|  | 
 | ||||||
|  |   /// Represents the left side of [Result] class. | ||||||
|  |   bool get isOk => _result.isOk; | ||||||
|  | 
 | ||||||
|  |   /// Represents the right side of [Result] class. | ||||||
|  |   bool get isErr => _result.isErr; | ||||||
|  | 
 | ||||||
|  |   /// Get nullable [Ok] value, and discarding the error, if any. | ||||||
|  |   Success? get ok => _result.ok; | ||||||
|  | 
 | ||||||
|  |   /// Get nullable [Err] value, and discarding the success value, if any. | ||||||
|  |   Failure? get err => _result.err; | ||||||
|  | 
 | ||||||
|  |   /// Get [U] value, may throw an exception. | ||||||
|  |   U unwrap<U>() { | ||||||
|  |     if (U == Success) { | ||||||
|  |       return fold<Success>( | ||||||
|  |         (value) => value, | ||||||
|  |         (right) => throw const ResultException( | ||||||
|  |           'Illegal use. You should check left value before calling', | ||||||
|  |         ), | ||||||
|  |       ) as U; | ||||||
|  |     } | ||||||
|  |     if (U == Failure) { | ||||||
|  |       return fold<Failure>( | ||||||
|  |         (left) => throw const ResultException( | ||||||
|  |           'Illegal use. You should check right value before calling', | ||||||
|  |         ), | ||||||
|  |         (value) => value, | ||||||
|  |       ) as U; | ||||||
|  |     } | ||||||
|  |     throw ResultException( | ||||||
|  |       'Illegal use. You should use $Success or $Failure type', | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /// Get **async** [U] value, may throw an exception. | ||||||
|  |   Future<U> unwrapAsync<U>() { | ||||||
|  |     if (U == Success) { | ||||||
|  |       return foldAsync<Success>( | ||||||
|  |         Future.value, | ||||||
|  |         (right) => throw const ResultException( | ||||||
|  |           'Illegal use. You should check left value before calling', | ||||||
|  |         ), | ||||||
|  |       ) as Future<U>; | ||||||
|  |     } | ||||||
|  |     if (U == Failure) { | ||||||
|  |       return foldAsync<Failure>( | ||||||
|  |         (left) => throw const ResultException( | ||||||
|  |           'Illegal use. You should check right value before calling', | ||||||
|  |         ), | ||||||
|  |         Future.value, | ||||||
|  |       ) as Future<U>; | ||||||
|  |     } | ||||||
|  |     throw ResultException( | ||||||
|  |       'Illegal use. You should use $Success or $Failure type', | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /// Fold [Ok] and [Err] into the value of one type | ||||||
|  |   U fold<U>( | ||||||
|  |     U Function(Success value) valueTransformer, | ||||||
|  |     U Function(Failure error) errorTransformer, | ||||||
|  |   ) => | ||||||
|  |       _result.fold( | ||||||
|  |         (ok) => valueTransformer(ok), | ||||||
|  |         (err) => errorTransformer(err), | ||||||
|  |       ); | ||||||
|  | 
 | ||||||
|  |   /// Fold [Ok] and [Err] **asynchronously** into the value of one type | ||||||
|  |   Future<U> foldAsync<U>( | ||||||
|  |     Future<U> Function(Success value) valueTransformer, | ||||||
|  |     Future<U> Function(Failure error) errorTransformer, | ||||||
|  |   ) => | ||||||
|  |       _result.foldAsync( | ||||||
|  |         (ok) => valueTransformer(ok), | ||||||
|  |         (err) => errorTransformer(err), | ||||||
|  |       ); | ||||||
|  | 
 | ||||||
|  |   /// Swap [Ok] and [Err] | ||||||
|  |   Result<Failure, Success> swap() => fold( | ||||||
|  |         Err.new, | ||||||
|  |         Ok.new, | ||||||
|  |       ); | ||||||
|  | 
 | ||||||
|  |   /// Returns [res] if the [Result] is [Ok], otherwise returns | ||||||
|  |   /// the [Err] value of this. | ||||||
|  |   Result<U, Failure> and<U>(Result<U, Failure> res) => Result._( | ||||||
|  |         _result.and(res._result), | ||||||
|  |       ); | ||||||
|  | 
 | ||||||
|  |   /// Returns [res] if the [Result] is [Err], otherwise returns | ||||||
|  |   /// the [Ok] value of this. | ||||||
|  |   Result<Success, F> or<F>(Result<Success, F> res) => Result._( | ||||||
|  |         _result.or(res._result), | ||||||
|  |       ); | ||||||
|  | 
 | ||||||
|  |   /// Returns true if the result is an [Ok] or [Err] value containing | ||||||
|  |   /// the given value/error. | ||||||
|  |   bool contains<U>(U x) { | ||||||
|  |     if (x is Success) { | ||||||
|  |       return _result.contains(x); | ||||||
|  |     } else if (x is Failure) { | ||||||
|  |       return _result.containsErr(x); | ||||||
|  |     } else { | ||||||
|  |       throw ArgumentError('The value must be of type Success or Failure'); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /// Returns the contained [Ok] value. Throw [ResultException] on [Err] | ||||||
|  |   /// with its content. | ||||||
|  |   Success expect(String msg) { | ||||||
|  |     try { | ||||||
|  |       return _result.expect(msg); | ||||||
|  |     } on sealed.ResultException catch (e) { | ||||||
|  |       throw ResultException(e.message.toString()); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /// Returns the contained [Err] value. Throw [ResultException] on [Ok] | ||||||
|  |   /// with its content. | ||||||
|  |   Failure expectErr(String msg) { | ||||||
|  |     try { | ||||||
|  |       return _result.expectErr(msg); | ||||||
|  |     } on sealed.ResultException catch (e) { | ||||||
|  |       throw ResultException(e.message.toString()); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /// Maps a [Result<Success, Failure>] to [Result<U, Failure>] by applying a | ||||||
|  |   /// function to a contained [Ok] value, leaving an [Err] value untouched. | ||||||
|  |   Result<U, Failure> map<U>(U Function(Success value) mapper) => | ||||||
|  |       Result._(_result.map(mapper)); | ||||||
|  | 
 | ||||||
|  |   /// Maps a [Result<Success, Failure>] to [Result<U, Failure>] by applying | ||||||
|  |   /// an **async** function to a contained [Ok] value, leaving an [Err] | ||||||
|  |   /// value untouched. | ||||||
|  |   Future<Result<U, Failure>> mapAsync<U>( | ||||||
|  |     Future<U> Function(Success value) mapper, | ||||||
|  |   ) async { | ||||||
|  |     final result = await _result.mapAsync(mapper); | ||||||
|  |     return Result._(result); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /// Maps a [Result<Success, Failure>] to [Result<Success, F>] by applying a | ||||||
|  |   /// function to a contained [Err] value, leaving an [Ok] value untouched. | ||||||
|  |   Result<Success, F> mapErr<F>(F Function(Failure error) mapper) => | ||||||
|  |       Result._(_result.mapErr(mapper)); | ||||||
|  | 
 | ||||||
|  |   /// Maps a [Result<Success, Failure>] to [Result<U, Failure>] by applying | ||||||
|  |   /// an **async** function to a contained [Err] value, leaving an [Ok] | ||||||
|  |   /// value untouched. | ||||||
|  |   Future<Result<Success, F>> mapErrAsync<F>( | ||||||
|  |     Future<F> Function(Failure error) mapper, | ||||||
|  |   ) async { | ||||||
|  |     final result = await _result.mapErrAsync(mapper); | ||||||
|  |     return Result._(result); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /// Transforms a [Result<Success, Failure>] to [Result<U, F>] by applying | ||||||
|  |   /// functions to contained [Ok] and [Err] values. | ||||||
|  |   Result<U, F> either<U, F>( | ||||||
|  |     U Function(Success value) valueTransformer, | ||||||
|  |     F Function(Failure error) errorTransformer, | ||||||
|  |   ) => | ||||||
|  |       Result._( | ||||||
|  |         _result | ||||||
|  |             .map( | ||||||
|  |               valueTransformer, | ||||||
|  |             ) | ||||||
|  |             .mapErr( | ||||||
|  |               errorTransformer, | ||||||
|  |             ), | ||||||
|  |       ); | ||||||
|  | 
 | ||||||
|  |   /// Transforms a [Result<Success, Failure>] to [Result<U, F>] by | ||||||
|  |   /// applying **async** functions to contained [Ok] and [Err] values. | ||||||
|  |   Future<Result<U, F>> eitherAsync<U, F>( | ||||||
|  |     Future<U> Function(Success value) valueTransformer, | ||||||
|  |     Future<F> Function(Failure error) errorTransformer, | ||||||
|  |   ) => | ||||||
|  |       _result | ||||||
|  |           .mapAsync( | ||||||
|  |             valueTransformer, | ||||||
|  |           ) | ||||||
|  |           .mapErrAsync( | ||||||
|  |             errorTransformer, | ||||||
|  |           ) | ||||||
|  |           .then(Result._); | ||||||
|  | 
 | ||||||
|  |   /// Constructs a new [Result] from a function that might throw | ||||||
|  |   static Result<Success, Failure> | ||||||
|  |       tryCatch<Success, Failure, Error extends Object>( | ||||||
|  |     Success Function() tryFn, | ||||||
|  |     Failure Function(Error error) onError, | ||||||
|  |   ) { | ||||||
|  |     try { | ||||||
|  |       return Ok(tryFn()); | ||||||
|  |     } on Error catch (e) { | ||||||
|  |       return Err(onError(e)); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /// Constructs a new [Result] from an **async** function that might throw | ||||||
|  |   static Future<Result<Success, Failure>> | ||||||
|  |       tryCatchAsync<Success, Failure, Error extends Object>( | ||||||
|  |     Future<Success> Function() tryFn, | ||||||
|  |     Failure Function(Error error) onError, | ||||||
|  |   ) async { | ||||||
|  |     try { | ||||||
|  |       return Ok(await tryFn()); | ||||||
|  |     } on Error catch (e) { | ||||||
|  |       return Err(onError(e)); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /// If the condition is satify then return [value] in | ||||||
|  |   /// [Ok] else [error] in [Err] | ||||||
|  |   static Result<Success, Failure> conditional<Success, Failure>( | ||||||
|  |     Success value, | ||||||
|  |     Failure error, { | ||||||
|  |     required bool test, | ||||||
|  |   }) => | ||||||
|  |       test ? Ok(value) : Err(error); | ||||||
|  | 
 | ||||||
|  |   /// If the condition is satify then return *command* [value] | ||||||
|  |   /// in [Ok] else [error] in [Err] | ||||||
|  |   static Result<Success, Failure> conditionalLazy<Success, Failure>( | ||||||
|  |     Success Function() value, | ||||||
|  |     Failure Function() error, | ||||||
|  |     bool Function() predicate, | ||||||
|  |   ) => | ||||||
|  |       predicate.call() ? Ok(value()) : Err(error()); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   int get hashCode => _result.hashCode; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   bool operator ==(Object other) { | ||||||
|  |     if (identical(this, other)) { | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     return other is Result<Success, Failure> && other._result == _result; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | final class Ok<Success, Failure> extends Result<Success, Failure> { | ||||||
|  |   Ok(this.ok) : super._(sealed.Ok(ok)); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   final Success ok; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   bool get isErr => false; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   bool get isOk => true; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Failure? get err => null; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   String toString() => switch (ok) { | ||||||
|  |         null => 'Ok(null)', | ||||||
|  |         Future() => 'Ok(${ok.runtimeType})', | ||||||
|  |         _ => 'Ok($ok)', | ||||||
|  |       }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | final class Err<Success, Failure> extends Result<Success, Failure> { | ||||||
|  |   Err(this.err) : super._(sealed.Err(err)); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   final Failure err; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   bool get isErr => true; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   bool get isOk => false; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Success? get ok => null; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   String toString() => switch (err) { | ||||||
|  |         _ => 'Err($err)', | ||||||
|  |       }; | ||||||
|  | } | ||||||
| @ -1,4 +1,4 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP | // Copyright (C) 2024 WYATT GROUP | ||||||
| // Please see the AUTHORS file for details. | // Please see the AUTHORS file for details. | ||||||
| // | // | ||||||
| // This program is free software: you can redistribute it and/or modify | // This program is free software: you can redistribute it and/or modify | ||||||
| @ -17,3 +17,4 @@ | |||||||
| export 'either/either_base.dart'; | export 'either/either_base.dart'; | ||||||
| export 'extensions/extensions.dart'; | export 'extensions/extensions.dart'; | ||||||
| export 'pair/pair.dart'; | export 'pair/pair.dart'; | ||||||
|  | export 'result/result.dart'; | ||||||
|  | |||||||
| @ -6,11 +6,14 @@ version: 0.0.5 | |||||||
| publish_to: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub | publish_to: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub | ||||||
| 
 | 
 | ||||||
| environment: | environment: | ||||||
|   sdk: ">=2.17.0 <3.0.0" |   sdk: "^3.0.0" | ||||||
|  | 
 | ||||||
|  | dependencies: | ||||||
|  |   sealed_result: ^3.0.0 | ||||||
| 
 | 
 | ||||||
| dev_dependencies: | dev_dependencies: | ||||||
|   test: ^1.22.0 |   test: ^1.22.0 | ||||||
| 
 | 
 | ||||||
|   wyatt_analysis: |   wyatt_analysis: | ||||||
|     hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub |     hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub | ||||||
|     version: ^2.5.0 |     version: ^2.6.1 | ||||||
|  | |||||||
| @ -21,85 +21,83 @@ void main() { | |||||||
|   group('Result<T,E>', () { |   group('Result<T,E>', () { | ||||||
|     test('`isOk` returns true on Ok value', () { |     test('`isOk` returns true on Ok value', () { | ||||||
|       expect( |       expect( | ||||||
|         const Ok<void, void>(null).isOk, |         Ok<void, void>(null).isOk, | ||||||
|         true, |         true, | ||||||
|       ); |       ); | ||||||
|       expect( |       expect( | ||||||
|         const Err<void, void>(null).isOk, |         Err<void, void>(null).isOk, | ||||||
|         false, |         false, | ||||||
|       ); |       ); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     test('`isErr` returns true on Err value', () { |     test('`isErr` returns true on Err value', () { | ||||||
|       expect( |       expect( | ||||||
|         const Ok<void, void>(null).isErr, |         Ok<void, void>(null).isErr, | ||||||
|         false, |         false, | ||||||
|       ); |       ); | ||||||
|       expect( |       expect( | ||||||
|         const Err<void, void>(null).isErr, |         Err<void, void>(null).isErr, | ||||||
|         true, |         true, | ||||||
|       ); |       ); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     test('`ok` returns value on Ok value', () { |     test('`ok` returns value on Ok value', () { | ||||||
|       const Result<int, String> x = Ok(2); |       final Result<int, String> x = Ok(2); | ||||||
|       expect(x.ok, 2); |       expect(x.ok, 2); | ||||||
|       expect(x.err, null); |       expect(x.err, null); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     test('`err` returns error on Err value', () { |     test('`err` returns error on Err value', () { | ||||||
|       const Result<int, String> x = Err('error'); |       final Result<int, String> x = Err('error'); | ||||||
|       expect(x.ok, null); |       expect(x.ok, null); | ||||||
|       expect(x.err, 'error'); |       expect(x.err, 'error'); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     test('unwrap() returns value on Ok value', () { |     test('unwrap() returns value on Ok value', () { | ||||||
|       const Result<int, String> x = Ok(2); |       final Result<int, String> x = Ok(2); | ||||||
|       expect(x.unwrap<int>(), 2); |       expect(x.unwrap<int>(), 2); | ||||||
|       expect(() => x.unwrap<String>(), throwsA(isException)); |       expect(() => x.unwrap<String>(), throwsA(isException)); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     test('unwrap() returns error on Err value', () { |     test('unwrap() returns error on Err value', () { | ||||||
|       const Result<int, String> x = Err('error'); |       final Result<int, String> x = Err('error'); | ||||||
|       expect(x.unwrap<String>(), 'error'); |       expect(x.unwrap<String>(), 'error'); | ||||||
|       expect(() => x.unwrap<int>(), throwsA(isException)); |       expect(() => x.unwrap<int>(), throwsA(isException)); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     test('unwrapAsync() returns value on Ok value', () async { |     test('unwrapAsync() returns value on Ok value', () async { | ||||||
|       const Result<int, String> x = Ok(2); |       final Result<int, String> x = Ok(2); | ||||||
|       expect(await x.unwrapAsync<int>(), 2); |       expect(await x.unwrapAsync<int>(), 2); | ||||||
|       expect(() async => x.unwrapAsync<String>(), throwsA(isException)); |       expect(() async => x.unwrapAsync<String>(), throwsA(isException)); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     test('unwrapAsync() returns error on Err value', () async { |     test('unwrapAsync() returns error on Err value', () async { | ||||||
|       const Result<int, String> x = Err('error'); |       final Result<int, String> x = Err('error'); | ||||||
|       expect(await x.unwrapAsync<String>(), 'error'); |       expect(await x.unwrapAsync<String>(), 'error'); | ||||||
|       expect(() async => x.unwrapAsync<int>(), throwsA(isException)); |       expect(() async => x.unwrapAsync<int>(), throwsA(isException)); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     test('fold() returns right value', () { |     test('fold() returns right value', () { | ||||||
|       expect( |       expect( | ||||||
|         const Ok<String, String>('') |         Ok<String, String>('').fold<bool>((left) => true, (right) => false), | ||||||
|             .fold<bool>((left) => true, (right) => false), |  | ||||||
|         true, |         true, | ||||||
|       ); |       ); | ||||||
|       expect( |       expect( | ||||||
|         const Err<String, String>('') |         Err<String, String>('').fold<bool>((left) => true, (right) => false), | ||||||
|             .fold<bool>((left) => true, (right) => false), |  | ||||||
|         false, |         false, | ||||||
|       ); |       ); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     test('foldAsync() returns right value', () async { |     test('foldAsync() returns right value', () async { | ||||||
|       expect( |       expect( | ||||||
|         await const Ok<String, String>('').foldAsync<bool>( |         await Ok<String, String>('').foldAsync<bool>( | ||||||
|           (left) => Future.value(true), |           (left) => Future.value(true), | ||||||
|           (right) => Future.value(false), |           (right) => Future.value(false), | ||||||
|         ), |         ), | ||||||
|         true, |         true, | ||||||
|       ); |       ); | ||||||
|       expect( |       expect( | ||||||
|         await const Err<String, String>('').foldAsync<bool>( |         await Err<String, String>('').foldAsync<bool>( | ||||||
|           (left) => Future.value(true), |           (left) => Future.value(true), | ||||||
|           (right) => Future.value(false), |           (right) => Future.value(false), | ||||||
|         ), |         ), | ||||||
| @ -108,7 +106,7 @@ void main() { | |||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     test('swap() swaps values', () { |     test('swap() swaps values', () { | ||||||
|       const Result<int, int> x = Ok(10); |       final Result<int, int> x = Ok(10); | ||||||
|       expect(x.isOk, true); |       expect(x.isOk, true); | ||||||
|       expect(x.isErr, false); |       expect(x.isErr, false); | ||||||
|       expect(x.ok, 10); |       expect(x.ok, 10); | ||||||
| @ -122,24 +120,24 @@ void main() { | |||||||
|       'and() returns res if the result is `Ok`, otherwise ' |       'and() returns res if the result is `Ok`, otherwise ' | ||||||
|       'returns the `Err` value of this.', |       'returns the `Err` value of this.', | ||||||
|       () { |       () { | ||||||
|         const Result<int, String> x1 = Ok(2); |         final Result<int, String> x1 = Ok(2); | ||||||
|         const Result<int, String> y1 = Err('late error'); |         final Result<int, String> y1 = Err('late error'); | ||||||
|         expect(x1.and(y1), y1); |         expect(x1.and(y1), y1); | ||||||
| 
 | 
 | ||||||
|         const Result<String, String> x2 = Err('early error'); |         final Result<String, String> x2 = Err('early error'); | ||||||
|         const Result<String, String> y2 = Ok('foo'); |         final Result<String, String> y2 = Ok('foo'); | ||||||
|         expect(x2.and(y2), x2); |         expect(x2.and(y2), x2); | ||||||
| 
 | 
 | ||||||
|         const Result<void, String> x3 = Err('not a 2'); |         final Result<void, String> x3 = Err('not a 2'); | ||||||
|         const Result<void, String> y3 = Err('late error'); |         final Result<void, String> y3 = Err('late error'); | ||||||
|         expect(x3.and(y3), x3); |         expect(x3.and(y3), x3); | ||||||
| 
 | 
 | ||||||
|         const Result<dynamic, void> x4 = Ok(2); |         final Result<dynamic, void> x4 = Ok(2); | ||||||
|         const Result<dynamic, void> y4 = Ok('different result type'); |         final Result<dynamic, void> y4 = Ok('different result type'); | ||||||
|         expect(x4.and(y4), y4); |         expect(x4.and(y4), y4); | ||||||
| 
 | 
 | ||||||
|         const Result<int, void> x5 = Ok(2); |         final Result<int, void> x5 = Ok(2); | ||||||
|         const Result<int, void> y5 = Ok(5); |         final Result<int, void> y5 = Ok(5); | ||||||
|         expect(x5.and(y5), y5); |         expect(x5.and(y5), y5); | ||||||
|       }, |       }, | ||||||
|     ); |     ); | ||||||
| @ -148,24 +146,24 @@ void main() { | |||||||
|       'or() returns res if the result is `Err`, otherwise ' |       'or() returns res if the result is `Err`, otherwise ' | ||||||
|       'returns the `Ok` value of this.', |       'returns the `Ok` value of this.', | ||||||
|       () { |       () { | ||||||
|         const Result<int, String> x1 = Ok(2); |         final Result<int, String> x1 = Ok(2); | ||||||
|         const Result<int, String> y1 = Err('late error'); |         final Result<int, String> y1 = Err('late error'); | ||||||
|         expect(x1.or(y1), x1); |         expect(x1.or(y1), x1); | ||||||
| 
 | 
 | ||||||
|         const Result<String, String> x2 = Err('early error'); |         final Result<String, String> x2 = Err('early error'); | ||||||
|         const Result<String, String> y2 = Ok('foo'); |         final Result<String, String> y2 = Ok('foo'); | ||||||
|         expect(x2.or(y2), y2); |         expect(x2.or(y2), y2); | ||||||
| 
 | 
 | ||||||
|         const Result<void, String> x3 = Err('not a 2'); |         final Result<void, String> x3 = Err('not a 2'); | ||||||
|         const Result<void, String> y3 = Err('late error'); |         final Result<void, String> y3 = Err('late error'); | ||||||
|         expect(x3.or(y3), y3); |         expect(x3.or(y3), y3); | ||||||
| 
 | 
 | ||||||
|         const Result<dynamic, void> x4 = Ok(2); |         final Result<dynamic, void> x4 = Ok(2); | ||||||
|         const Result<dynamic, void> y4 = Ok('different result type'); |         final Result<dynamic, void> y4 = Ok('different result type'); | ||||||
|         expect(x4.or(y4), x4); |         expect(x4.or(y4), x4); | ||||||
| 
 | 
 | ||||||
|         const Result<int, void> x5 = Ok(2); |         final Result<int, void> x5 = Ok(2); | ||||||
|         const Result<int, void> y5 = Ok(5); |         final Result<int, void> y5 = Ok(5); | ||||||
|         expect(x5.or(y5), x5); |         expect(x5.or(y5), x5); | ||||||
|       }, |       }, | ||||||
|     ); |     ); | ||||||
| @ -174,10 +172,10 @@ void main() { | |||||||
|       'contains() returns true if the result is an Ok value ' |       'contains() returns true if the result is an Ok value ' | ||||||
|       'containing the given value.', |       'containing the given value.', | ||||||
|       () { |       () { | ||||||
|         const Result<int, void> x1 = Ok(2); |         final Result<int, void> x1 = Ok(2); | ||||||
|         expect(x1.contains(2), true); |         expect(x1.contains(2), true); | ||||||
|         expect(x1.contains(3), false); |         expect(x1.contains(3), false); | ||||||
|         const Result<void, String> x2 = Err('Some error message'); |         final Result<void, String> x2 = Err('Some error message'); | ||||||
|         expect(x2.contains(2), false); |         expect(x2.contains(2), false); | ||||||
|       }, |       }, | ||||||
|     ); |     ); | ||||||
| @ -186,10 +184,10 @@ void main() { | |||||||
|       'expect() return value if the result is an Ok value ' |       'expect() return value if the result is an Ok value ' | ||||||
|       'else throw Exception', |       'else throw Exception', | ||||||
|       () { |       () { | ||||||
|         const Result<int, String> x1 = Ok(2); |         final Result<int, String> x1 = Ok(2); | ||||||
|         expect(x1.expect('Testing expect'), 2); |         expect(x1.expect('Testing expect'), 2); | ||||||
| 
 | 
 | ||||||
|         const Result<int, String> x2 = Err('emergency failure'); |         final Result<int, String> x2 = Err('emergency failure'); | ||||||
|         expect( |         expect( | ||||||
|           () => x2.expect('Testing expect'), |           () => x2.expect('Testing expect'), | ||||||
|           throwsA( |           throwsA( | ||||||
| @ -205,10 +203,10 @@ void main() { | |||||||
|       'expectErr() return value if the result is an Err value ' |       'expectErr() return value if the result is an Err value ' | ||||||
|       'else throw Exception', |       'else throw Exception', | ||||||
|       () { |       () { | ||||||
|         const Result<String, int> x1 = Err(2); |         final Result<String, int> x1 = Err(2); | ||||||
|         expect(x1.expectErr('Testing expect err'), 2); |         expect(x1.expectErr('Testing expect err'), 2); | ||||||
| 
 | 
 | ||||||
|         const Result<String, int> x2 = Ok('success value'); |         final Result<String, int> x2 = Ok('success value'); | ||||||
|         expect( |         expect( | ||||||
|           () => x2.expectErr('Testing expect err'), |           () => x2.expectErr('Testing expect err'), | ||||||
|           throwsA( |           throwsA( | ||||||
| @ -223,12 +221,12 @@ void main() { | |||||||
|     test( |     test( | ||||||
|       'map() transforms Ok value.', |       'map() transforms Ok value.', | ||||||
|       () { |       () { | ||||||
|         const Result<bool, void> x1 = Ok(true); |         final Result<bool, void> x1 = Ok(true); | ||||||
| 
 | 
 | ||||||
|         expect(x1.ok, true); |         expect(x1.ok, true); | ||||||
|         expect(x1.map((value) => false).ok, false); |         expect(x1.map((value) => false).ok, false); | ||||||
| 
 | 
 | ||||||
|         const Result<bool, String> x2 = Err('oops'); |         final Result<bool, String> x2 = Err('oops'); | ||||||
| 
 | 
 | ||||||
|         expect(x2.map((value) => false).isErr, true); |         expect(x2.map((value) => false).isErr, true); | ||||||
|       }, |       }, | ||||||
| @ -237,11 +235,11 @@ void main() { | |||||||
|     test( |     test( | ||||||
|       'mapErr() transforms Err value.', |       'mapErr() transforms Err value.', | ||||||
|       () { |       () { | ||||||
|         const Result<bool, String> x1 = Ok(true); |         final Result<bool, String> x1 = Ok(true); | ||||||
| 
 | 
 | ||||||
|         expect(x1.mapErr((value) => false).isOk, true); |         expect(x1.mapErr((value) => false).isOk, true); | ||||||
| 
 | 
 | ||||||
|         const Result<bool, String> x2 = Err('oops'); |         final Result<bool, String> x2 = Err('oops'); | ||||||
| 
 | 
 | ||||||
|         expect(x2.err, 'oops'); |         expect(x2.err, 'oops'); | ||||||
|         expect(x2.mapErr((error) => 'failure').err, 'failure'); |         expect(x2.mapErr((error) => 'failure').err, 'failure'); | ||||||
| @ -251,12 +249,12 @@ void main() { | |||||||
|     test( |     test( | ||||||
|       'mapAsync() transforms Ok value.', |       'mapAsync() transforms Ok value.', | ||||||
|       () async { |       () async { | ||||||
|         const Result<bool, void> x1 = Ok(true); |         final Result<bool, void> x1 = Ok(true); | ||||||
| 
 | 
 | ||||||
|         expect(x1.ok, true); |         expect(x1.ok, true); | ||||||
|         expect((await x1.mapAsync((value) => Future.value(false))).ok, false); |         expect((await x1.mapAsync((value) => Future.value(false))).ok, false); | ||||||
| 
 | 
 | ||||||
|         const Result<bool, String> x2 = Err('oops'); |         final Result<bool, String> x2 = Err('oops'); | ||||||
| 
 | 
 | ||||||
|         expect((await x2.mapAsync((value) => Future.value(false))).isErr, true); |         expect((await x2.mapAsync((value) => Future.value(false))).isErr, true); | ||||||
|       }, |       }, | ||||||
| @ -265,14 +263,14 @@ void main() { | |||||||
|     test( |     test( | ||||||
|       'mapErrAsync() transforms Err value.', |       'mapErrAsync() transforms Err value.', | ||||||
|       () async { |       () async { | ||||||
|         const Result<bool, String> x1 = Ok(true); |         final Result<bool, String> x1 = Ok(true); | ||||||
| 
 | 
 | ||||||
|         expect( |         expect( | ||||||
|           (await x1.mapErrAsync((value) => Future.value(false))).isOk, |           (await x1.mapErrAsync((value) => Future.value(false))).isOk, | ||||||
|           true, |           true, | ||||||
|         ); |         ); | ||||||
| 
 | 
 | ||||||
|         const Result<bool, String> x2 = Err('oops'); |         final Result<bool, String> x2 = Err('oops'); | ||||||
| 
 | 
 | ||||||
|         expect(x2.err, 'oops'); |         expect(x2.err, 'oops'); | ||||||
|         expect( |         expect( | ||||||
| @ -285,14 +283,14 @@ void main() { | |||||||
|     test( |     test( | ||||||
|       'either() transforms values.', |       'either() transforms values.', | ||||||
|       () { |       () { | ||||||
|         const Result<bool, bool> x1 = Ok(true); |         final Result<bool, bool> x1 = Ok(true); | ||||||
|         final Result<int, String> y1 = |         final Result<int, String> y1 = | ||||||
|             x1.either<int, String>((value) => 1, (error) => 'error'); |             x1.either<int, String>((value) => 1, (error) => 'error'); | ||||||
| 
 | 
 | ||||||
|         expect(y1.isOk, true); |         expect(y1.isOk, true); | ||||||
|         expect(y1.ok, 1); |         expect(y1.ok, 1); | ||||||
| 
 | 
 | ||||||
|         const Result<bool, bool> x2 = Err(true); |         final Result<bool, bool> x2 = Err(true); | ||||||
|         final Result<int, String> y2 = |         final Result<int, String> y2 = | ||||||
|             x2.either<int, String>((value) => 1, (error) => 'error'); |             x2.either<int, String>((value) => 1, (error) => 'error'); | ||||||
| 
 | 
 | ||||||
| @ -304,7 +302,7 @@ void main() { | |||||||
|     test( |     test( | ||||||
|       'eitherAsync() transforms values.', |       'eitherAsync() transforms values.', | ||||||
|       () async { |       () async { | ||||||
|         const Result<bool, bool> x1 = Ok(true); |         final Result<bool, bool> x1 = Ok(true); | ||||||
|         final Result<int, String> y1 = await x1.eitherAsync<int, String>( |         final Result<int, String> y1 = await x1.eitherAsync<int, String>( | ||||||
|           (value) => Future.value(1), |           (value) => Future.value(1), | ||||||
|           (error) => Future.value('error'), |           (error) => Future.value('error'), | ||||||
| @ -313,7 +311,7 @@ void main() { | |||||||
|         expect(y1.isOk, true); |         expect(y1.isOk, true); | ||||||
|         expect(y1.ok, 1); |         expect(y1.ok, 1); | ||||||
| 
 | 
 | ||||||
|         const Result<bool, bool> x2 = Err(true); |         final Result<bool, bool> x2 = Err(true); | ||||||
|         final Result<int, String> y2 = await x2.eitherAsync<int, String>( |         final Result<int, String> y2 = await x2.eitherAsync<int, String>( | ||||||
|           (value) => Future.value(1), |           (value) => Future.value(1), | ||||||
|           (error) => Future.value('error'), |           (error) => Future.value('error'), | ||||||
| @ -370,9 +368,9 @@ void main() { | |||||||
|       'conditional() returns Result on true test', |       'conditional() returns Result on true test', | ||||||
|       () { |       () { | ||||||
|         final Result<int, String> x1 = Result.conditional<int, String>( |         final Result<int, String> x1 = Result.conditional<int, String>( | ||||||
|           false, |  | ||||||
|           2, |           2, | ||||||
|           'error', |           'error', | ||||||
|  |           test: false, | ||||||
|         ); |         ); | ||||||
|         expect( |         expect( | ||||||
|           x1.isErr, |           x1.isErr, | ||||||
| @ -382,9 +380,9 @@ void main() { | |||||||
|         expect(x1.err, 'error'); |         expect(x1.err, 'error'); | ||||||
| 
 | 
 | ||||||
|         final Result<int, String> x2 = Result.conditional<int, String>( |         final Result<int, String> x2 = Result.conditional<int, String>( | ||||||
|           true, |  | ||||||
|           2, |           2, | ||||||
|           'error', |           'error', | ||||||
|  |           test: true, | ||||||
|         ); |         ); | ||||||
|         expect( |         expect( | ||||||
|           x2.isOk, |           x2.isOk, | ||||||
| @ -399,9 +397,9 @@ void main() { | |||||||
|       'conditionalLazy() returns Result on true test', |       'conditionalLazy() returns Result on true test', | ||||||
|       () { |       () { | ||||||
|         final Result<int, String> x1 = Result.conditionalLazy<int, String>( |         final Result<int, String> x1 = Result.conditionalLazy<int, String>( | ||||||
|           false, |  | ||||||
|           () => 2, |           () => 2, | ||||||
|           () => 'error', |           () => 'error', | ||||||
|  |           () => false, | ||||||
|         ); |         ); | ||||||
|         expect( |         expect( | ||||||
|           x1.isErr, |           x1.isErr, | ||||||
| @ -411,9 +409,9 @@ void main() { | |||||||
|         expect(x1.err, 'error'); |         expect(x1.err, 'error'); | ||||||
| 
 | 
 | ||||||
|         final Result<int, String> x2 = Result.conditionalLazy<int, String>( |         final Result<int, String> x2 = Result.conditionalLazy<int, String>( | ||||||
|           true, |  | ||||||
|           () => 2, |           () => 2, | ||||||
|           () => 'error', |           () => 'error', | ||||||
|  |           () => true, | ||||||
|         ); |         ); | ||||||
|         expect( |         expect( | ||||||
|           x2.isOk, |           x2.isOk, | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user