tuwunel_core/utils/future/
bool_ext.rs1#![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(()) }