Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Option | extension methods simplifying work #91

Open
4 of 11 tasks
a-givertzman opened this issue Nov 6, 2024 · 0 comments · May be fixed by #92
Open
4 of 11 tasks

Option | extension methods simplifying work #91

a-givertzman opened this issue Nov 6, 2024 · 0 comments · May be fixed by #92

Comments

@a-givertzman
Copy link
Owner

a-givertzman commented Nov 6, 2024

Option | helpful methods

In addition to working with Option efficient,
some additional methods to be provided...

Implementations grouped by meaning

  • Querying the contained values
///
/// Returns `true` if the option is a [`Some`] value.
///
/// # Examples
///
/// ```
/// let x: Option<u32> = Some(2);
/// assert_eq!(x.is_some(), true);
///
/// let x: Option<u32> = None;
/// assert_eq!(x.is_some(), false);
/// ```
pub const fn is_some(&self) -> bool {
    matches!(*self, Some(_))
}
///
/// Returns `true` if the option is a [`Some`] and the value inside of it matches a predicate.
///
/// # Examples
///
/// ```
/// let x: Option<u32> = Some(2);
/// assert_eq!(x.is_some_and(|x| x > 1), true);
///
/// let x: Option<u32> = Some(0);
/// assert_eq!(x.is_some_and(|x| x > 1), false);
///
/// let x: Option<u32> = None;
/// assert_eq!(x.is_some_and(|x| x > 1), false);
/// ```
pub fn is_some_and(self, f: impl FnOnce(T) -> bool) -> bool {
    match self {
        None => false,
        Some(x) => f(x),
    }
}
///
/// Returns `true` if the option is a [`None`] value.
///
/// # Examples
///
/// ```
/// let x: Option<u32> = Some(2);
/// assert_eq!(x.is_none(), false);
///
/// let x: Option<u32> = None;
/// assert_eq!(x.is_none(), true);
/// ```
pub const fn is_none(&self) -> bool {
    !self.is_some()
}
///
/// Returns `true` if the option is a [`None`] or the value inside of it matches a predicate.
///
/// # Examples
///
/// ```
/// let x: Option<u32> = Some(2);
/// assert_eq!(x.is_none_or(|x| x > 1), true);
///
/// let x: Option<u32> = Some(0);
/// assert_eq!(x.is_none_or(|x| x > 1), false);
///
/// let x: Option<u32> = None;
/// assert_eq!(x.is_none_or(|x| x > 1), true);
/// ```
pub fn is_none_or(self, f: impl FnOnce(T) -> bool) -> bool {
    match self {
        None => true,
        Some(x) => f(x),
    }
}
  • Extracting contained values

    • expect
///
/// Returns the contained [`Some`] value, consuming the `self` value.
///
/// # Panics
///
/// Panics if the value is a [`None`] with a custom panic message provided by
/// `msg`.
///
/// # Examples
///
/// ```
/// let x = Some("value");
/// assert_eq!(x.expect("fruits are healthy"), "value");
/// ```
///
/// ```should_panic
/// let x: Option<&str> = None;
/// x.expect("fruits are healthy"); // panics with `fruits are healthy`
/// ```
///
/// # Recommended Message Style
///
/// We recommend that `expect` messages are used to describe the reason you
/// _expect_ the `Option` should be `Some`.
///
/// ```should_panic
/// # let slice: &[u8] = &[];
/// let item = slice.get(0)
///     .expect("slice should not be empty");
/// ```
///
/// **Hint**: If you're having trouble remembering how to phrase expect
/// error messages remember to focus on the word "should" as in "env
/// variable should be set by blah" or "the given binary should be available
/// and executable by the current user".
///
/// For more detail on expect message styles and the reasoning behind our
/// recommendation please refer to the section on ["Common Message
/// Styles"](../../std/error/index.html#common-message-styles) in the [`std::error`](../../std/error/index.html) module docs.
pub const fn expect(self, msg: &str) -> T {
    match self {
        Some(val) => val,
        None => expect_failed(msg),
    }
}
  • unwrap
