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}