Skip to main content

async_selector/
task.rs

1use std::{
2    ops::ControlFlow,
3    pin::Pin,
4    task::{Context, Poll},
5};
6
7use crate::selector::{BorrowedMut, Removed};
8
9pub mod strategy;
10
11/// Asynchronous task that can be polled with strategy `S`.
12///
13/// Strategy parameter allows for:
14/// 1. Convenient blanket implementations on external types ([`Future`]s and [`Stream`](futures::Stream)s)
15/// 2. Multiple implementations on a single type
16/// 3. Exposing shared data to the task
17///
18/// Unless you want to customize [`Selector`](crate::Selector)'s behavior,
19/// you don't have to manually implement this trait.
20/// You can use one of ready-to-go strategies from [`strategy`].
21///
22/// # Custom task example
23///
24/// The example below polls a set of [`UdpSocket`](https://docs.rs/tokio/latest/tokio/net/struct.UdpSocket.html)s
25/// for incoming datagrams.
26///
27/// Note that:
28/// 1. [`UdpSocket`](https://docs.rs/tokio/latest/tokio/net/struct.UdpSocket.html) is an external type,
29///    and so is this trait (from the perspective of the implementing crate).
30///    The local strategy type makes the implementation possible.
31/// 2. The strategy holds the receive buffer, so the whole selector needs only one,
32///    no matter how many sockets it holds. Each datagram is copied out of the shared buffer
33///    in [`Task::transform_cont`], before the next poll can overwrite it.
34/// 3. A failed socket is removed from the selector, because the failure is reported
35///    with [`ControlFlow::Break`].
36///
37/// ```
38/// # use std::{
39/// #     io,
40/// #     mem::MaybeUninit,
41/// #     net::SocketAddr,
42/// #     ops::ControlFlow,
43/// #     pin::Pin,
44/// #     task::{Context, Poll, ready},
45/// # };
46/// # use async_selector::{
47/// #     selector::{BorrowedMut, Removed, Selector},
48/// #     task::Task,
49/// # };
50/// # use futures::StreamExt;
51/// # use tokio::{io::ReadBuf, net::UdpSocket};
52/// /// Receive buffer shared by all sockets in the selector.
53/// ///
54/// /// Large enough to hold any datagram.
55/// struct RecvBuffer(Box<[MaybeUninit<u8>; u16::MAX as usize]>);
56///
57/// impl Task<RecvBuffer> for UdpSocket {
58///     /// Address of the peer and length of the datagram,
59///     /// which sits in the shared buffer.
60///     type Cont = (SocketAddr, Vec<u8>);
61///     /// Fatal socket error.
62///     type Break = io::Error;
63///     type Output = io::Result<(SocketAddr, Vec<u8>)>;
64///
65///     fn poll_progress(
66///         self: Pin<&mut Self>,
67///         buffer: &mut RecvBuffer,
68///         cx: &mut Context<'_>,
69///     ) -> Poll<ControlFlow<Self::Break, Self::Cont>> {
70///         let mut buf = ReadBuf::uninit(buffer.0.as_mut_slice());
71///         match ready!(self.poll_recv_from(cx, &mut buf)) {
72///             Ok(peer) => Poll::Ready(ControlFlow::Continue((peer, buf.filled().to_vec()))),
73///             Err(error) => Poll::Ready(ControlFlow::Break(error)),
74///         }
75///     }
76///
77///     fn transform_cont(
78///         _: BorrowedMut<'_, Self>,
79///         buffer: &mut RecvBuffer,
80///         value: Self::Cont,
81///     ) -> Option<Self::Output> {
82///         Some(Ok(value))
83///     }
84///
85///     fn transform_break(
86///         _: Removed<Self>,
87///         _: &mut RecvBuffer,
88///         error: Self::Break,
89///     ) -> Option<Self::Output> {
90///         Some(Err(error))
91///     }
92/// }
93///
94/// # #[tokio::main(flavor = "current_thread")]
95/// # async fn main() -> io::Result<()> {
96/// let mut selector = Selector::new(RecvBuffer(Box::new([MaybeUninit::uninit(); u16::MAX as usize])));
97/// let mut addrs = Vec::new();
98/// for _ in 0..2 {
99///     let socket = UdpSocket::bind("127.0.0.1:0").await?;
100///     addrs.push(socket.local_addr()?);
101///     selector.push(socket);
102/// }
103///
104/// let sender = UdpSocket::bind("127.0.0.1:0").await?;
105/// for addr in &addrs {
106///     sender.send_to(b"hello", addr).await?;
107///     let (peer, data) = selector.next().await.unwrap()?;
108///     assert_eq!(peer, sender.local_addr()?);
109///     assert_eq!(data, b"hello");
110/// }
111/// # Ok(())
112/// # }
113/// ```
114pub trait Task<S: ?Sized = ()>: Sized {
115    /// Type returned from [`Self::poll_progress`]
116    /// when the task produces some value, but has not finished yet.
117    type Cont;
118    /// Type returned from [`Self::poll_progress`]
119    /// when the task produces its last value.
120    type Break;
121    /// Final value type, produced from [`Self::Cont`]/[`Self::Break`]
122    /// in [`Self::transform_cont`]/[`Self::transform_break`].
123    type Output;
124
125    /// Polls progress on this task using the given strategy.
126    ///
127    /// # Returns
128    ///
129    /// * [`ControlFlow::Break`], if task has finished,
130    ///   and **should not** be polled again.
131    /// * [`ControlFlow::Continue`], if the task has produced a value,
132    ///   but has not finished yet and **can** be polled again.
133    fn poll_progress(
134        self: Pin<&mut Self>,
135        strategy: &mut S,
136        cx: &mut Context<'_>,
137    ) -> Poll<ControlFlow<Self::Break, Self::Cont>>;
138
139    /// Transforms [`Self::Cont`] value obtained from [`Self::poll_progress`]
140    /// into the final value type [`Self::Output`].
141    ///
142    /// This is the place to:
143    /// 1. Enrich the value with some properties of the task, passed as [`BorrowedMut`]
144    /// 2. Silently ignore the value by returning [`None`]
145    fn transform_cont(
146        task: BorrowedMut<'_, Self>,
147        strategy: &mut S,
148        value: Self::Cont,
149    ) -> Option<Self::Output>;
150
151    /// Transforms [`Self::Break`] value obtained from [`Self::poll_progress`]
152    /// into the final value type [`Self::Output`].
153    ///
154    /// This is the place to:
155    /// 1. Enrich the value with some properties of the task, passed as [`Removed`]
156    /// 2. Silently ignore the value by returning [`None`]
157    fn transform_break(
158        task: Removed<Self>,
159        strategy: &mut S,
160        value: Self::Break,
161    ) -> Option<Self::Output>;
162}
163
164impl<S, T> Task<&mut S> for T
165where
166    S: ?Sized,
167    T: Task<S>,
168{
169    type Cont = <Self as Task<S>>::Cont;
170    type Break = <Self as Task<S>>::Break;
171    type Output = <Self as Task<S>>::Output;
172
173    fn poll_progress(
174        self: Pin<&mut Self>,
175        strategy: &mut &mut S,
176        cx: &mut Context<'_>,
177    ) -> Poll<ControlFlow<Self::Break, Self::Cont>> {
178        self.poll_progress(&mut **strategy, cx)
179    }
180
181    fn transform_cont(
182        task: BorrowedMut<'_, Self>,
183        strategy: &mut &mut S,
184        value: Self::Cont,
185    ) -> Option<Self::Output> {
186        Self::transform_cont(task, &mut **strategy, value)
187    }
188
189    fn transform_break(
190        task: Removed<Self>,
191        strategy: &mut &mut S,
192        value: Self::Break,
193    ) -> Option<Self::Output> {
194        Self::transform_break(task, &mut **strategy, value)
195    }
196}
197
198impl<S, T> Task<Box<S>> for T
199where
200    S: ?Sized,
201    T: Task<S>,
202{
203    type Cont = <Self as Task<S>>::Cont;
204    type Break = <Self as Task<S>>::Break;
205    type Output = <Self as Task<S>>::Output;
206
207    fn poll_progress(
208        self: Pin<&mut Self>,
209        strategy: &mut Box<S>,
210        cx: &mut Context<'_>,
211    ) -> Poll<ControlFlow<Self::Break, Self::Cont>> {
212        self.poll_progress(strategy.as_mut(), cx)
213    }
214
215    fn transform_cont(
216        task: BorrowedMut<'_, Self>,
217        strategy: &mut Box<S>,
218        value: Self::Cont,
219    ) -> Option<Self::Output> {
220        Self::transform_cont(task, strategy.as_mut(), value)
221    }
222
223    fn transform_break(
224        task: Removed<Self>,
225        strategy: &mut Box<S>,
226        value: Self::Break,
227    ) -> Option<Self::Output> {
228        Self::transform_break(task, strategy.as_mut(), value)
229    }
230}