Skip to main content

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}