///
/// Returns the contained [`Some`] value, consuming the `self` value.
///
/// Because this function may panic, its use is generally discouraged.
/// Instead, prefer to use pattern matching and handle the [`None`]
/// case explicitly, or call [`unwrap_or`], [`unwrap_or_else`], or
/// [`unwrap_or_default`].
///
/// [`unwrap_or`]: Option::unwrap_or
/// [`unwrap_or_else`]: Option::unwrap_or_else
/// [`unwrap_or_default`]: Option::unwrap_or_default
///
/// # Panics
///
/// Panics if the self value equals [`None`].
///
/// # Examples
///
/// ```
/// let x = Some("air");
/// assert_eq!(x.unwrap(), "air");
/// ```
///
/// ```should_panic
/// let x: Option<&str> = None;
/// assert_eq!(x.unwrap(), "air"); // fails
/// ```
pub const fn unwrap(self) -> T {
    match self {
        Some(val) => val,
        None => unwrap_failed(),
    }
}
  • unwrap_or
///
/// Returns the contained [`Some`] value or a provided default.
///
/// Arguments passed to `unwrap_or` are eagerly evaluated; if you are passing
/// the result of a function call, it is recommended to use [`unwrap_or_else`],
/// which is lazily evaluated.
///
/// [`unwrap_or_else`]: Option::unwrap_or_else
///
/// # Examples
///
/// ```
/// assert_eq!(Some("car").unwrap_or("bike"), "car");
/// assert_eq!(None.unwrap_or("bike"), "bike");
/// ```
pub fn unwrap_or(self, default: T) -> T {
    match self {
        Some(x) => x,
        None => default,
    }
}
  • unwrap_or_else
///
/// Returns the contained [`Some`] value or computes it from a closure.
///
/// # Examples
///
/// ```
/// let k = 10;
/// assert_eq!(Some(4).unwrap_or_else(|| 2 * k), 4);
/// assert_eq!(None.unwrap_or_else(|| 2 * k), 20);
/// ```
pub fn unwrap_or_else<F>(self, f: F) -> T
where
    F: FnOnce() -> T,
{
    match self {
        Some(x) => x,
        None => f(),
    }
}
  • unwrap_or_default
///
/// Returns the contained [`Some`] value or a default.
///
/// Consumes the `self` argument then, if [`Some`], returns the contained
/// value, otherwise if [`None`], returns the [default value] for that
/// type.
///
/// # Examples
///
/// ```
/// let x: Option<u32> = None;
/// let y: Option<u32> = Some(12);
///
/// assert_eq!(x.unwrap_or_default(), 0);
/// assert_eq!(y.unwrap_or_default(), 12);
/// ```
///
/// [default value]: Default::default
/// [`parse`]: str::parse
/// [`FromStr`]: crate::str::FromStr
- [ ] unwrap_or_default
pub fn unwrap_or_default(self) -> T
where
    T: Default,
{
    match self {
        Some(x) => x,
        None => T::default(),
    }
}
  • Transforming contained values
