Skip to main content

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}