diff --git a/lib/oxidized.dart b/lib/oxidized.dart index 3287e58..9e13895 100644 --- a/lib/oxidized.dart +++ b/lib/oxidized.dart @@ -94,3 +94,6 @@ library oxidized; export 'src/option.dart'; export 'src/result.dart'; export 'src/unit.dart'; + +export 'src/option_utils/option_utils.dart'; +export 'src/result_utils/result_utils.dart'; diff --git a/lib/src/option_utils/option_option_flattener.dart b/lib/src/option_utils/option_option_flattener.dart new file mode 100644 index 0000000..826aad1 --- /dev/null +++ b/lib/src/option_utils/option_option_flattener.dart @@ -0,0 +1,20 @@ +part of 'option_utils.dart'; + +extension OptionOptionFlattener on Option> { + /// Flats an option of an option. + /// + /// ```dart + /// Some(Some(1)) => Some(1) + /// Some(None()) => None() + /// None() => None() + /// ``` + /// + /// See also: + /// - https://doc.rust-lang.org/std/option/enum.Option.html#method.flatten + Option flatten() { + return match( + (option) => option, + () => None(), + ); + } +} diff --git a/lib/src/option_utils/option_result_transposer.dart b/lib/src/option_utils/option_result_transposer.dart new file mode 100644 index 0000000..a08164b --- /dev/null +++ b/lib/src/option_utils/option_result_transposer.dart @@ -0,0 +1,23 @@ +part of 'option_utils.dart'; + +extension OptionResultTransposer + on Option> { + /// Transposes the result of an option. + /// + /// ```dart + /// Some(Ok(1)) => Ok(Some(1)); + /// Some(Err('error message')) => Err('error message'); + /// None() => Ok(None()); + /// ``` + /// + /// See also https://doc.rust-lang.org/std/option/enum.Option.html#method.transpose + Result, E> transpose() { + return match( + (result) => result.match( + (value) => Ok(Some(value)), + (err) => Err(err), + ), + () => Ok(None()), + ); + } +} diff --git a/lib/src/option_utils/option_utils.dart b/lib/src/option_utils/option_utils.dart new file mode 100644 index 0000000..d05c202 --- /dev/null +++ b/lib/src/option_utils/option_utils.dart @@ -0,0 +1,4 @@ +import 'package:oxidized/oxidized.dart'; + +part 'option_option_flattener.dart'; +part 'option_result_transposer.dart'; diff --git a/lib/src/result_utils/result_option_transposer.dart b/lib/src/result_utils/result_option_transposer.dart new file mode 100644 index 0000000..2b0ebcb --- /dev/null +++ b/lib/src/result_utils/result_option_transposer.dart @@ -0,0 +1,24 @@ +part of 'result_utils.dart'; + +extension ResultOptionTransposer + on Result, E> { + /// Transposes the result to an option. + /// + /// ```dart + /// Ok(None()) => None() + /// Ok(Some(val)) => Some(Ok(val)) + /// Err(err) => Some(Err(err)) + /// ``` + /// + /// See also: + /// - https://doc.rust-lang.org/std/result/enum.Result.html#method.transpose + Option> transpose() { + return match( + (option) => option.match( + (val) => Some(Ok(val)), + () => None(), + ), + (err) => Some(Err(err)), + ); + } +} diff --git a/lib/src/result_utils/result_result_flattener.dart b/lib/src/result_utils/result_result_flattener.dart new file mode 100644 index 0000000..d550e29 --- /dev/null +++ b/lib/src/result_utils/result_result_flattener.dart @@ -0,0 +1,24 @@ +part of 'result_utils.dart'; + +extension ResultResultFlattener + on Result, E> { + /// Flattens a [Result, E>] into a [Result] + /// + /// ```dart + /// Ok(Ok(value)) => Ok(value) + /// Ok(Err(error)) => Err(error) + /// Err(error) => Err(error) + /// ``` + /// + /// See also: + /// - https://doc.rust-lang.org/std/result/enum.Result.html#method.flatten + Result flatten() { + return match( + (result) => result.match( + (val) => Ok(val), + (err) => Err(err), + ), + (err) => Err(err), + ); + } +} diff --git a/lib/src/result_utils/result_utils.dart b/lib/src/result_utils/result_utils.dart new file mode 100644 index 0000000..fea8a4e --- /dev/null +++ b/lib/src/result_utils/result_utils.dart @@ -0,0 +1,4 @@ +import 'package:oxidized/oxidized.dart'; + +part 'result_option_transposer.dart'; +part 'result_result_flattener.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index e06145e..bb7bf86 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -6,7 +6,7 @@ repository: https://github.com/nlfiedler/oxidized.git issue_tracker: https://github.com/nlfiedler/oxidized/issues environment: - sdk: '>=2.12.0 <3.0.0' + sdk: ">=2.13.0 <3.0.0" dependencies: equatable: ^2.0.3 diff --git a/test/src/option_utils/option_option_flattener_test.dart b/test/src/option_utils/option_option_flattener_test.dart new file mode 100644 index 0000000..6138e57 --- /dev/null +++ b/test/src/option_utils/option_option_flattener_test.dart @@ -0,0 +1,25 @@ +import 'package:oxidized/oxidized.dart'; +import 'package:test/test.dart'; + +typedef OptInt = Option; +typedef OptOptInt = Option; + +void main() { + test('None().flatten() must return None', () { + final OptOptInt input = None(); + final OptInt output = None(); + expect(input.flatten(), equals(output)); + }); + + test('Some(None()).flatten() must return None()', () { + final OptOptInt input = Some(None()); + final OptInt output = None(); + expect(input.flatten(), equals(output)); + }); + + test('Some(Some(val)).flatten() must return Some(val)', () { + final OptOptInt input = Some(Some(1)); + final OptInt output = Some(1); + expect(input.flatten(), equals(output)); + }); +} diff --git a/test/src/option_utils/option_result_transposer_test.dart b/test/src/option_utils/option_result_transposer_test.dart new file mode 100644 index 0000000..2eff3cb --- /dev/null +++ b/test/src/option_utils/option_result_transposer_test.dart @@ -0,0 +1,25 @@ +import 'package:oxidized/oxidized.dart'; +import 'package:test/test.dart'; + +typedef OptRes = Option>; +typedef ResOpt = Result, String>; + +void main() { + test('None() transpose must return Ok(None())', () { + final OptRes input = None(); + final ResOpt output = Ok(None()); + expect(input.transpose(), equals(output)); + }); + + test('Some(Ok(val)) transpose must return Ok(Some(val))', () { + final OptRes input = Some(Ok(1)); + final ResOpt output = Ok(Some(1)); + expect(input.transpose(), equals(output)); + }); + + test('Some(Err(val)) transpose must return Err(val)', () { + final OptRes input = Some(Err('error')); + final ResOpt output = Err('error'); + expect(input.transpose(), equals(output)); + }); +} diff --git a/test/src/result_utils/result_option_transposer_test.dart b/test/src/result_utils/result_option_transposer_test.dart new file mode 100644 index 0000000..7527179 --- /dev/null +++ b/test/src/result_utils/result_option_transposer_test.dart @@ -0,0 +1,25 @@ +import 'package:oxidized/oxidized.dart'; +import 'package:test/test.dart'; + +typedef OptRes = Option>; +typedef ResOpt = Result, String>; + +void main() { + test('Ok(None()).transpose() must return None()', () async { + final ResOpt input = Ok(None()); + final OptRes output = None(); + expect(input.transpose(), output); + }); + + test('Ok(Some(val)).transpose() must return Some(Ok(val))', () async { + final ResOpt input = Ok(Some(1)); + final OptRes output = Some(Ok(1)); + expect(input.transpose(), output); + }); + + test('Err(err).transpose() must return Some(Err(err))', () async { + final ResOpt input = Err('error message'); + final OptRes output = Some(Err('error message')); + expect(input.transpose(), output); + }); +} diff --git a/test/src/result_utils/result_result_flattener_test.dart b/test/src/result_utils/result_result_flattener_test.dart new file mode 100644 index 0000000..bda6bc1 --- /dev/null +++ b/test/src/result_utils/result_result_flattener_test.dart @@ -0,0 +1,25 @@ +import 'package:oxidized/oxidized.dart'; +import 'package:test/test.dart'; + +typedef Res = Result; +typedef ResRes = Result, String>; + +void main() { + test('Ok(Ok(val).flatten() must return Ok(val)', () async { + final ResRes input = Ok(Ok(1)); + final Res output = Ok(1); + expect(input.flatten(), output); + }); + + test('Ok(Err(err).flatten() must return Err(err)', () async { + final ResRes input = Ok(Err('error message')); + final Res output = Err('error message'); + expect(input.flatten(), output); + }); + + test('Err(err).flatten() must return Err(err)', () async { + final ResRes input = Err('error message'); + final Res output = Err('error message'); + expect(input.flatten(), output); + }); +}