///
/// Maps an `Option<T>` to `Option<U>` by applying a function to a contained value (if `Some`) or returns `None` (if `None`).
///
/// # Examples
///
/// Calculates the length of an <code>Option<[String]></code> as an
/// <code>Option<[usize]></code>, consuming the original:
///
/// [String]: ../../std/string/struct.String.html "String"
/// ```
/// let maybe_some_string = Some(String::from("Hello, World!"));
/// // `Option::map` takes self *by value*, consuming `maybe_some_string`
/// let maybe_some_len = maybe_some_string.map(|s| s.len());
/// assert_eq!(maybe_some_len, Some(13));
///
/// let x: Option<&str> = None;
/// assert_eq!(x.map(|s| s.len()), None);
/// ```
pub fn map<U, F>(self, f: F) -> Option<U>
where
    F: FnOnce(T) -> U,
{
    match self {
        Some(x) => Some(f(x)),
        None => None,
    }
}
///
/// Calls a function with a reference to the contained value if [`Some`].
///
/// Returns the original option.
///
/// # Examples
///
/// ```
/// let list = vec![1, 2, 3];
///
/// // prints "got: 2"
/// let x = list
///     .get(1)
///     .inspect(|x| println!("got: {x}"))
///     .expect("list should be long enough");
///
/// // prints nothing
/// list.get(5).inspect(|x| println!("got: {x}"));
/// ```
pub fn inspect<F: FnOnce(&T)>(self, f: F) -> Self {
    if let Some(ref x) = self {
        f(x);
    }

    self
}
///
/// 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`]: Option::map_or_else
///
/// # Examples
///
/// ```
/// let x = Some("foo");
/// assert_eq!(x.map_or(42, |v| v.len()), 3);
///
/// let x: Option<&str> = None;
/// assert_eq!(x.map_or(42, |v| v.len()), 42);
/// ```
pub fn map_or<U, F>(self, default: U, f: F) -> U
where
    F: FnOnce(T) -> U,
{
    match self {
        Some(t) => f(t),
        None => default,
    }
}
///
/// 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 = Some("foo");
/// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 3);
///
/// let x: Option<&str> = None;
/// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 42);
/// ```
///
/// # Handling a Result-based fallback
///
/// A somewhat common occurrence when dealing with optional values
/// in combination with [`Result<T, E>`] is the case where one wants to invoke
/// a fallible fallback if the option is not present.  This example
/// parses a command line argument (if present), or the contents of a file to
/// an integer.  However, unlike accessing the command line argument, reading
/// the file is fallible, so it must be wrapped with `Ok`.
///
/// ```no_run
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let v: u64 = std::env::args()
///    .nth(1)
///    .map_or_else(|| std::fs::read_to_string("/etc/someconfig.conf"), Ok)?
///    .parse()?;
/// #   Ok(())
/// # }
/// ```
pub fn map_or_else<U, D, F>(self, default: D, f: F) -> U
where
    D: FnOnce() -> U,
    F: FnOnce(T) -> U,
{
    match self {
        Some(t) => f(t),
        None => default(),
    }
}
///
/// Transforms the `Option<T>` into a [`Result<T, E>`], mapping [`Some(v)`] to
/// [`Ok(v)`] and [`None`] to [`Err(err)`].
///
/// Arguments passed to `ok_or` are eagerly evaluated; if you are passing the
/// result of a function call, it is recommended to use [`ok_or_else`], which is
/// lazily evaluated.
///
/// [`Ok(v)`]: Ok
/// [`Err(err)`]: Err
/// [`Some(v)`]: Some
/// [`ok_or_else`]: Option::ok_or_else
///
/// # Examples
///
/// ```
/// let x = Some("foo");
/// assert_eq!(x.ok_or(0), Ok("foo"));
///
/// let x: Option<&str> = None;
/// assert_eq!(x.ok_or(0), Err(0));
/// ```
pub fn ok_or<E>(self, err: E) -> Result<T, E> {
    match self {
        Some(v) => Ok(v),
        None => Err(err),
    }
}
///
/// Transforms the `Option<T>` into a [`Result<T, E>`], mapping [`Some(v)`] to
/// [`Ok(v)`] and [`None`] to [`Err(err())`].
///
/// [`Ok(v)`]: Ok
/// [`Err(err())`]: Err
/// [`Some(v)`]: Some
///
/// # Examples
///
/// ```
/// let x = Some("foo");
/// assert_eq!(x.ok_or_else(|| 0), Ok("foo"));
///
/// let x: Option<&str> = None;
/// assert_eq!(x.ok_or_else(|| 0), Err(0));
/// ```
pub fn ok_or_else<E, F>(self, err: F) -> Result<T, E>
where
    F: FnOnce() -> E,
{
    match self {
        Some(v) => Ok(v),
        None => Err(err()),
    }
}
///
/// Converts from `Option<T>` (or `&Option<T>`) to `Option<&T::Target>`.
///
/// Leaves the original Option in-place, creating a new one with a reference
/// to the original one, additionally coercing the contents via [`Deref`].
///
/// # Examples
///
/// ```
/// let x: Option<String> = Some("hey".to_owned());
/// assert_eq!(x.as_deref(), Some("hey"));
///
/// let x: Option<String> = None;
/// assert_eq!(x.as_deref(), None);
/// ```
pub fn as_deref(&self) -> Option<&T::Target>
where
    T: Deref,
{
    match self.as_ref() {
        Some(t) => Some(t.deref()),
        None => None,
    }
}
///
/// Converts from `Option<T>` (or `&mut Option<T>`) to `Option<&mut T::Target>`.
///
/// Leaves the original `Option` in-place, creating a new one containing a mutable reference to
/// the inner type's [`Deref::Target`] type.
///
/// # Examples
///
/// ```
/// let mut x: Option<String> = Some("hey".to_owned());
/// assert_eq!(x.as_deref_mut().map(|x| {
///     x.make_ascii_uppercase();
///     x
/// }), Some("HEY".to_owned().as_mut_str()));
/// ```
pub fn as_deref_mut(&mut self) -> Option<&mut T::Target>
where
    T: DerefMut,
{
    match self.as_mut() {
        Some(t) => Some(t.deref_mut()),
        None => None,
    }
}
///
/// Returns a slice of the contained value, if any. If this is `None`, an
/// empty slice is returned. This can be useful to have a single type of
/// iterator over an `Option` or slice.
///
/// Note: Should you have an `Option<&T>` and wish to get a slice of `T`,
/// you can unpack it via `opt.map_or(&[], std::slice::from_ref)`.
///
/// # Examples
///
/// ```rust
/// assert_eq!(
///     [Some(1234).as_slice(), None.as_slice()],
///     [&[1234][..], &[][..]],
/// );
/// ```
///
/// The inverse of this function is (discounting
/// borrowing) [`[_]::first`](slice::first):
///
/// ```rust
/// for i in [Some(1234_u16), None] {
///     assert_eq!(i.as_ref(), i.as_slice().first());
/// }
/// ```
pub const fn as_slice(&self) -> &[T] {
    unsafe {
        slice::from_raw_parts(
            (self as *const Self).byte_add(core::mem::offset_of!(Self, Some.0)).cast(),
            self.len(),
        )
    }
}
  • Iterator constructors
