Skip to main content

tuwunel_core/utils/future/
bool_ext.rs

1//! Extended external extensions to futures::FutureExt
2#![expect(clippy::many_single_char_names, clippy::impl_trait_in_params)]
3
4use std::marker::Unpin;
5
6use futures::{
7	Future, FutureExt,
8	future::{
9		Either::{Left, Right},
10		select_ok, try_join, try_join_all, try_join3, try_join4,
11	},
12};
13
14use crate::utils::BoolExt as _;
15
16pub trait BoolExt
17where
18	Self: Future<Output = bool> + Send,
19{
20	fn or<B>(self, b: B) -> impl Future<Output = bool> + Send
21	where
22		B: Future<Output = bool> + Send + Unpin,
23		Self: Sized + Unpin;
24
25	fn and<B>(self, b: B) -> impl Future<Output = bool> + Send
26	where
27		B: Future<Output = bool> + Send,
28		Self: Sized;
29
30	fn and2<B, C>(self, b: B, c: C) -> impl Future<Output = bool> + Send
31	where
32		B: Future<Output = bool> + Send,
33		C: Future<Output = bool> + Send,
34		Self: Sized;
35
36	fn and3<B, C, D>(self, b: B, c: C, d: D) -> impl Future<Output = bool> + Send
37	where
38		B: Future<Output = bool> + Send,
39		C: Future<Output = bool> + Send,
40		D: Future<Output = bool> + Send,
41		Self: Sized;
42}
43
44impl<Fut> BoolExt for Fut
45where
46	Fut: Future<Output = bool> + Send,
47{
48	fn or<B>(self, b: B) -> impl Future<Output = bool> + Send
49	where
50		B: Future<Output = bool> + Send + Unpin,
51		Self: Sized + Unpin,
52	{
53		select_ok([Left(self.map(test)), Right(b.map(test))]).map(|res| res.is_ok())
54	}
55
56	fn and<B>(self, b: B) -> impl Future<Output = bool> + Send
57	where
58		B: Future<Output = bool> + Send,
59		Self: Sized,
60	{
61		try_join(self.map(test), b.map(test)).map(|res| res.is_ok())
62	}
63
64	fn and2<B, C>(self, b: B, c: C) -> impl Future<Output = bool> + Send
65	where
66		B: Future<Output = bool> + Send,
67		C: Future<Output = bool> + Send,
68		Self: Sized,
69	{
70		try_join3(self.map(test), b.map(test), c.map(test)).map(|res| res.is_ok())
71	}
72
73	fn and3<B, C, D>(self, b: B, c: C, d: D) -> impl Future<Output = bool> + Send
74	where
75		B: Future<Output = bool> + Send,
76		C: Future<Output = bool> + Send,
77		D: Future<Output = bool> + Send,
78		Self: Sized,
79	{
80		try_join4(self.map(test), b.map(test), c.map(test), d.map(test)).map(|res| res.is_ok())
81	}
82}
83
84pub fn and<I, F>(args: I) -> impl Future<Output = bool> + Send
85where
86	I: Iterator<Item = F> + Send,
87	F: Future<Output = bool> + Send,
88{
89	let args = args.map(|a| a.map(test));
90
91	try_join_all(args).map(|res| res.is_ok())
92}
93
94pub fn or<I, F>(args: I) -> impl Future<Output = bool> + Send
95where
96	I: Iterator<Item = F> + Send,
97	F: Future<Output = bool> + Send + Unpin,
98{
99	let args = args.map(|a| a.map(test));
100
101	select_ok(args).map(|res| res.is_ok())
102}
103
104pub fn and4(
105	a: impl Future<Output = bool> + Send,
106	b: impl Future<Output = bool> + Send,
107	c: impl Future<Output = bool> + Send,
108	d: impl Future<Output = bool> + Send,
109) -> impl Future<Output = bool> + Send {
110	a.and3(b, c, d)
111}
112
113pub fn and5(
114	a: impl Future<Output = bool> + Send,
115	b: impl Future<Output = bool> + Send,
116	c: impl Future<Output = bool> + Send,
117	d: impl Future<Output = bool> + Send,
118	e: impl Future<Output = bool> + Send,
119) -> impl Future<Output = bool> + Send {
120	a.and2(b, c).and2(d, e)
121}
122
123pub fn and6(
124	a: impl Future<Output = bool> + Send,
125	b: impl Future<Output = bool> + Send,
126	c: impl Future<Output = bool> + Send,
127	d: impl Future<Output = bool> + Send,
128	e: impl Future<Output = bool> + Send,
129	f: impl Future<Output = bool> + Send,
130) -> impl Future<Output = bool> + Send {
131	a.and3(b, c, d).and2(e, f)
132}
133
134pub fn and7(
135	a: impl Future<Output = bool> + Send,
136	b: impl Future<Output = bool> + Send,
137	c: impl Future<Output = bool> + Send,
138	d: impl Future<Output = bool> + Send,
139	e: impl Future<Output = bool> + Send,
140	f: impl Future<Output = bool> + Send,
141	g: impl Future<Output = bool> + Send,
142) -> impl Future<Output = bool> + Send {
143	a.and3(b, c, d).and3(e, f, g)
144}
145
146fn test(test: bool) -> crate::Result<(), ()> { test.ok_or(()) }