1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
//! Extra utilities for handling optionality.
//!
//! This module extends capabilities offered by [`std::option`].
/// Extension with a set of extra combinators for `Option<A>`.
pub trait OptionExt<A> {
/// Applies `f` yielding yet another option if `Some(x)` otherwise propagates `None`.
///
/// ```
/// use lifterr::option::OptionExt;
///
/// fn some() -> Option<i32> { Some(1) }
/// fn none() -> Option<i32> { None }
///
/// assert_eq!(some().then(|| Some("42")), Some("42"));
/// assert_eq!(none().then(|| Some("42")), None);
/// ```
fn then<F, B>(self, f: F) -> Option<B>
where
F: Fn() -> Option<B>;
/// Applies `f` yielding a value which is then wrapped into another option if `Some(x)` otherwise propagates `None`.
///
/// ```
/// use lifterr::option::OptionExt;
///
/// fn some() -> Option<i32> { Some(1) }
/// fn none() -> Option<i32> { None }
///
/// assert_eq!(some().remap(|| "42"), Some("42"));
/// assert_eq!(none().remap(|| "42"), None);
/// ```
fn remap<F, B>(self, f: F) -> Option<B>
where
Self: Sized,
F: Fn() -> B,
{
self.then(|| f().into())
}
/// Replaces whatever value of type `A` in `Option<A>` with an unit.
fn void(self) -> Option<()>
where
Self: Sized,
{
self.remap(|| ())
}
/// Recovers from an absent value with a total function.
fn recover<F>(self, f: F) -> Option<A>
where
F: FnOnce() -> A,
Self: Sized,
{
self.recover_with(|| f().into())
}
/// Recovers from an absent value with a partial function.
///
/// ```
/// use lifterr::option::OptionExt;
///
/// fn not_found() -> Option<i32> { None }
/// fn fallback() -> Option<i32> { Some(42) }
///
/// assert_eq!(Some(10).recover_with(fallback), Some(10));
/// assert_eq!(not_found().recover_with(fallback), Some(42));
/// ```
fn recover_with<F>(self, f: F) -> Option<A>
where
F: FnOnce() -> Option<A>;
}
impl<A> OptionExt<A> for Option<A> {
fn then<F, B>(self, f: F) -> Option<B>
where
F: Fn() -> Option<B>,
{
self.and_then(|_| f())
}
fn recover_with<F>(self, f: F) -> Option<A>
where
F: FnOnce() -> Option<A>,
{
self.map_or_else(f, A::into)
}
}