///
/// Returns an iterator over the possibly contained value.
///
/// # Examples
///
/// ```
/// let x = Some(4);
/// assert_eq!(x.iter().next(), Some(&4));
///
/// let x: Option<u32> = None;
/// assert_eq!(x.iter().next(), None);
/// ```
pub const fn iter(&self) -> Iter<'_, T> {
    Iter { inner: Item { opt: self.as_ref() } }
}

- [ ] **Boolean operations on the values, eager and lazy**

///
/// Returns [`None`] if the option is [`None`], otherwise returns `optb`.
///
/// Arguments passed to `and` are eagerly evaluated; if you are passing the
/// result of a function call, it is recommended to use [`and_then`], which is
/// lazily evaluated.
///
/// [`and_then`]: Option::and_then
///
/// # Examples
///
/// ```
/// let x = Some(2);
/// let y: Option<&str> = None;
/// assert_eq!(x.and(y), None);
///
/// let x: Option<u32> = None;
/// let y = Some("foo");
/// assert_eq!(x.and(y), None);
///
/// let x = Some(2);
/// let y = Some("foo");
/// assert_eq!(x.and(y), Some("foo"));
///
/// let x: Option<u32> = None;
/// let y: Option<&str> = None;
/// assert_eq!(x.and(y), None);
/// ```
pub fn and<U>(self, optb: Option<U>) -> Option<U> {
    match self {
        Some(_) => optb,
        None => None,
    }
}
///
/// Returns [`None`] if the option is [`None`], otherwise calls `f` with the
/// wrapped value and returns the result.
///
/// Some languages call this operation flatmap.
///
/// # Examples
///
/// ```
/// fn sq_then_to_string(x: u32) -> Option<String> {
///     x.checked_mul(x).map(|sq| sq.to_string())
/// }
///
/// assert_eq!(Some(2).and_then(sq_then_to_string), Some(4.to_string()));
/// assert_eq!(Some(1_000_000).and_then(sq_then_to_string), None); // overflowed!
/// assert_eq!(None.and_then(sq_then_to_string), None);
/// ```
///
/// Often used to chain fallible operations that may return [`None`].
///
/// ```
/// let arr_2d = [["A0", "A1"], ["B0", "B1"]];
///
/// let item_0_1 = arr_2d.get(0).and_then(|row| row.get(1));
/// assert_eq!(item_0_1, Some(&"A1"));
///
/// let item_2_0 = arr_2d.get(2).and_then(|row| row.get(0));
/// assert_eq!(item_2_0, None);
/// ```
pub fn and_then<U, F>(self, f: F) -> Option<U>
where
    F: FnOnce(T) -> Option<U>,
{
    match self {
        Some(x) => f(x),
        None => None,
    }
}
///
/// Returns [`None`] if the option is [`None`], otherwise calls `predicate`
/// with the wrapped value and returns:
///
/// - [`Some(t)`] if `predicate` returns `true` (where `t` is the wrapped
///   value), and
/// - [`None`] if `predicate` returns `false`.
///
/// This function works similar to [`Iterator::filter()`]. You can imagine
/// the `Option<T>` being an iterator over one or zero elements. `filter()`
/// lets you decide which elements to keep.
///
/// # Examples
///
/// ```rust
/// fn is_even(n: &i32) -> bool {
///     n % 2 == 0
/// }
///
/// assert_eq!(None.filter(is_even), None);
/// assert_eq!(Some(3).filter(is_even), None);
/// assert_eq!(Some(4).filter(is_even), Some(4));
/// ```
///
/// [`Some(t)`]: Some
pub fn filter<P>(self, predicate: P) -> Self
where
    P: FnOnce(&T) -> bool,
{
    if let Some(x) = self {
        if predicate(&x) {
            return Some(x);
        }
    }
    None
}
///
/// Returns the option if it contains a value, otherwise returns `optb`.
///
/// Arguments passed to `or` are eagerly evaluated; if you are passing the
/// result of a function call, it is recommended to use [`or_else`], which is
/// lazily evaluated.
///
/// [`or_else`]: Option::or_else
///
/// # Examples
///
/// ```
/// let x = Some(2);
/// let y = None;
/// assert_eq!(x.or(y), Some(2));
///
/// let x = None;
/// let y = Some(100);
/// assert_eq!(x.or(y), Some(100));
///
/// let x = Some(2);
/// let y = Some(100);
/// assert_eq!(x.or(y), Some(2));
///
/// let x: Option<u32> = None;
/// let y = None;
/// assert_eq!(x.or(y), None);
/// ```
pub fn or(self, optb: Option<T>) -> Option<T> {
    match self {
        x @ Some(_) => x,
        None => optb,
    }
}
///
/// Returns the option if it contains a value, otherwise calls `f` and
/// returns the result.
///
/// # Examples
///
/// ```
/// fn nobody() -> Option<&'static str> { None }
/// fn vikings() -> Option<&'static str> { Some("vikings") }
///
/// assert_eq!(Some("barbarians").or_else(vikings), Some("barbarians"));
/// assert_eq!(None.or_else(vikings), Some("vikings"));
/// assert_eq!(None.or_else(nobody), None);
/// ```
pub fn or_else<F>(self, f: F) -> Option<T>
where
    F: FnOnce() -> Option<T>,
{
    match self {
        x @ Some(_) => x,
        None => f(),
    }
}
///
/// Returns [`Some`] if exactly one of `self`, `optb` is [`Some`], otherwise returns [`None`].
///
/// # Examples
///
/// ```
/// let x = Some(2);
/// let y: Option<u32> = None;
/// assert_eq!(x.xor(y), Some(2));
///
/// let x: Option<u32> = None;
/// let y = Some(2);
/// assert_eq!(x.xor(y), Some(2));
///
/// let x = Some(2);
/// let y = Some(2);
/// assert_eq!(x.xor(y), None);
///
/// let x: Option<u32> = None;
/// let y: Option<u32> = None;
/// assert_eq!(x.xor(y), None);
/// ```
pub fn xor(self, optb: Option<T>) -> Option<T> {
    match (self, optb) {
        (a @ Some(_), None) => a,
        (None, b @ Some(_)) => b,
        _ => None,
    }
}
  • Entry-like operations to insert a value and return a reference
