async_selector/task/strategy.rs
1//! Set of strategies that provide blanket [`Task`] implementations
2//! for implementors of common traits: [`Future`], [`Stream`] and [`TryStream`].
3
4use std::{
5 convert::Infallible,
6 ops::ControlFlow,
7 pin::Pin,
8 task::{Context, Poll},
9};
10
11use futures::{Stream, TryStream};
12
13use crate::{
14 selector::{BorrowedMut, Id, Removed},
15 task::Task,
16};
17
18/// Yield future's output.
19///
20/// Enables [`Task`] implementation on any type that implements [`Future`].
21///
22/// The future will be polled until it resolves.
23/// After that, the [`Selector`](crate::Selector) will
24/// silently drop it and yield the output.
25///
26/// ```
27/// # use async_selector::{
28/// # selector::Selector,
29/// # task::strategy::FutureBasic,
30/// # };
31/// # use futures::StreamExt;
32/// # #[tokio::main]
33/// # async fn main() {
34/// let mut selector = (0..4)
35/// .map(std::future::ready)
36/// .collect::<Selector<_, FutureBasic>>();
37/// for i in 0..4 {
38/// let j: i32 = selector.next().await.unwrap();
39/// assert_eq!(j, i);
40/// }
41/// assert!(selector.is_empty());
42/// # }
43/// ```
44#[derive(Debug, Clone, Copy, Default)]
45pub struct FutureBasic;
46
47impl<F: Future> Task<FutureBasic> for F {
48 type Cont = Infallible;
49 type Break = F::Output;
50 type Output = F::Output;
51
52 fn poll_progress(
53 self: Pin<&mut Self>,
54 _: &mut FutureBasic,
55 cx: &mut Context<'_>,
56 ) -> Poll<ControlFlow<Self::Break, Self::Cont>> {
57 self.poll(cx).map(ControlFlow::Break)
58 }
59
60 fn transform_cont(
61 _: BorrowedMut<'_, Self>,
62 _: &mut FutureBasic,
63 _: Self::Cont,
64 ) -> Option<Self::Output> {
65 unreachable!("cannot construct std::convert::Infallible")
66 }
67
68 fn transform_break(
69 _: Removed<F>,
70 _: &mut FutureBasic,
71 value: Self::Break,
72 ) -> Option<Self::Output> {
73 Some(value)
74 }
75}
76
77/// Yield future's output and the future itself.
78///
79/// Enables [`Task`] implementation on any type that implements [`Future`].
80///
81/// The future will be polled until it resolves.
82/// After that, the [`Selector`](crate::Selector) will
83/// yield the output and the future itself.
84///
85/// ```
86/// # use async_selector::{
87/// # selector::{Removed, Selector},
88/// # task::strategy::FutureReclaim,
89/// # };
90/// # use futures::{future::{FusedFuture, Ready}, StreamExt};
91/// # #[tokio::main]
92/// # async fn main() {
93/// let mut selector = (0..4)
94/// .map(futures::future::ready)
95/// .collect::<Selector<_, FutureReclaim>>();
96/// for i in 0..4 {
97/// let item: (Removed<Ready<i32>>, i32) = selector.next().await.unwrap();
98/// assert!(item.0.is_terminated());
99/// assert_eq!(item.1, i);
100/// }
101/// assert!(selector.is_empty());
102/// # }
103/// ```
104#[derive(Debug, Clone, Copy, Default)]
105pub struct FutureReclaim;
106
107impl<F: Future> Task<FutureReclaim> for F {
108 type Cont = Infallible;
109 type Break = F::Output;
110 type Output = (Removed<F>, F::Output);
111
112 fn poll_progress(
113 self: Pin<&mut Self>,
114 _: &mut FutureReclaim,
115 cx: &mut Context<'_>,
116 ) -> Poll<ControlFlow<Self::Break, Self::Cont>> {
117 self.poll(cx).map(ControlFlow::Break)
118 }
119
120 fn transform_cont(
121 _: BorrowedMut<'_, F>,
122 _: &mut FutureReclaim,
123 _: Self::Cont,
124 ) -> Option<Self::Output> {
125 unreachable!("cannot construct std::convert::Infallible")
126 }
127
128 fn transform_break(
129 task: Removed<F>,
130 _: &mut FutureReclaim,
131 value: Self::Break,
132 ) -> Option<Self::Output> {
133 Some((task, value))
134 }
135}
136
137/// Yield stream's items.
138///
139/// Enables [`Task`] implementation on any type that implements [`Stream`].
140///
141/// The stream will be polled for items until it is exhausted.
142/// [`Selector`](crate::Selector) will yield all items.
143/// After that, the [`Selector`](crate::Selector) will silently drop the stream.
144///
145/// ```
146/// # use async_selector::{
147/// # selector::Selector,
148/// # task::strategy::StreamBasic,
149/// # };
150/// # use futures::StreamExt;
151/// # #[tokio::main]
152/// # async fn main() {
153/// let mut selector = (0..4)
154/// .map(|i| futures::stream::repeat(i).take(2))
155/// .collect::<Selector<_, StreamBasic>>();
156/// for i in 0..8 {
157/// let j: i32 = selector.next().await.unwrap();
158/// assert_eq!(j, i % 4);
159/// }
160/// assert!(selector.next().await.is_none());
161/// assert!(selector.is_empty());
162/// # }
163/// ```
164#[derive(Debug, Clone, Copy, Default)]
165pub struct StreamBasic;
166
167impl<S: Stream> Task<StreamBasic> for S {
168 type Cont = S::Item;
169 type Break = ();
170 type Output = S::Item;
171
172 fn poll_progress(
173 self: Pin<&mut Self>,
174 _: &mut StreamBasic,
175 cx: &mut Context<'_>,
176 ) -> Poll<ControlFlow<Self::Break, Self::Cont>> {
177 match std::task::ready!(self.poll_next(cx)) {
178 Some(item) => Poll::Ready(ControlFlow::Continue(item)),
179 None => Poll::Ready(ControlFlow::Break(())),
180 }
181 }
182
183 fn transform_cont(
184 _: BorrowedMut<'_, Self>,
185 _: &mut StreamBasic,
186 value: Self::Cont,
187 ) -> Option<Self::Output> {
188 Some(value)
189 }
190
191 fn transform_break(
192 _: Removed<Self>,
193 _: &mut StreamBasic,
194 _: Self::Break,
195 ) -> Option<Self::Output> {
196 None
197 }
198}
199
200/// Yield stream's items annotated with stream [`Id`].
201///
202/// Enables [`Task`] implementation on any type that implements [`Stream`].
203///
204/// The stream will be polled for items until it is exhausted.
205/// [`Selector`](crate::Selector) will yield all items, attaching stream's task [`Id`] to each.
206/// After that, the [`Selector`](crate::Selector) will silently drop the stream.
207///
208/// ```
209/// # use async_selector::{
210/// # selector::{Id, Selector},
211/// # task::strategy::StreamWithId,
212/// # };
213/// # use futures::{channel::mpsc, StreamExt};
214/// # #[tokio::main]
215/// # async fn main() {
216/// let (tx, rx) = mpsc::unbounded::<i32>();
217/// let mut selector = Selector::<_, StreamWithId>::default();
218/// let id = selector.push(rx).id().clone();
219/// tx.unbounded_send(1).unwrap();
220/// let item: (Id<_>, i32) = selector.next().await.unwrap();
221/// assert_eq!(item.0, id);
222/// assert_eq!(item.1, 1);
223/// drop(tx);
224/// assert!(selector.next().await.is_none());
225/// assert!(selector.is_empty());
226/// # }
227/// ```
228#[derive(Debug, Clone, Copy, Default)]
229pub struct StreamWithId;
230
231impl<S: Stream> Task<StreamWithId> for S {
232 type Cont = S::Item;
233 type Break = ();
234 type Output = (Id<S>, S::Item);
235
236 fn poll_progress(
237 self: Pin<&mut Self>,
238 _: &mut StreamWithId,
239 cx: &mut Context<'_>,
240 ) -> Poll<ControlFlow<Self::Break, Self::Cont>> {
241 match std::task::ready!(self.poll_next(cx)) {
242 Some(item) => Poll::Ready(ControlFlow::Continue(item)),
243 None => Poll::Ready(ControlFlow::Break(())),
244 }
245 }
246
247 fn transform_cont(
248 task: BorrowedMut<'_, Self>,
249 _: &mut StreamWithId,
250 value: Self::Cont,
251 ) -> Option<Self::Output> {
252 Some((task.id().clone(), value))
253 }
254
255 fn transform_break(
256 _: Removed<Self>,
257 _: &mut StreamWithId,
258 _: Self::Break,
259 ) -> Option<Self::Output> {
260 None
261 }
262}
263
264/// Yield stream's items annotated with stream [`Id`], and the exhausted stream itself.
265///
266/// Enables [`Task`] implementation on any type that implements [`Stream`].
267///
268/// The stream will be polled for items until it is exhausted.
269/// [`Selector`](crate::Selector) will yield all items, attaching stream's task [`Id`] to each.
270/// After that, the [`Selector`](crate::Selector) will yield the exhausted stream.
271///
272/// ```
273/// # use async_selector::{
274/// # selector::{Id, Removed, Selector},
275/// # task::strategy::StreamReclaim,
276/// # };
277/// # use futures::{channel::mpsc, StreamExt};
278/// # use std::ops::ControlFlow;
279/// # #[tokio::main]
280/// # async fn main() {
281/// let (tx, rx) = mpsc::unbounded::<i32>();
282/// let mut selector = Selector::<_, StreamReclaim>::default();
283/// let id = selector.push(rx).id().clone();
284/// tx.unbounded_send(1).unwrap();
285/// match selector.next().await.unwrap() {
286/// ControlFlow::Continue(item) => {
287/// assert_eq!(item.0, id);
288/// assert_eq!(item.1, 1);
289/// }
290/// ControlFlow::Break(..) => unreachable!("channel is still open"),
291/// }
292/// drop(tx);
293/// match selector.next().await.unwrap() {
294/// ControlFlow::Continue(..) => {
295/// unreachable!("channel was closed");
296/// }
297/// ControlFlow::Break((item)) => {
298/// let rx: mpsc::UnboundedReceiver<i32> = item.into_inner();
299/// }
300/// }
301/// assert!(selector.is_empty());
302/// # }
303/// ```
304#[derive(Debug, Clone, Copy, Default)]
305pub struct StreamReclaim;
306
307impl<S: Stream> Task<StreamReclaim> for S {
308 type Cont = S::Item;
309 type Break = ();
310 type Output = ControlFlow<Removed<S>, (Id<S>, S::Item)>;
311
312 fn poll_progress(
313 self: Pin<&mut Self>,
314 _: &mut StreamReclaim,
315 cx: &mut Context<'_>,
316 ) -> Poll<ControlFlow<Self::Break, Self::Cont>> {
317 match std::task::ready!(self.poll_next(cx)) {
318 Some(item) => Poll::Ready(ControlFlow::Continue(item)),
319 None => Poll::Ready(ControlFlow::Break(())),
320 }
321 }
322
323 fn transform_cont(
324 task: BorrowedMut<'_, Self>,
325 _: &mut StreamReclaim,
326 value: Self::Cont,
327 ) -> Option<Self::Output> {
328 Some(ControlFlow::Continue((task.id().clone(), value)))
329 }
330
331 fn transform_break(
332 task: Removed<Self>,
333 _: &mut StreamReclaim,
334 _: Self::Break,
335 ) -> Option<Self::Output> {
336 Some(ControlFlow::Break(task))
337 }
338}
339
340/// Yield stream's items (stopping after first error).
341///
342/// Enables [`Task`] implementation on any type that implements [`TryStream`].
343///
344/// The stream will be polled for items until it is exhausted or yields an error.
345/// [`Selector`](crate::Selector) will yield all items and the first error.
346/// After that, the [`Selector`](crate::Selector) will silently drop the stream.
347///
348/// ```
349/// # use async_selector::{
350/// # selector::Selector,
351/// # task::strategy::TryStreamBasic,
352/// # };
353/// # use futures::{channel::mpsc, StreamExt};
354/// # #[tokio::main]
355/// # async fn main() {
356/// let (tx_1, rx_1) = mpsc::unbounded::<Result<i32, &'static str>>();
357/// let (tx_2, rx_2) = mpsc::unbounded::<Result<i32, &'static str>>();
358/// let mut selector = [rx_1, rx_2].into_iter().collect::<Selector::<_, TryStreamBasic>>();
359/// tx_1.unbounded_send(Err("error")).unwrap();
360/// assert_eq!(
361/// selector.next().await.unwrap(),
362/// Err("error"),
363/// );
364/// tx_2.unbounded_send(Ok(1)).unwrap();
365/// assert_eq!(
366/// selector.next().await.unwrap(),
367/// Ok(1),
368/// );
369/// drop(tx_2);
370/// assert!(selector.next().await.is_none());
371/// assert!(selector.is_empty());
372/// # }
373/// ```
374#[derive(Debug, Clone, Copy, Default)]
375pub struct TryStreamBasic;
376
377impl<S: TryStream> Task<TryStreamBasic> for S {
378 type Cont = S::Ok;
379 type Break = Result<(), S::Error>;
380 type Output = Result<S::Ok, S::Error>;
381
382 fn poll_progress(
383 self: Pin<&mut Self>,
384 _: &mut TryStreamBasic,
385 cx: &mut Context<'_>,
386 ) -> Poll<ControlFlow<Self::Break, Self::Cont>> {
387 match std::task::ready!(self.try_poll_next(cx)) {
388 Some(Ok(item)) => Poll::Ready(ControlFlow::Continue(item)),
389 Some(Err(error)) => Poll::Ready(ControlFlow::Break(Err(error))),
390 None => Poll::Ready(ControlFlow::Break(Ok(()))),
391 }
392 }
393
394 fn transform_cont(
395 _: BorrowedMut<'_, Self>,
396 _: &mut TryStreamBasic,
397 value: Self::Cont,
398 ) -> Option<Self::Output> {
399 Some(Ok(value))
400 }
401
402 fn transform_break(
403 _: Removed<Self>,
404 _: &mut TryStreamBasic,
405 value: Self::Break,
406 ) -> Option<Self::Output> {
407 value.err().map(Err)
408 }
409}
410
411/// Yield stream's items annotated with stream [`Id`] (stopping after first error).
412///
413/// Enables [`Task`] implementation on any type that implements [`TryStream`].
414///
415/// The stream will be polled for items until it is exhausted or yields an error.
416/// [`Selector`](crate::Selector) will yield all items and the first error,
417/// attaching stream's task [`Id`] to each.
418/// After that, the [`Selector`](crate::Selector) will silently drop the stream.
419///
420/// ```
421/// # use async_selector::{
422/// # selector::{Id, Selector},
423/// # task::strategy::TryStreamWithId,
424/// # };
425/// # use futures::{channel::mpsc, StreamExt};
426/// # #[tokio::main]
427/// # async fn main() {
428/// let (tx_1, rx_1) = mpsc::unbounded::<Result<i32, &'static str>>();
429/// let (tx_2, rx_2) = mpsc::unbounded::<Result<i32, &'static str>>();
430/// let mut selector = Selector::<_, TryStreamWithId>::default();
431/// let id_1 = selector.push(rx_1).id().clone();
432/// let id_2 = selector.push(rx_2).id().clone();
433/// tx_1.unbounded_send(Err("error")).unwrap();
434/// assert_eq!(
435/// selector.next().await.unwrap(),
436/// (id_1, Err("error")),
437/// );
438/// tx_2.unbounded_send(Ok(1)).unwrap();
439/// assert_eq!(
440/// selector.next().await.unwrap(),
441/// (id_2, Ok(1)),
442/// );
443/// drop(tx_2);
444/// assert!(selector.next().await.is_none());
445/// assert!(selector.is_empty());
446/// # }
447/// ```
448#[derive(Debug, Clone, Copy, Default)]
449pub struct TryStreamWithId;
450
451impl<S: TryStream> Task<TryStreamWithId> for S {
452 type Cont = S::Ok;
453 type Break = Result<(), S::Error>;
454 type Output = (Id<S>, Result<S::Ok, S::Error>);
455
456 fn poll_progress(
457 self: Pin<&mut Self>,
458 _: &mut TryStreamWithId,
459 cx: &mut Context<'_>,
460 ) -> Poll<ControlFlow<Self::Break, Self::Cont>> {
461 match std::task::ready!(self.try_poll_next(cx)) {
462 Some(Ok(item)) => Poll::Ready(ControlFlow::Continue(item)),
463 Some(Err(error)) => Poll::Ready(ControlFlow::Break(Err(error))),
464 None => Poll::Ready(ControlFlow::Break(Ok(()))),
465 }
466 }
467
468 fn transform_cont(
469 task: BorrowedMut<'_, Self>,
470 _: &mut TryStreamWithId,
471 value: Self::Cont,
472 ) -> Option<Self::Output> {
473 Some((task.id().clone(), Ok(value)))
474 }
475
476 fn transform_break(
477 task: Removed<Self>,
478 _: &mut TryStreamWithId,
479 value: Self::Break,
480 ) -> Option<Self::Output> {
481 match value {
482 Ok(()) => None,
483 Err(error) => Some((task.id().clone(), Err(error))),
484 }
485 }
486}
487
488/// Yield stream's items annotated with stream [`Id`] (stopping after first error),
489/// and the exhausted/failed stream itself.
490///
491/// Enables [`Task`] implementation on any type that implements [`TryStream`].
492///
493/// The stream will be polled for items until it is exhausted or yields an error.
494/// [`Selector`](crate::Selector) will yield all items and the first error,
495/// attaching stream's task [`Id`] to each.
496/// After that, the [`Selector`](crate::Selector) will yield the exhausted/failed stream.
497///
498/// ```
499/// # use async_selector::{
500/// # selector::{Id, Removed, Selector},
501/// # task::strategy::TryStreamReclaim,
502/// # };
503/// # use futures::{channel::mpsc, StreamExt};
504/// # #[tokio::main]
505/// # async fn main() {
506/// let (tx_1, rx_1) = mpsc::unbounded::<Result<i32, &'static str>>();
507/// let (tx_2, rx_2) = mpsc::unbounded::<Result<i32, &'static str>>();
508/// let mut selector = Selector::<_, TryStreamReclaim>::default();
509/// let id_1 = selector.push(rx_1).id().clone();
510/// let id_2 = selector.push(rx_2).id().clone();
511/// tx_1.unbounded_send(Err("error")).unwrap();
512/// let item: (Removed<_>, Result<_, _>) = selector
513/// .next()
514/// .await
515/// .unwrap()
516/// .break_value()
517/// .unwrap();
518/// assert_eq!(item.0.id(), &id_1);
519/// assert_eq!(
520/// item.1,
521/// Err("error"),
522/// );
523/// tx_2.unbounded_send(Ok(1)).unwrap();
524/// let item: (Id<_>, i32) = selector
525/// .next()
526/// .await
527/// .unwrap()
528/// .continue_value()
529/// .unwrap();
530/// assert_eq!(item.0, id_2);
531/// assert_eq!(item.1, 1);
532/// drop(tx_2);
533/// let item: (Removed<_>, Result<_, _>) = selector
534/// .next()
535/// .await
536/// .unwrap()
537/// .break_value()
538/// .unwrap();
539/// assert_eq!(item.0.id(), &id_2);
540/// assert_eq!(item.1, Ok(()));
541/// assert!(selector.is_empty());
542/// # }
543/// ```
544#[derive(Debug, Clone, Copy, Default)]
545pub struct TryStreamReclaim;
546
547impl<S: TryStream> Task<TryStreamReclaim> for S {
548 type Cont = S::Ok;
549 type Break = Result<(), S::Error>;
550 type Output = ControlFlow<(Removed<S>, Result<(), S::Error>), (Id<S>, S::Ok)>;
551
552 fn poll_progress(
553 self: Pin<&mut Self>,
554 _: &mut TryStreamReclaim,
555 cx: &mut Context<'_>,
556 ) -> Poll<ControlFlow<Self::Break, Self::Cont>> {
557 match std::task::ready!(self.try_poll_next(cx)) {
558 Some(Ok(item)) => Poll::Ready(ControlFlow::Continue(item)),
559 Some(Err(error)) => Poll::Ready(ControlFlow::Break(Err(error))),
560 None => Poll::Ready(ControlFlow::Break(Ok(()))),
561 }
562 }
563
564 fn transform_cont(
565 task: BorrowedMut<'_, Self>,
566 _: &mut TryStreamReclaim,
567 value: Self::Cont,
568 ) -> Option<Self::Output> {
569 Some(ControlFlow::Continue((task.id().clone(), value)))
570 }
571
572 fn transform_break(
573 task: Removed<Self>,
574 _: &mut TryStreamReclaim,
575 value: Self::Break,
576 ) -> Option<Self::Output> {
577 Some(ControlFlow::Break((task, value)))
578 }
579}