option_either_or/
lib.rs

1//! An extension trait for [`Option<T>`] which provides conversion to [`Either`].
2//!
3//! Deriving the naming conventions from [`Option::ok_or`] and [`Option::ok_or_else`] would lead to
4//! symmetrical methods: `left_or` and `left_or_else` (and analogically for converting [`Some`] to
5//! [`Right`]), but since the purpose of this conversion pattern is to be a generalization of
6//! [`Option::unwrap_or`] ([`_else`]) supporting different types for different branches, whether
7//! [`Some`] maps to [`Left`] or [`Right`] is irrelevant. As a result, the [`OptionEitherOr`]
8//! extension trait provides [`either_or`] and [`either_or_else`].
9//!
10//! Providing conversions where it matters whether [`Some`] is mapped to [`Left`] or [`Right`] is
11//! out of scope of this crate.
12//!
13//! [`Either`]: either::Either
14//! [`Left`]: either::Either::Left
15//! [`Right`]: either::Either::Right
16//! [`_else`]: Option::unwrap_or_else
17//! [`either_or`]: OptionEitherOr::either_or
18//! [`either_or_else`]: OptionEitherOr::either_or_else
19
20#![no_std]
21
22use either::Either;
23
24/// A trait that provides conversion to [`Either`]
25pub trait OptionEitherOr {
26    /// The type that will be converted into [`Either::Right`]
27    type R;
28
29    /// Convert `Self::R` into [`Either::Right`] or value returned from `f` into [`Either::Left`]
30    /// if [`None`].
31    fn either_or_else<F: FnOnce() -> L, L>(self, f: F) -> Either<L, Self::R>;
32
33    /// Convert `Self::R` into [`Either::Right`] or `l` into [`Either::Left`] if [`None`].
34    fn either_or<L>(self, l: L) -> Either<L, Self::R>
35    where
36        Self: Sized,
37    {
38        self.either_or_else(|| l)
39    }
40}
41
42impl<T> OptionEitherOr for Option<T> {
43    type R = T;
44
45    fn either_or_else<F: FnOnce() -> L, L>(self, f: F) -> Either<L, Self::R> {
46        match self {
47            Some(l) => Either::Right(l),
48            None => Either::Left(f()),
49        }
50    }
51}
52
53#[cfg(test)]
54mod test {
55    use either::Either;
56
57    use crate::OptionEitherOr;
58
59    #[test]
60    fn converts_some() {
61        let o = Some("a");
62        let e = o.either_or(3);
63        assert_eq!(e, Either::Right("a"))
64    }
65
66    #[test]
67    fn converts_none() {
68        let o = Option::<()>::None;
69        let e = o.either_or(3);
70        assert_eq!(e, Either::Left(3))
71    }
72}