///
/// Inserts `value` into the option, then returns a mutable reference to it.
///
/// If the option already contains a value, the old value is dropped.
///
/// See also [`Option::get_or_insert`], which doesn't update the value if
/// the option already contains [`Some`].
///
/// # Example
///
/// ```
/// let mut opt = None;
/// let val = opt.insert(1);
/// assert_eq!(*val, 1);
/// assert_eq!(opt.unwrap(), 1);
/// let val = opt.insert(2);
/// assert_eq!(*val, 2);
/// *val = 3;
/// assert_eq!(opt.unwrap(), 3);
/// ```
pub fn insert(&mut self, value: T) -> &mut T {
    *self = Some(value);
    unsafe { self.as_mut().unwrap_unchecked() }
}
///
/// Inserts `value` into the option if it is [`None`], then
/// returns a mutable reference to the contained value.
///
/// See also [`Option::insert`], which updates the value even if
/// the option already contains [`Some`].
///
/// # Examples
///
/// ```
/// let mut x = None;
///
/// {
///     let y: &mut u32 = x.get_or_insert(5);
///     assert_eq!(y, &5);
///
///     *y = 7;
/// }
///
/// assert_eq!(x, Some(7));
/// ```
pub fn get_or_insert(&mut self, value: T) -> &mut T {
    if let None = *self {
        *self = Some(value);
    }
    unsafe { self.as_mut().unwrap_unchecked() }
}
///
/// Inserts the default value into the option if it is [`None`], then
/// returns a mutable reference to the contained value.
///
/// # Examples
///
/// ```
/// #![feature(option_get_or_insert_default)]
///
/// let mut x = None;
///
/// {
///     let y: &mut u32 = x.get_or_insert_default();
///     assert_eq!(y, &0);
///
///     *y = 7;
/// }
///
/// assert_eq!(x, Some(7));
/// ```
pub fn get_or_insert_default(&mut self) -> &mut T
where
    T: Default,
{
    self.get_or_insert_with(T::default)
}
///
/// Inserts a value computed from `f` into the option if it is [`None`],
/// then returns a mutable reference to the contained value.
///
/// # Examples
///
/// ```
/// let mut x = None;
///
/// {
///     let y: &mut u32 = x.get_or_insert_with(|| 5);
///     assert_eq!(y, &5);
///
///     *y = 7;
/// }
///
/// assert_eq!(x, Some(7));
/// ```
pub fn get_or_insert_with<F>(&mut self, f: F) -> &mut T
where
    F: FnOnce() -> T,
{
    if let None = self {
        *self = Some(f());
    }

    // SAFETY: a `None` variant for `self` would have been replaced by a `Some`
    // variant in the code above.
    unsafe { self.as_mut().unwrap_unchecked() }
}
  • Misc
