From 438e84cfc234b93d556cd76c0e971b02f79eaa8b Mon Sep 17 00:00:00 2001 From: cairolover Date: Tue, 24 Dec 2024 22:16:47 +0100 Subject: [PATCH 1/2] feat(corelib): option map --- corelib/src/option.cairo | 80 ++++++++++++++++++++++-------- corelib/src/test/option_test.cairo | 27 ++++++++++ 2 files changed, 87 insertions(+), 20 deletions(-) diff --git a/corelib/src/option.cairo b/corelib/src/option.cairo index 2402cf0e359..1014d20870d 100644 --- a/corelib/src/option.cairo +++ b/corelib/src/option.cairo @@ -119,6 +119,14 @@ //! [`Ok(v)`]: Result::Ok //! [`Some(v)`]: Option::Some //! [`ok_or`]: OptionTrait::ok_or +//! +//! These methods transform the [`Some`] variant: +//! +//! * [`map`] transforms [`Option`] to [`Option`] by applying the +//! provided function to the contained value of [`Some`] and leaving +//! [`None`] values unchanged +//! +//! [`map`]: OptionTrait::map /// The `Option` enum representing either `Some(value)` or `None`. #[must_use] @@ -175,18 +183,6 @@ pub trait OptionTrait { /// ``` fn unwrap(self: Option) -> T; - /// Transforms the `Option` into a `Result`, mapping `Option::Some(v)` to - /// `Result::Ok(v)` and `Option::None` to `Result::Err(err)`. - /// - /// # Examples - /// - /// ``` - /// let option = Option::Some(123); - /// let result = option.ok_or('no value'); - /// assert!(result.unwrap() == 123); - /// ``` - fn ok_or>(self: Option, err: E) -> Result; - /// Returns `true` if the `Option` is `Option::Some`, `false` otherwise. /// /// # Examples @@ -251,6 +247,40 @@ pub trait OptionTrait { >( self: Option, f: F, ) -> T; + + ///////////////////////////////////////////////////////////////////////// + // Transforming contained values + ///////////////////////////////////////////////////////////////////////// + + /// Maps an `Option` to `Option` by applying a function to a contained value (if `Some`) + /// or returns `None` (if `None`). + /// + /// # Examples + /// + /// ``` + /// let maybe_some_string: Option = Option::Some("Hello, World!"); + /// // `Option::map` takes self *by value*, consuming `maybe_some_string` + /// let maybe_some_len = maybe_some_string.map(|s: ByteArray| s.len()); + /// assert!(maybe_some_len == Option::Some(13)); + /// + /// let x: Option = Option::None; + /// assert!(x.map(|s: ByteArray| s.len()) == Option::None); + /// ``` + fn map, +core::ops::FnOnce[Output: U]>( + self: Option, f: F, + ) -> Option; + + /// Transforms the `Option` into a `Result`, mapping `Option::Some(v)` to + /// `Result::Ok(v)` and `Option::None` to `Result::Err(err)`. + /// + /// # Examples + /// + /// ``` + /// let option = Option::Some(123); + /// let result = option.ok_or('no value'); + /// assert!(result.unwrap() == 123); + /// ``` + fn ok_or>(self: Option, err: E) -> Result; } pub impl OptionTraitImpl of OptionTrait { @@ -267,14 +297,6 @@ pub impl OptionTraitImpl of OptionTrait { self.expect('Option::unwrap failed.') } - #[inline] - fn ok_or>(self: Option, err: E) -> Result { - match self { - Option::Some(v) => Result::Ok(v), - Option::None => Result::Err(err), - } - } - #[inline] fn is_some(self: @Option) -> bool { match self { @@ -318,4 +340,22 @@ pub impl OptionTraitImpl of OptionTrait { Option::None => f(), } } + + #[inline] + fn map, +core::ops::FnOnce[Output: U]>( + self: Option, f: F, + ) -> Option { + match self { + Option::Some(x) => Option::Some(f(x)), + Option::None => Option::None, + } + } + + #[inline] + fn ok_or>(self: Option, err: E) -> Result { + match self { + Option::Some(v) => Result::Ok(v), + Option::None => Result::Err(err), + } + } } diff --git a/corelib/src/test/option_test.cairo b/corelib/src/test/option_test.cairo index 4d2d8a01420..70c655cec4b 100644 --- a/corelib/src/test/option_test.cairo +++ b/corelib/src/test/option_test.cairo @@ -78,3 +78,30 @@ fn test_default_for_option() { assert!(Default::>::default().is_none()); assert!(Default::>::default().is_none()); } + +#[test] +fn test_option_some_map() { + let maybe_some_string: Option = Option::Some("Hello, World!"); + let maybe_some_len = maybe_some_string.map(|s: ByteArray| s.len()); + assert!(maybe_some_len == Option::Some(13)); +} + +#[test] +fn test_option_none_map() { + let x: Option = Option::None; + assert!(x.map(|s: ByteArray| s.len()) == Option::None); +} + +#[test] +fn test_option_some_ok_or() { + let x = Option::Some(123); + let result = x.ok_or('no value'); + assert!(result == Result::Ok(123)); +} + +#[test] +fn test_option_none_ok_or() { + let x: Option = Option::None; + let result = x.ok_or('no value'); + assert!(result == Result::Err('no value')); +} From 62947da5f34e3fb26db49006ae62b3c6ce61be87 Mon Sep 17 00:00:00 2001 From: cairolover Date: Thu, 26 Dec 2024 08:56:26 +0100 Subject: [PATCH 2/2] un-move ok_or --- corelib/src/option.cairo | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/corelib/src/option.cairo b/corelib/src/option.cairo index 1014d20870d..bd7777cc8b7 100644 --- a/corelib/src/option.cairo +++ b/corelib/src/option.cairo @@ -183,6 +183,18 @@ pub trait OptionTrait { /// ``` fn unwrap(self: Option) -> T; + /// Transforms the `Option` into a `Result`, mapping `Option::Some(v)` to + /// `Result::Ok(v)` and `Option::None` to `Result::Err(err)`. + /// + /// # Examples + /// + /// ``` + /// let option = Option::Some(123); + /// let result = option.ok_or('no value'); + /// assert!(result.unwrap() == 123); + /// ``` + fn ok_or>(self: Option, err: E) -> Result; + /// Returns `true` if the `Option` is `Option::Some`, `false` otherwise. /// /// # Examples @@ -269,18 +281,6 @@ pub trait OptionTrait { fn map, +core::ops::FnOnce[Output: U]>( self: Option, f: F, ) -> Option; - - /// Transforms the `Option` into a `Result`, mapping `Option::Some(v)` to - /// `Result::Ok(v)` and `Option::None` to `Result::Err(err)`. - /// - /// # Examples - /// - /// ``` - /// let option = Option::Some(123); - /// let result = option.ok_or('no value'); - /// assert!(result.unwrap() == 123); - /// ``` - fn ok_or>(self: Option, err: E) -> Result; } pub impl OptionTraitImpl of OptionTrait { @@ -297,6 +297,14 @@ pub impl OptionTraitImpl of OptionTrait { self.expect('Option::unwrap failed.') } + #[inline] + fn ok_or>(self: Option, err: E) -> Result { + match self { + Option::Some(v) => Result::Ok(v), + Option::None => Result::Err(err), + } + } + #[inline] fn is_some(self: @Option) -> bool { match self { @@ -350,12 +358,4 @@ pub impl OptionTraitImpl of OptionTrait { Option::None => Option::None, } } - - #[inline] - fn ok_or>(self: Option, err: E) -> Result { - match self { - Option::Some(v) => Result::Ok(v), - Option::None => Result::Err(err), - } - } }