diff --git a/corelib/src/result.cairo b/corelib/src/result.cairo index a3d50283e45..6177623a08b 100644 --- a/corelib/src/result.cairo +++ b/corelib/src/result.cairo @@ -540,4 +540,118 @@ pub impl ResultTraitImpl of ResultTrait { Result::Err(x) => Option::Some(x), } } + + /// Maps a `Result` to `Result` by applying a function to a + /// contained [`Ok`] value, leaving an [`Err`] value untouched. + /// + /// This function can be used to compose the results of two functions. + /// + /// # Examples + /// + /// Print the square of the number contained in the `Result`, otherwise print the error. + /// + /// ``` + /// let inputs: Array> = array![ + /// Result::Ok(1), Result::Err("error"), Result::Ok(3), Result::Ok(4), + /// ]; + /// for i in inputs { + /// match i.map(|i| i * 2) { + /// Result::Ok(x) => println!("{x}"), + /// Result::Err(e) => println!("{e}"), + /// } + /// } + /// ``` + #[inline] + fn map, +core::ops::FnOnce[Output: U]>( + self: Result, f: F, + ) -> Result { + match self { + Result::Ok(x) => Result::Ok(f(x)), + Result::Err(e) => Result::Err(e), + } + } + + /// Returns the provided default (if [`Err`]), or + /// applies a function to the contained value (if [`Ok`]). + /// + /// # Examples + /// + /// ``` + /// let x: Result<_, ByteArray> = Result::Ok("foo"); + /// assert!(x.map_or(42, |v: ByteArray| v.len()) == 3); + /// + /// let x: Result<_, ByteArray> = Result::Err("bar"); + /// assert!(x.map_or(42, |v: ByteArray| v.len()) == 42); + /// ``` + #[inline] + fn map_or, +Destruct, +Drop, +core::ops::FnOnce[Output: U]>( + self: Result, default: U, f: F, + ) -> U { + match self { + Result::Ok(x) => f(x), + Result::Err(_) => default, + } + } + + /// Maps a `Result` to `U` by applying fallback function `default` to + /// a contained [`Err`] value, or function `f` to a contained [`Ok`] value. + /// + /// This function can be used to unpack a successful result + /// while handling an error. + /// + /// + /// # Examples + /// + /// ``` + /// let k = 21; + /// + /// let x : Result = Result::Ok("foo"); + /// assert!(x.map_or_else(|e: ByteArray| k * 2, |v: ByteArray| v.len()) == 3); + /// + /// let x : Result = Result::Err("bar"); + /// assert!(x.map_or_else(|e: ByteArray| k * 2, |v: ByteArray| v.len()) == 42); + /// ``` + #[inline] + fn map_or_else< + U, + D, + F, + +Drop, + +Drop, + +core::ops::FnOnce[Output: U], + +core::ops::FnOnce[Output: U], + >( + self: Result, default: D, f: F, + ) -> U { + match self { + Result::Ok(t) => f(t), + Result::Err(e) => default(e), + } + } + + /// Maps a `Result` to `Result` by applying a function to a + /// contained [`Err`] value, leaving an [`Ok`] value untouched. + /// + /// This function can be used to pass through a successful result while handling + /// an error. + /// + /// + /// # Examples + /// + /// ``` + /// let stringify = |x: u32| -> ByteArray { format!("error code: {x}") }; + /// let x: Result = Result::Ok(2); + /// assert!(x.map_err(stringify) == Result::::Ok(2)); + /// + /// let x: Result = Result::Err(13); + /// assert!(x.map_err(stringify) == Result::Err("error code: 13")); + /// ``` + fn map_err, +core::ops::FnOnce[Output: F]>( + self: Result, op: O, + ) -> Result { + match self { + Result::Ok(x) => Result::Ok(x), + Result::Err(e) => Result::Err(op(e)), + } + } } diff --git a/corelib/src/test/result_test.cairo b/corelib/src/test/result_test.cairo index 8d126e14689..9e2af67261a 100644 --- a/corelib/src/test/result_test.cairo +++ b/corelib/src/test/result_test.cairo @@ -256,3 +256,59 @@ fn test_result_ok_err_should_return_none() { let x: Result = Result::Ok(2); assert!(x.err().is_none()); } + +#[test] +fn test_result_ok_map() { + let x: Result = Result::Ok(1); + assert!(x.map(|i| i * 2) == Result::Ok(2)); +} + +#[test] +fn test_result_err_map() { + let x: Result = Result::Err("error"); + assert!(x.map(|i| i * 2) == Result::Err("error")); +} + +#[test] +fn test_result_ok_map_or() { + let x: Result = Result::Ok("foo"); + assert!(x.map_or(42, |v: ByteArray| v.len()) == 3); +} + +#[test] +fn test_result_err_map_or() { + let x: Result = Result::Err("bar"); + assert!(x.map_or(42, |v: ByteArray| v.len()) == 42); +} + +#[test] +fn test_result_ok_map_or_else() { + let k = 21; + let x: Result = Result::Ok("foo"); + assert!(x.map_or_else(|_e| k * 2, |v: ByteArray| v.len()) == 3); +} + +#[test] +fn test_result_err_map_or_else() { + let k = 21; + let x: Result = Result::Err("bar"); + assert!(x.map_or_else(|_e| k * 2, |v: ByteArray| v.len()) == 42); +} + +#[test] +fn test_result_ok_map_err() { + let stringify = |x: u32| -> ByteArray { + format!("error code: {}", x) + }; + let x: Result = Result::Ok(2); + assert!(x.map_err(stringify) == Result::::Ok(2)); +} + +#[test] +fn test_result_err_map_err() { + let stringify = |x: u32| -> ByteArray { + format!("error code: {}", x) + }; + let x: Result = Result::Err(13); + assert!(x.map_err(stringify) == Result::Err("error code: 13")); +}