///
/// Takes the value out of the option, leaving a [`None`] in its place.
///
/// # Examples
///
/// ```
/// let mut x = Some(2);
/// let y = x.take();
/// assert_eq!(x, None);
/// assert_eq!(y, Some(2));
///
/// let mut x: Option<u32> = None;
/// let y = x.take();
/// assert_eq!(x, None);
/// assert_eq!(y, None);
/// ```
pub const fn take(&mut self) -> Option<T> {
    // FIXME replace `mem::replace` by `mem::take` when the latter is const ready
    mem::replace(self, None)
}
///
/// Takes the value out of the option, but only if the predicate evaluates to
/// `true` on a mutable reference to the value.
///
/// In other words, replaces `self` with `None` if the predicate returns `true`.
/// This method operates similar to [`Option::take`] but conditional.
///
/// # Examples
///
/// ```
/// let mut x = Some(42);
///
/// let prev = x.take_if(|v| if *v == 42 {
///     *v += 1;
///     false
/// } else {
///     false
/// });
/// assert_eq!(x, Some(43));
/// assert_eq!(prev, None);
///
/// let prev = x.take_if(|v| *v == 43);
/// assert_eq!(x, None);
/// assert_eq!(prev, Some(43));
/// ```
pub fn take_if<P>(&mut self, predicate: P) -> Option<T>
where
    P: FnOnce(&mut T) -> bool,
{
    if self.as_mut().map_or(false, predicate) { self.take() } else { None }
}
///
/// Replaces the actual value in the option by the value given in parameter,
/// returning the old value if present,
/// leaving a [`Some`] in its place without deinitializing either one.
///
/// # Examples
///
/// ```
/// let mut x = Some(2);
/// let old = x.replace(5);
/// assert_eq!(x, Some(5));
/// assert_eq!(old, Some(2));
///
/// let mut x = None;
/// let old = x.replace(3);
/// assert_eq!(x, Some(3));
/// assert_eq!(old, None);
/// ```
pub const fn replace(&mut self, value: T) -> Option<T> {
    mem::replace(self, Some(value))
}
///
/// Zips `self` with another `Option`.
///
/// If `self` is `Some(s)` and `other` is `Some(o)`, this method returns `Some((s, o))`.
/// Otherwise, `None` is returned.
///
/// # Examples
///
/// ```
/// let x = Some(1);
/// let y = Some("hi");
/// let z = None::<u8>;
///
/// assert_eq!(x.zip(y), Some((1, "hi")));
/// assert_eq!(x.zip(z), None);
/// ```
pub fn zip<U>(self, other: Option<U>) -> Option<(T, U)> {
    match (self, other) {
        (Some(a), Some(b)) => Some((a, b)),
        _ => None,
    }
}
///
/// Zips `self` and another `Option` with function `f`.
///
/// If `self` is `Some(s)` and `other` is `Some(o)`, this method returns `Some(f(s, o))`.
/// Otherwise, `None` is returned.
///
/// # Examples
///
/// ```
/// #![feature(option_zip)]
///
/// #[derive(Debug, PartialEq)]
/// struct Point {
///     x: f64,
///     y: f64,
/// }
///
/// impl Point {
///     fn new(x: f64, y: f64) -> Self {
///         Self { x, y }
///     }
/// }
///
/// let x = Some(17.5);
/// let y = Some(42.7);
///
/// assert_eq!(x.zip_with(y, Point::new), Some(Point { x: 17.5, y: 42.7 }));
/// assert_eq!(x.zip_with(None, Point::new), None);
/// ```
pub fn zip_with<U, F, R>(self, other: Option<U>, f: F) -> Option<R>
where
    F: FnOnce(T, U) -> R,
{
    match (self, other) {
        (Some(a), Some(b)) => Some(f(a, b)),
        _ => None,
    }
}
@a-givertzman a-givertzman changed the title Option | extensions to simplify work Option | extension methods simplifying work Nov 6, 2024
@a-givertzman a-givertzman linked a pull request Nov 6, 2024 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant