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}