tuwunel_core/utils/bool.rs
1//! Trait BoolExt
2
3use futures::future::OptionFuture;
4
5/// Adds composable branching and conversion operations to Boolean values.
6///
7/// The adapters map conditions into options, results, futures, or selected
8/// values. Lazy variants invoke their closure only on the documented branch.
9pub trait BoolExt {
10 /// Retains `t` only when the Boolean is true.
11 ///
12 /// A false value produces `None` regardless of `t`. An existing `None`
13 /// remains absent on either branch.
14 fn and<T>(self, t: Option<T>) -> Option<T>;
15
16 /// Computes the conjunction with another Boolean.
17 ///
18 /// Both operands are already evaluated before the method runs. The result
19 /// is true only when both values are true.
20 #[must_use]
21 fn and_is(self, b: bool) -> bool;
22
23 /// Computes a conjunction with the closure's Boolean result.
24 ///
25 /// The closure is invoked even when the receiver is false. Its result is
26 /// then combined with the receiver using logical conjunction.
27 #[must_use]
28 fn and_if<F: FnOnce() -> bool>(self, f: F) -> bool;
29
30 /// Invokes `f` and returns its option only when the Boolean is true.
31 ///
32 /// A false receiver returns `None` without calling the closure. A true
33 /// receiver preserves either option variant returned by `f`.
34 fn and_then<T, F: FnOnce() -> Option<T>>(self, f: F) -> Option<T>;
35
36 /// Clones `t` when true or returns `err` when false.
37 ///
38 /// The referenced value is cloned only for the true branch. The owned
39 /// fallback is returned for false and dropped for true.
40 #[must_use]
41 fn clone_or<T: Clone>(self, err: T, t: &T) -> T;
42
43 /// Copies `t` when true or returns `err` when false.
44 ///
45 /// Both candidate values are passed by value. The Boolean selects which
46 /// copy becomes the result.
47 #[must_use]
48 fn copy_or<T: Copy>(self, err: T, t: T) -> T;
49
50 /// Asserts that the Boolean is true and returns it.
51 ///
52 /// A successful assertion always returns `true`. The supplied message is
53 /// used only for a failed assertion.
54 ///
55 /// # Panics
56 ///
57 /// Panics with `msg` when the Boolean is false.
58 #[must_use]
59 fn expect(self, msg: &str) -> Self;
60
61 /// Asserts that the Boolean is false and returns it.
62 ///
63 /// A successful assertion always returns `false`. The supplied message is
64 /// used only for a failed assertion.
65 ///
66 /// # Panics
67 ///
68 /// Panics with `msg` when the Boolean is true.
69 #[must_use]
70 fn expect_false(self, msg: &str) -> Self;
71
72 /// Converts true to `Some(())` and false to `None`.
73 ///
74 /// The unit value carries no additional state. The option is useful for
75 /// continuing condition-driven combinator chains.
76 fn into_option(self) -> Option<()>;
77
78 /// Converts true to `Ok(())` and false to `Err(())`.
79 ///
80 /// Both result payloads are unit values. The conversion preserves only the
81 /// receiver's success or failure state.
82 #[expect(clippy::result_unit_err)]
83 fn into_result(self) -> Result<(), ()>;
84
85 /// Reports whether the Boolean is false.
86 ///
87 /// The receiver is borrowed rather than consumed. The returned value is the
88 /// logical negation of the receiver.
89 #[must_use]
90 fn is_false(&self) -> Self;
91
92 /// Applies `f` to the Boolean value.
93 ///
94 /// The closure is invoked exactly once for either Boolean branch. This
95 /// method allows a Boolean to begin a generic method chain.
96 fn map<T, F: FnOnce(Self) -> T>(self, f: F) -> T
97 where
98 Self: Sized;
99
100 /// Maps true through `f` or returns `err` for false.
101 ///
102 /// The closure is called only for the true branch. The error is supplied
103 /// eagerly, returned for false, and dropped for true.
104 fn map_ok_or<T, E, F: FnOnce() -> T>(self, err: E, f: F) -> Result<T, E>;
105
106 /// Maps true through `f` or returns `err` for false.
107 ///
108 /// The closure is called only for the true branch. The fallback value is
109 /// returned directly when the receiver is false.
110 fn map_or<T, F: FnOnce() -> T>(self, err: T, f: F) -> T;
111
112 /// Selects between lazy false and true branch closures.
113 ///
114 /// `f` is invoked when the receiver is true, while `err` is invoked when it
115 /// is false. Exactly one closure runs.
116 fn map_or_else<T, E: FnOnce() -> T, F: FnOnce() -> T>(self, err: E, f: F) -> T;
117
118 /// Converts true to `Ok(())` and false to the supplied error.
119 ///
120 /// The error value is supplied eagerly and returned by the false branch.
121 /// The true branch drops it and carries a unit success value.
122 fn ok_or<E>(self, err: E) -> Result<(), E>;
123
124 /// Converts true to `Ok(())` or lazily creates an error for false.
125 ///
126 /// The closure is called only when the receiver is false. A true receiver
127 /// produces the unit success value directly.
128 fn ok_or_else<E, F: FnOnce() -> E>(self, err: F) -> Result<(), E>;
129
130 /// Invokes `f` and returns its value only when the Boolean is false.
131 ///
132 /// A true receiver returns `None` without calling the closure. It is the
133 /// false-branch counterpart to `bool::then`.
134 fn or<T, F: FnOnce() -> T>(self, f: F) -> Option<T>;
135
136 /// Returns `Some(t)` when false and `None` when true.
137 ///
138 /// The supplied value is returned for false and dropped for true. It is the
139 /// inverse of `bool::then_some`.
140 fn or_some<T>(self, t: T) -> Option<T>;
141
142 /// Creates an optional future only when the Boolean is true.
143 ///
144 /// The closure is not invoked for a false receiver. Awaiting the returned
145 /// [`OptionFuture`] yields `Some(output)` when constructed or `None`
146 /// otherwise.
147 fn then_async<O: Future, F: FnOnce() -> O>(self, f: F) -> OptionFuture<O>;
148
149 /// Produces an absent option for any Boolean value.
150 ///
151 /// The receiver is consumed only to preserve chain shape. No value is
152 /// constructed for either branch.
153 fn then_none<T>(self) -> Option<T>;
154
155 /// Returns `Ok(t)` when true or `Err(e)` when false.
156 ///
157 /// Both values are supplied eagerly and the Boolean selects the result
158 /// variant. Neither value is converted.
159 fn then_ok_or<T, E>(self, t: T, e: E) -> Result<T, E>;
160
161 /// Returns `Ok(t)` when true or lazily creates an error when false.
162 ///
163 /// The error closure is called only for the false branch. The success value
164 /// is moved into `Ok` when the receiver is true.
165 fn then_ok_or_else<T, E, F: FnOnce() -> E>(self, t: T, e: F) -> Result<T, E>;
166}
167
168impl BoolExt for bool {
169 #[inline]
170 fn and<T>(self, t: Option<T>) -> Option<T> { self.then_some(t).flatten() }
171
172 #[inline]
173 fn and_if<F: FnOnce() -> Self>(self, f: F) -> Self { self.and_is(f()) }
174
175 #[inline]
176 fn and_is(self, b: Self) -> Self { self && b }
177
178 #[inline]
179 fn and_then<T, F: FnOnce() -> Option<T>>(self, f: F) -> Option<T> { self.then(f).flatten() }
180
181 #[inline]
182 fn clone_or<T: Clone>(self, err: T, t: &T) -> T { self.map_or(err, || t.clone()) }
183
184 #[inline]
185 fn copy_or<T: Copy>(self, err: T, t: T) -> T { self.map_or(err, || t) }
186
187 #[inline]
188 fn expect(self, msg: &str) -> Self { self.then_some(true).expect(msg) }
189
190 #[inline]
191 fn expect_false(self, msg: &str) -> Self { self.is_false().then_some(false).expect(msg) }
192
193 #[inline]
194 fn into_option(self) -> Option<()> { self.then_some(()) }
195
196 #[inline]
197 fn into_result(self) -> Result<(), ()> { self.ok_or(()) }
198
199 #[inline]
200 fn is_false(&self) -> Self { self.eq(&false) }
201
202 #[inline]
203 fn map<T, F: FnOnce(Self) -> T>(self, f: F) -> T
204 where
205 Self: Sized,
206 {
207 f(self)
208 }
209
210 #[inline]
211 fn map_ok_or<T, E, F: FnOnce() -> T>(self, err: E, f: F) -> Result<T, E> {
212 self.ok_or(err).map(|()| f())
213 }
214
215 #[inline]
216 fn map_or<T, F: FnOnce() -> T>(self, err: T, f: F) -> T { self.then(f).unwrap_or(err) }
217
218 #[inline]
219 fn map_or_else<T, E: FnOnce() -> T, F: FnOnce() -> T>(self, err: E, f: F) -> T {
220 self.then(f).unwrap_or_else(err)
221 }
222
223 #[inline]
224 fn ok_or<E>(self, err: E) -> Result<(), E> { self.into_option().ok_or(err) }
225
226 #[inline]
227 fn ok_or_else<E, F: FnOnce() -> E>(self, err: F) -> Result<(), E> {
228 self.into_option().ok_or_else(err)
229 }
230
231 #[inline]
232 fn or<T, F: FnOnce() -> T>(self, f: F) -> Option<T> { self.is_false().then(f) }
233
234 #[inline]
235 fn or_some<T>(self, t: T) -> Option<T> { self.is_false().then_some(t) }
236
237 #[inline]
238 fn then_async<O: Future, F: FnOnce() -> O>(self, f: F) -> OptionFuture<O> {
239 OptionFuture::<_>::from(self.then(f))
240 }
241
242 #[inline]
243 fn then_none<T>(self) -> Option<T> { Option::<T>::None }
244
245 #[inline]
246 fn then_ok_or<T, E>(self, t: T, e: E) -> Result<T, E> { self.map_ok_or(e, move || t) }
247
248 #[inline]
249 fn then_ok_or_else<T, E, F: FnOnce() -> E>(self, t: T, e: F) -> Result<T, E> {
250 self.ok_or_else(e).map(move |()| t)
251 }
252}