From c11c3b21735939c2c1e1fc2125f259b4499a74c8 Mon Sep 17 00:00:00 2001 From: bloodyowl Date: Sat, 16 Mar 2024 13:41:29 +0100 Subject: [PATCH] Add Option.all & Result.all helpers --- src/Core__Option.mjs | 22 +++++++++++++++ src/Core__Option.res | 18 ++++++++++++ src/Core__Option.resi | 12 ++++++++ src/Core__Result.mjs | 25 +++++++++++++++++ src/Core__Result.res | 18 ++++++++++++ src/Core__Result.resi | 12 ++++++++ test/OptionTests.mjs | 53 +++++++++++++++++++++++++++++++++++ test/OptionTests.res | 7 +++++ test/ResultTests.mjs | 65 +++++++++++++++++++++++++++++++++++++++++++ test/ResultTests.res | 4 +++ 10 files changed, 236 insertions(+) create mode 100644 test/OptionTests.mjs create mode 100644 test/OptionTests.res diff --git a/src/Core__Option.mjs b/src/Core__Option.mjs index 776bc0bf..4a3710d9 100644 --- a/src/Core__Option.mjs +++ b/src/Core__Option.mjs @@ -98,6 +98,27 @@ function compare(a, b, cmp) { } } +function all(options) { + var acc = []; + var returnValue; + var index = 0; + while(returnValue === undefined && index < options.length) { + var value = options[index]; + if (value !== undefined) { + acc.push(Caml_option.valFromOption(value)); + index = index + 1 | 0; + } else { + returnValue = Caml_option.some(undefined); + } + }; + var match = returnValue; + if (match !== undefined) { + return ; + } else { + return acc; + } +} + var mapWithDefault = mapOr; var getWithDefault = getOr; @@ -117,5 +138,6 @@ export { isNone , equal , compare , + all , } /* No side effect */ diff --git a/src/Core__Option.res b/src/Core__Option.res index a799a0ea..16332b8e 100644 --- a/src/Core__Option.res +++ b/src/Core__Option.res @@ -98,3 +98,21 @@ let compare = (a, b, cmp) => | (Some(_), None) => Core__Ordering.greater | (None, None) => Core__Ordering.equal } + +let all = options => { + let acc = [] + let returnValue = ref(None) + let index = ref(0) + while returnValue.contents == None && index.contents < options->Core__Array.length { + switch options->Core__Array.getUnsafe(index.contents) { + | None => returnValue.contents = Some(None) + | Some(value) => + acc->Core__Array.push(value) + index.contents = index.contents + 1 + } + } + switch returnValue.contents { + | Some(_) => None + | None => Some(acc) + } +} diff --git a/src/Core__Option.resi b/src/Core__Option.resi index fbaceba4..6b4977c9 100644 --- a/src/Core__Option.resi +++ b/src/Core__Option.resi @@ -252,3 +252,15 @@ Option.compare(None, None, clockCompare) // 0. ``` */ let compare: (option<'a>, option<'b>, ('a, 'b) => Core__Ordering.t) => Core__Ordering.t + +/** +`all(options)` returns an option of array if all options are Some, otherwise returns None. + +## Examples + +```rescript +Option.all([Some(1), Some(2), Some(3)]) // Some([1, 2, 3]) +Option.all([Some(1), None]) // None +``` +*/ +let all: array> => option> diff --git a/src/Core__Result.mjs b/src/Core__Result.mjs index 6ec9cb05..d380a400 100644 --- a/src/Core__Result.mjs +++ b/src/Core__Result.mjs @@ -108,6 +108,30 @@ function mapError(r, f) { } } +function all(results) { + var acc = []; + var returnValue; + var index = 0; + while(returnValue === undefined && index < results.length) { + var err = results[index]; + if (err.TAG === "Ok") { + acc.push(err._0); + index = index + 1 | 0; + } else { + returnValue = err; + } + }; + var error = returnValue; + if (error !== undefined) { + return error; + } else { + return { + TAG: "Ok", + _0: acc + }; + } +} + var mapWithDefault = mapOr; var getWithDefault = getOr; @@ -126,5 +150,6 @@ export { compare , forEach , mapError , + all , } /* No side effect */ diff --git a/src/Core__Result.res b/src/Core__Result.res index a2abc3d0..b426a784 100644 --- a/src/Core__Result.res +++ b/src/Core__Result.res @@ -95,3 +95,21 @@ let mapError = (r, f) => | Ok(_) as result => result | Error(e) => Error(f(e)) } + +let all = results => { + let acc = [] + let returnValue = ref(None) + let index = ref(0) + while returnValue.contents == None && index.contents < results->Core__Array.length { + switch results->Core__Array.getUnsafe(index.contents) { + | Error(_) as err => returnValue.contents = Some(err) + | Ok(value) => + acc->Core__Array.push(value) + index.contents = index.contents + 1 + } + } + switch returnValue.contents { + | Some(error) => error + | None => Ok(acc) + } +} diff --git a/src/Core__Result.resi b/src/Core__Result.resi index a30c5e0b..9e0cd8ce 100644 --- a/src/Core__Result.resi +++ b/src/Core__Result.resi @@ -234,3 +234,15 @@ Result.mapError(Ok("abc"), format) // Ok("abc") ``` */ let mapError: (result<'a, 'b>, 'b => 'c) => result<'a, 'c> + +/** +`all(results)` returns a result of array if all options are Ok, otherwise returns Error. + +## Examples + +```rescript +Option.all([Ok(1), Ok(2), Ok(3)]) // Ok([1, 2, 3]) +Option.all([Ok(1), Error(1)]) // Error(1) +``` +*/ +let all: array> => result, 'b> diff --git a/test/OptionTests.mjs b/test/OptionTests.mjs new file mode 100644 index 00000000..dc8ea16b --- /dev/null +++ b/test/OptionTests.mjs @@ -0,0 +1,53 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE + +import * as Test from "./Test.mjs"; +import * as Caml_obj from "rescript/lib/es6/caml_obj.js"; +import * as Core__Option from "../src/Core__Option.mjs"; + +var eq = Caml_obj.equal; + +Test.run([ + [ + "OptionTests.res", + 5, + 20, + 25 + ], + "all" + ], Core__Option.all([]), eq, []); + +Test.run([ + [ + "OptionTests.res", + 6, + 20, + 25 + ], + "all" + ], Core__Option.all([ + 1, + 2, + 3 + ]), eq, [ + 1, + 2, + 3 + ]); + +Test.run([ + [ + "OptionTests.res", + 7, + 20, + 25 + ], + "all" + ], Core__Option.all([ + 1, + undefined + ]), eq, undefined); + +export { + eq , +} +/* Not a pure module */ diff --git a/test/OptionTests.res b/test/OptionTests.res new file mode 100644 index 00000000..7461b84f --- /dev/null +++ b/test/OptionTests.res @@ -0,0 +1,7 @@ +open RescriptCore + +let eq = (a, b) => a == b + +Test.run(__POS_OF__("all"), Option.all([]), eq, Some([])) +Test.run(__POS_OF__("all"), Option.all([Some(1), Some(2), Some(3)]), eq, Some([1, 2, 3])) +Test.run(__POS_OF__("all"), Option.all([Some(1), None]), eq, None) diff --git a/test/ResultTests.mjs b/test/ResultTests.mjs index a191b784..9d7d0023 100644 --- a/test/ResultTests.mjs +++ b/test/ResultTests.mjs @@ -88,6 +88,71 @@ Test.run([ _0: 15 }); +Test.run([ + [ + "ResultTests.res", + 36, + 20, + 25 + ], + "all" + ], Core__Result.all([]), eq, { + TAG: "Ok", + _0: [] + }); + +Test.run([ + [ + "ResultTests.res", + 37, + 20, + 25 + ], + "all" + ], Core__Result.all([ + { + TAG: "Ok", + _0: 1 + }, + { + TAG: "Ok", + _0: 2 + }, + { + TAG: "Ok", + _0: 3 + } + ]), eq, { + TAG: "Ok", + _0: [ + 1, + 2, + 3 + ] + }); + +Test.run([ + [ + "ResultTests.res", + 38, + 20, + 25 + ], + "all" + ], Core__Result.all([ + { + TAG: "Ok", + _0: 1 + }, + { + TAG: "Error", + _0: 2 + } + ]), eq, { + TAG: "Error", + _0: 2 + }); + export { eq , forEachIfOkCallFunction , diff --git a/test/ResultTests.res b/test/ResultTests.res index 040028c6..6aa070ec 100644 --- a/test/ResultTests.res +++ b/test/ResultTests.res @@ -32,3 +32,7 @@ Test.run( eq, Error(15), ) + +Test.run(__POS_OF__("all"), Result.all([]), eq, Ok([])) +Test.run(__POS_OF__("all"), Result.all([Ok(1), Ok(2), Ok(3)]), eq, Ok([1, 2, 3])) +Test.run(__POS_OF__("all"), Result.all([Ok(1), Error(2)]), eq, Error(2))