Skip to content

Commit

Permalink
Add docs and filter, flatten methods
Browse files Browse the repository at this point in the history
  • Loading branch information
jfecher committed Aug 1, 2023
1 parent 7b7cef0 commit cdee978
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 3 deletions.
3 changes: 2 additions & 1 deletion crates/nargo_cli/tests/test_data/option/Nargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[package]
name = "option"
authors = [""]
compiler_version = "0.7.0"

[dependencies]
[dependencies]
2 changes: 1 addition & 1 deletion crates/noirc_evaluator/src/ssa_refactor/acir_gen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -998,7 +998,7 @@ impl Context {
}
Intrinsic::ArrayLen => {
let len = match self.convert_value(arguments[0], dfg) {
AcirValue::Var(_, _) => unreachable!("Non-array passed to array.len() method"),
AcirValue::Var(_, _) => unreachable!("Non-array passed to array.len() method"),
AcirValue::Array(values) => (values.len() as u128).into(),
AcirValue::DynamicArray(array) => (array.len as u128).into(),
};
Expand Down
46 changes: 45 additions & 1 deletion noir_stdlib/src/option.nr
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,33 @@ struct Option<T> {
}

impl<T> Option<T> {
/// Constructs a None value
fn none() -> Self {
Self { _is_some: false, value: crate::unsafe::zeroed() }
}

/// Constructs a Some wrapper around the given value
fn some(value: T) -> Self {
Self { _is_some: true, value }
}

/// True if this Option is None
fn is_none(self) -> bool {
!self._is_some
}

/// True if this Option is Some
fn is_some(self) -> bool {
self._is_some
}

/// Asserts `self.is_some()` and returns the wrapped value.
fn unwrap(self) -> T {
assert(self._is_some);
self.value
}

/// Returns the wrapped value if `self.is_some()`. Otherwise, returns the given default value.
fn unwrap_or(self, default: T) -> T {
if self._is_some {
self.value
Expand All @@ -33,6 +39,8 @@ impl<T> Option<T> {
}
}

/// Returns the wrapped value if `self.is_some()`. Otherwise, calls the given function to return
/// a default value.
fn unwrap_or_else(self, default: fn() -> T) -> T {
if self._is_some {
self.value
Expand All @@ -41,6 +49,7 @@ impl<T> Option<T> {
}
}

/// If self is `Some(x)`, this returns `Some(f(x))`. Otherwise, this returns `None`.
fn map<U>(self, f: fn(T) -> U) -> Option<U> {
if self._is_some {
Option::some(f(self.value))
Expand All @@ -49,6 +58,7 @@ impl<T> Option<T> {
}
}

/// If self is `Some(x)`, this returns `f(x)`. Otherwise, this returns the given default value.
fn map_or<U>(self, default: U, f: fn(T) -> U) -> U {
if self._is_some {
f(self.value)
Expand All @@ -57,6 +67,7 @@ impl<T> Option<T> {
}
}

/// If self is `Some(x)`, this returns `f(x)`. Otherwise, this returns `default()`.
fn map_or_else<U>(self, default: fn() -> U, f: fn(T) -> U) -> U {
if self._is_some {
f(self.value)
Expand All @@ -65,6 +76,7 @@ impl<T> Option<T> {
}
}

/// Returns None if self is None. Otherwise, this returns `other`.
fn and(self, other: Self) -> Self {
if self.is_none() {
Option::none()
Expand All @@ -73,6 +85,10 @@ impl<T> Option<T> {
}
}

/// If self is None, this returns None. Otherwise, this calls the given function
/// with the Some value contained within self, and returns the result of that call.
///
/// In some languages this function is called `flat_map` or `bind`.
fn and_then<U>(self, f: fn(T) -> Option<U>) -> Option<U> {
if self._is_some {
f(self.value)
Expand All @@ -81,6 +97,7 @@ impl<T> Option<T> {
}
}

/// If self is Some, return self. Otherwise, return `other`.
fn or(self, other: Self) -> Self {
if self._is_some {
self
Expand All @@ -89,14 +106,17 @@ impl<T> Option<T> {
}
}

fn or_else<U>(self, default: fn() -> Option<T>) -> Option<T> {
/// If self is Some, return self. Otherwise, return `default()`.
fn or_else<U>(self, default: fn() -> Self) -> Self {
if self._is_some {
self
} else {
default()
}
}

// If only one of the two Options is Some, return that option.
// Otherwise, if both options are Some or both are None, None is returned.
fn xor(self, other: Self) -> Self {
if self._is_some {
if other._is_some {
Expand All @@ -110,4 +130,28 @@ impl<T> Option<T> {
Option::none()
}
}

/// Returns `Some(x)` if self is `Some(x)` and `predicate(x)` is true.
/// Otherwise, this returns `None`
fn filter(self, predicate: fn(T) -> bool) -> Self {
if self._is_some {
if predicate(self.value) {
self
} else {
None
}
} else {
None
}
}

/// Flattens an Option<Option<T>> into a Option<T>.
/// This returns None if the outer Option is None. Otherwise, this returns the inner Option.
fn flatten(option: Option<Option<T>>) -> Option<T> {
if option._is_some {
option.value
} else {
None
}
}
}

0 comments on commit cdee978

Please sign in to comment.