Skip to content

Commit

Permalink
feat(corelib): OptionTrait::map_or, OptionTrait::map_or_else (#6935)
Browse files Browse the repository at this point in the history
Co-authored-by: orizi <[email protected]>
  • Loading branch information
julio4 and orizi authored Dec 31, 2024
1 parent f593c6d commit 9d2d903
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 0 deletions.
91 changes: 91 additions & 0 deletions corelib/src/option.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,19 @@
//!
//! [`map`]: OptionTrait::map
//!
//! These methods transform [`Option<T>`] to a value of a possibly
//! different type `U`:
//!
//! * [`map_or`] applies the provided function to the contained value of
//! [`Some`], or returns the provided default value if the [`Option`] is
//! [`None`]
//! * [`map_or_else`] applies the provided function to the contained value
//! of [`Some`], or returns the result of evaluating the provided
//! fallback function if the [`Option`] is [`None`]
//!
//! [`map_or`]: OptionTrait::map_or
//! [`map_or_else`]: OptionTrait::map_or_else
//!
//! ## Boolean operators
//!
//! These methods treat the [`Option`] as a boolean value, where [`Some`]
Expand Down Expand Up @@ -506,6 +519,55 @@ pub trait OptionTrait<T> {
fn map<U, F, +Drop<F>, +core::ops::FnOnce<F, (T,)>[Output: U]>(
self: Option<T>, f: F,
) -> Option<U>;

/// Returns the provided default result (if none),
/// or applies a function to the contained value (if any).
///
/// Arguments passed to `map_or` are eagerly evaluated; if you are passing
/// the result of a function call, it is recommended to use [`map_or_else`],
/// which is lazily evaluated.
///
/// [`map_or_else`]: OptionTrait::map_or_else
///
/// # Examples
///
/// ```
/// assert_eq!(Option::Some("foo").map_or(42, |v: ByteArray| v.len()), 3);
///
/// let x: Option<ByteArray> = Option::None;
/// assert_eq!(x.map_or(42, |v: ByteArray| v.len()), 42);
/// ```
#[must_use]
fn map_or<U, F, +Drop<U>, +Drop<F>, +core::ops::FnOnce<F, (T,)>[Output: U]>(
self: Option<T>, default: U, f: F,
) -> U;

/// Computes a default function result (if none), or
/// applies a different function to the contained value (if any).
///
/// # Basic examples
///
/// ```
/// let k = 21;
///
/// let x = Option::Some("foo");
/// assert_eq!(x.map_or_else( || 2 * k, |v: ByteArray| v.len()), 3);
///
/// let x: Option<ByteArray> = Option::None;
/// assert_eq!(x.map_or_else( || 2 * k, |v: ByteArray| v.len()), 42);
/// ```
fn map_or_else<
U,
D,
F,
+Drop<U>,
+Drop<D>,
+Drop<F>,
+core::ops::FnOnce<D, ()>[Output: U],
+core::ops::FnOnce<F, (T,)>[Output: U],
>(
self: Option<T>, default: D, f: F,
) -> U;
}

pub impl OptionTraitImpl<T> of OptionTrait<T> {
Expand Down Expand Up @@ -658,4 +720,33 @@ pub impl OptionTraitImpl<T> of OptionTrait<T> {
Option::None => Option::None,
}
}

#[inline]
fn map_or<U, F, +Drop<U>, +Drop<F>, +core::ops::FnOnce<F, (T,)>[Output: U]>(
self: Option<T>, default: U, f: F,
) -> U {
match self {
Option::Some(x) => f(x),
Option::None => default,
}
}

#[inline]
fn map_or_else<
U,
D,
F,
+Drop<U>,
+Drop<D>,
+Drop<F>,
+core::ops::FnOnce<D, ()>[Output: U],
+core::ops::FnOnce<F, (T,)>[Output: U],
>(
self: Option<T>, default: D, f: F,
) -> U {
match self {
Option::Some(x) => f(x),
Option::None => default(),
}
}
}
25 changes: 25 additions & 0 deletions corelib/src/test/option_test.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -218,3 +218,28 @@ fn test_option_none_map() {
let x: Option<ByteArray> = Option::None;
assert!(x.map(|s: ByteArray| s.len()) == Option::None);
}

#[test]
fn test_option_some_map_or() {
assert_eq!(Option::Some("foo").map_or(42, |v: ByteArray| v.len()), 3);
}

#[test]
fn test_option_none_map_or() {
let x: Option<ByteArray> = Option::None;
assert_eq!(x.map_or(42, |v: ByteArray| v.len()), 42);
}

#[test]
fn test_option_some_map_or_else() {
let k = 21;
let x = Option::Some("foo");
assert_eq!(x.map_or_else( || 2 * k, |v: ByteArray| v.len()), 3);
}

#[test]
fn test_option_none_map_or_else() {
let k = 21;
let x: Option<ByteArray> = Option::None;
assert_eq!(x.map_or_else( || 2 * k, |v: ByteArray| v.len()), 42);
}

0 comments on commit 9d2d903

Please sign in to comment.