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