Skip to main content

tuwunel_core/utils/stream/
try_ready.rs

1//! Synchronous combinator extensions to futures::TryStream
2#![expect(clippy::type_complexity)]
3
4use futures::{
5	future::{Ready, ready},
6	stream::{
7		AndThen, TryFilter, TryFilterMap, TryFold, TryForEach, TrySkipWhile, TryStream,
8		TryStreamExt, TryTakeWhile,
9	},
10};
11
12use crate::Result;
13
14/// Adds synchronous combinators to fallible streams.
15///
16/// Closures run immediately when a successful item is polled, avoiding an async
17/// block around non-async work. Source errors retain the stream's error type.
18pub trait TryReadyExt<T, E, S>
19where
20	S: TryStream<Ok = T, Error = E, Item = Result<T, E>> + ?Sized,
21	Self: TryStream + Sized,
22{
23	/// Applies a synchronous fallible transform to successful items.
24	///
25	/// Existing source errors bypass `f`. Successful transformed values and
26	/// closure errors remain in source order.
27	fn ready_and_then<U, F>(
28		self,
29		f: F,
30	) -> AndThen<Self, Ready<Result<U, E>>, impl FnMut(S::Ok) -> Ready<Result<U, E>>>
31	where
32		F: Fn(S::Ok) -> Result<U, E>;
33
34	/// Retains successful items accepted by a synchronous predicate.
35	///
36	/// The predicate borrows only successful values. Source errors pass through
37	/// without invoking it.
38	fn ready_try_filter<F>(
39		self,
40		f: F,
41	) -> TryFilter<Self, Ready<bool>, impl FnMut(&S::Ok) -> Ready<bool>>
42	where
43		F: Fn(&S::Ok) -> bool;
44
45	/// Maps successful items through a synchronous fallible filter.
46	///
47	/// `Ok(Some(value))` yields a value and `Ok(None)` discards the item.
48	/// Source errors and closure errors remain in the result stream.
49	fn ready_try_filter_map<F, U>(
50		self,
51		f: F,
52	) -> TryFilterMap<
53		Self,
54		Ready<Result<Option<U>, E>>,
55		impl FnMut(S::Ok) -> Ready<Result<Option<U>, E>>,
56	>
57	where
58		F: Fn(S::Ok) -> Result<Option<U>, E>;
59
60	/// Folds successful items with a synchronous fallible accumulator.
61	///
62	/// Folding begins from `init` and processes values in source order. A
63	/// source or closure error ends the returned future with that error.
64	fn ready_try_fold<U, F>(
65		self,
66		init: U,
67		f: F,
68	) -> TryFold<Self, Ready<Result<U, E>>, U, impl FnMut(U, S::Ok) -> Ready<Result<U, E>>>
69	where
70		F: Fn(U, S::Ok) -> Result<U, E>;
71
72	/// Folds successful items from `U::default()` with a fallible accumulator.
73	///
74	/// Values are processed in source order. An empty stream returns the
75	/// default, while a source or closure error ends the fold.
76	fn ready_try_fold_default<U, F>(
77		self,
78		f: F,
79	) -> TryFold<Self, Ready<Result<U, E>>, U, impl FnMut(U, S::Ok) -> Ready<Result<U, E>>>
80	where
81		F: Fn(U, S::Ok) -> Result<U, E>,
82		U: Default;
83
84	/// Applies a synchronous fallible closure to each successful item.
85	///
86	/// Values are processed in source order. A source or closure error ends the
87	/// returned future before later items are visited.
88	fn ready_try_for_each<F>(
89		self,
90		f: F,
91	) -> TryForEach<Self, Ready<Result<(), E>>, impl FnMut(S::Ok) -> Ready<Result<(), E>>>
92	where
93		F: FnMut(S::Ok) -> Result<(), E>;
94
95	/// Skips leading successful items accepted by a fallible predicate.
96	///
97	/// The first false item and later items are yielded without further
98	/// predicate calls. Source and predicate errors remain in the result
99	/// stream.
100	fn ready_try_skip_while<F>(
101		self,
102		f: F,
103	) -> TrySkipWhile<Self, Ready<Result<bool, E>>, impl FnMut(&S::Ok) -> Ready<Result<bool, E>>>
104	where
105		F: Fn(&S::Ok) -> Result<bool, E>;
106
107	/// Yields leading successful items accepted by a fallible predicate.
108	///
109	/// The first false item ends the stream and is not yielded. Source and
110	/// predicate errors are yielded without terminating the adapter, and a
111	/// predicate error discards the tested item.
112	fn ready_try_take_while<F>(
113		self,
114		f: F,
115	) -> TryTakeWhile<Self, Ready<Result<bool, E>>, impl FnMut(&S::Ok) -> Ready<Result<bool, E>>>
116	where
117		F: Fn(&S::Ok) -> Result<bool, E>;
118}
119
120impl<T, E, S> TryReadyExt<T, E, S> for S
121where
122	S: TryStream<Ok = T, Error = E, Item = Result<T, E>> + ?Sized,
123	Self: TryStream + Sized,
124{
125	#[inline]
126	fn ready_and_then<U, F>(
127		self,
128		f: F,
129	) -> AndThen<Self, Ready<Result<U, E>>, impl FnMut(S::Ok) -> Ready<Result<U, E>>>
130	where
131		F: Fn(S::Ok) -> Result<U, E>,
132	{
133		self.and_then(move |t| ready(f(t)))
134	}
135
136	#[inline]
137	fn ready_try_filter<F>(
138		self,
139		f: F,
140	) -> TryFilter<Self, Ready<bool>, impl FnMut(&S::Ok) -> Ready<bool>>
141	where
142		F: Fn(&S::Ok) -> bool,
143	{
144		self.try_filter(move |t| ready(f(t)))
145	}
146
147	#[inline]
148	fn ready_try_filter_map<F, U>(
149		self,
150		f: F,
151	) -> TryFilterMap<
152		Self,
153		Ready<Result<Option<U>, E>>,
154		impl FnMut(S::Ok) -> Ready<Result<Option<U>, E>>,
155	>
156	where
157		F: Fn(S::Ok) -> Result<Option<U>, E>,
158	{
159		self.try_filter_map(move |t| ready(f(t)))
160	}
161
162	#[inline]
163	fn ready_try_fold<U, F>(
164		self,
165		init: U,
166		f: F,
167	) -> TryFold<Self, Ready<Result<U, E>>, U, impl FnMut(U, S::Ok) -> Ready<Result<U, E>>>
168	where
169		F: Fn(U, S::Ok) -> Result<U, E>,
170	{
171		self.try_fold(init, move |a, t| ready(f(a, t)))
172	}
173
174	#[inline]
175	fn ready_try_fold_default<U, F>(
176		self,
177		f: F,
178	) -> TryFold<Self, Ready<Result<U, E>>, U, impl FnMut(U, S::Ok) -> Ready<Result<U, E>>>
179	where
180		F: Fn(U, S::Ok) -> Result<U, E>,
181		U: Default,
182	{
183		self.ready_try_fold(U::default(), f)
184	}
185
186	#[inline]
187	fn ready_try_for_each<F>(
188		self,
189		mut f: F,
190	) -> TryForEach<Self, Ready<Result<(), E>>, impl FnMut(S::Ok) -> Ready<Result<(), E>>>
191	where
192		F: FnMut(S::Ok) -> Result<(), E>,
193	{
194		self.try_for_each(move |t| ready(f(t)))
195	}
196
197	#[inline]
198	fn ready_try_skip_while<F>(
199		self,
200		f: F,
201	) -> TrySkipWhile<Self, Ready<Result<bool, E>>, impl FnMut(&S::Ok) -> Ready<Result<bool, E>>>
202	where
203		F: Fn(&S::Ok) -> Result<bool, E>,
204	{
205		self.try_skip_while(move |t| ready(f(t)))
206	}
207
208	#[inline]
209	fn ready_try_take_while<F>(
210		self,
211		f: F,
212	) -> TryTakeWhile<Self, Ready<Result<bool, E>>, impl FnMut(&S::Ok) -> Ready<Result<bool, E>>>
213	where
214		F: Fn(&S::Ok) -> Result<bool, E>,
215	{
216		self.try_take_while(move |t| ready(f(t)))
217	}
218}