Skip to main content

tuwunel_core/utils/future/
option_ext.rs

1#![expect(clippy::wrong_self_convention)]
2
3use futures::{FutureExt, future::OptionFuture};
4
5use super::super::BoolExt;
6
7/// Adds option-like combinators to futures with optional output.
8///
9/// Each adapter transforms the eventual `Option<T>` without requiring an
10/// intermediate await. Lazy fallbacks run only for absent output.
11pub trait OptionFutureExt<T> {
12	/// Tests whether the future yields no value or one matching `f`.
13	///
14	/// An absent output returns true without invoking the predicate. A present
15	/// value is borrowed for the predicate after the future resolves.
16	fn is_none_or(self, f: impl FnOnce(&T) -> bool + Send) -> impl Future<Output = bool> + Send;
17
18	/// Tests whether the future yields a value matching `f`.
19	///
20	/// An absent output returns false without invoking the predicate. A present
21	/// value is borrowed for the predicate after the future resolves.
22	fn is_some_and(self, f: impl FnOnce(&T) -> bool + Send) -> impl Future<Output = bool> + Send;
23
24	/// Returns the future's value or the supplied fallback.
25	///
26	/// The fallback is supplied eagerly and used only for absent output. A
27	/// present value passes through unchanged.
28	fn unwrap_or(self, t: T) -> impl Future<Output = T> + Send;
29
30	/// Returns the future's value or `T::default()`.
31	///
32	/// The default is constructed only after the future yields `None`. A
33	/// present value passes through unchanged.
34	fn unwrap_or_default(self) -> impl Future<Output = T> + Send
35	where
36		T: Default;
37
38	/// Returns the future's value or lazily computes a fallback.
39	///
40	/// The closure is called only after the future yields `None`. A present
41	/// value passes through without invoking it.
42	fn unwrap_or_else(self, f: impl FnOnce() -> T + Send) -> impl Future<Output = T> + Send;
43
44	/// Runs an asynchronous fallback only when the future yields `None`.
45	///
46	/// Absent output becomes `Some` of the fallback future's output. Present
47	/// output suppresses the fallback and becomes `None` rather than being
48	/// returned.
49	fn unwrap_or_else_async<F: Future<Output = T> + Send>(
50		self,
51		f: impl FnOnce() -> F + Send,
52	) -> impl Future<Output = Option<T>> + Send;
53}
54
55impl<T, Fut> OptionFutureExt<T> for OptionFuture<Fut>
56where
57	Fut: Future<Output = T> + Send,
58	T: Send,
59{
60	#[inline]
61	fn is_none_or(self, f: impl FnOnce(&T) -> bool + Send) -> impl Future<Output = bool> + Send {
62		self.map(|o| o.as_ref().is_none_or(f))
63	}
64
65	#[inline]
66	fn is_some_and(self, f: impl FnOnce(&T) -> bool + Send) -> impl Future<Output = bool> + Send {
67		self.map(|o| o.as_ref().is_some_and(f))
68	}
69
70	#[inline]
71	fn unwrap_or(self, t: T) -> impl Future<Output = T> + Send { self.map(|o| o.unwrap_or(t)) }
72
73	#[inline]
74	fn unwrap_or_default(self) -> impl Future<Output = T> + Send
75	where
76		T: Default,
77	{
78		self.map(Option::unwrap_or_default)
79	}
80
81	#[inline]
82	fn unwrap_or_else(self, f: impl FnOnce() -> T + Send) -> impl Future<Output = T> + Send {
83		self.map(|o| o.unwrap_or_else(f))
84	}
85
86	#[inline]
87	fn unwrap_or_else_async<F: Future<Output = T> + Send>(
88		self,
89		f: impl FnOnce() -> F + Send,
90	) -> impl Future<Output = Option<T>> + Send {
91		self.map(|o| o.is_none().then_async(f)).flatten()
92	}
93}