Skip to main content

tuwunel_core/utils/future/
option_ext.rs

1#![expect(clippy::wrong_self_convention)]
2
3use futures::{
4	FutureExt,
5	future::{OptionFuture, ready},
6};
7
8/// Adds option-like combinators to futures with optional output.
9///
10/// Each adapter transforms the eventual `Option<T>` without requiring an
11/// intermediate await. Lazy fallbacks run only for absent output.
12pub trait OptionFutureExt<T> {
13	/// Tests whether the future yields no value or one matching `f`.
14	///
15	/// An absent output returns true without invoking the predicate. A present
16	/// value is borrowed for the predicate after the future resolves.
17	fn is_none_or(self, f: impl FnOnce(&T) -> bool + Send) -> impl Future<Output = bool> + Send;
18
19	/// Tests whether the future yields a value matching `f`.
20	///
21	/// An absent output returns false without invoking the predicate. A present
22	/// value is borrowed for the predicate after the future resolves.
23	fn is_some_and(self, f: impl FnOnce(&T) -> bool + Send) -> impl Future<Output = bool> + Send;
24
25	/// Returns the future's value or the supplied fallback.
26	///
27	/// The fallback is supplied eagerly and used only for absent output. A
28	/// present value passes through unchanged.
29	fn unwrap_or(self, t: T) -> impl Future<Output = T> + Send;
30
31	/// Returns the future's value or `T::default()`.
32	///
33	/// The default is constructed only after the future yields `None`. A
34	/// present value passes through unchanged.
35	fn unwrap_or_default(self) -> impl Future<Output = T> + Send
36	where
37		T: Default;
38
39	/// Returns the future's value or lazily computes a fallback.
40	///
41	/// The closure is called only after the future yields `None`. A present
42	/// value passes through without invoking it.
43	fn unwrap_or_else(self, f: impl FnOnce() -> T + Send) -> impl Future<Output = T> + Send;
44
45	/// Returns the future's value or lazily awaits an asynchronous fallback.
46	///
47	/// The closure is called only after the future yields `None`. A present
48	/// value passes through without invoking it.
49	fn unwrap_or_else_async<F: Future<Output = T> + Send>(
50		self,
51		f: impl FnOnce() -> F + Send,
52	) -> impl Future<Output = 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 = T> + Send {
91		self.map(|o| o.map_or_else(|| f().right_future(), |t| ready(t).left_future()))
92			.flatten()
93	}
94}