Skip to main content

async_rs/implementors/
noop.rs

1//! noop implementation of async runtime definition traits
2
3use crate::{
4    Runtime,
5    sys::AsSysFd,
6    traits::{Executor, Reactor, RuntimeKit},
7    util::{self, DummyIO, DummyStream, Task},
8};
9use futures_core::Stream;
10use futures_io::{AsyncRead, AsyncWrite};
11use std::{
12    future::{self, Future, Ready},
13    io::{self, Read, Write},
14    marker::PhantomData,
15    net::SocketAddr,
16    time::{Duration, Instant},
17};
18
19use task::NTask;
20
21/// Type alias for the noop runtime
22pub type NoopRuntime = Runtime<Noop>;
23
24impl NoopRuntime {
25    /// Create a new NoopRuntime
26    #[must_use]
27    pub fn noop() -> Self {
28        Self::new(Noop)
29    }
30}
31
32/// A no-op [`RuntimeKit`] implementation that never actually executes tasks or I/O
33///
34/// `spawn` and `spawn_blocking` drop the work they are handed and return a task which never
35/// completes, so anything built on them never resolves either: awaiting the result of
36/// [`Runtime::to_socket_addrs`](crate::Runtime::to_socket_addrs) on a `NoopRuntime` waits forever,
37/// and parked rather than spinning, since that is what
38/// [`simple_block_on`](crate::util::simple_block_on) does with a future which never wakes.
39///
40/// The [`Reactor`] side resolves under any executor, not just [`Executor::block_on`], but only as
41/// far as handing something back: `sleep` completes immediately, and `tcp_connect_addr` hands over
42/// a [`DummyIO`](crate::util::DummyIO) without having connected to anything. Using it is where the
43/// waiting starts again — every read, write, flush and close on a `DummyIO`, and every item of the
44/// stream `interval` returns, is `Poll::Pending` forever, and no waker is ever registered, so the
45/// executor cannot even be woken to cancel the task waiting on one.
46///
47/// `register` is the one to watch: it takes the socket by value and drops it, closing the
48/// descriptor, and hands back a `DummyIO` in its place. Dropping a `NoopRuntime` into a test
49/// harness therefore loses the socket, silently.
50#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
51pub struct Noop;
52
53impl RuntimeKit for Noop {}
54
55impl Executor for Noop {
56    type Task<T: Send + 'static> = NTask<T>;
57
58    fn block_on<T, F: Future<Output = T>>(&self, f: F) -> T {
59        // We cannot fake something unless we require T: Default, which we don't want.
60        // Let's get a minimalist implementation for this one.
61        util::simple_block_on(f)
62    }
63
64    fn spawn<T: Send + 'static, F: Future<Output = T> + Send + 'static>(
65        &self,
66        _f: F,
67    ) -> Task<Self::Task<T>> {
68        NTask(PhantomData).into()
69    }
70
71    fn spawn_blocking<T: Send + 'static, F: FnOnce() -> T + Send + 'static>(
72        &self,
73        _f: F,
74    ) -> Task<Self::Task<T>> {
75        NTask(PhantomData).into()
76    }
77}
78
79impl Reactor for Noop {
80    type TcpStream = DummyIO;
81    type Sleep = Ready<()>;
82
83    fn register<H: Read + Write + AsSysFd + Send + 'static>(
84        &self,
85        _socket: H,
86    ) -> io::Result<impl AsyncRead + AsyncWrite + Send + Unpin + 'static> {
87        Ok(DummyIO)
88    }
89
90    fn sleep(&self, _dur: Duration) -> Self::Sleep {
91        future::ready(())
92    }
93
94    fn interval(&self, _dur: Duration) -> impl Stream<Item = Instant> + Send + 'static {
95        DummyStream(PhantomData)
96    }
97
98    fn tcp_connect_addr(
99        &self,
100        _addr: SocketAddr,
101    ) -> impl Future<Output = io::Result<Self::TcpStream>> + Send + 'static {
102        async { Ok(DummyIO) }
103    }
104}
105
106mod task {
107    use crate::util::TaskImpl;
108    use async_trait::async_trait;
109    use std::{
110        future::Future,
111        marker::PhantomData,
112        pin::Pin,
113        task::{Context, Poll},
114    };
115
116    /// A noop task
117    #[derive(Debug)]
118    pub struct NTask<T: Send + 'static>(pub(super) PhantomData<T>);
119
120    impl<T: Send + 'static> Unpin for NTask<T> {}
121
122    #[async_trait]
123    impl<T: Send + 'static> TaskImpl for NTask<T> {}
124
125    impl<T: Send + 'static> Future for NTask<T> {
126        type Output = T;
127
128        fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
129            Poll::Pending
130        }
131    }
132}
133
134#[cfg(test)]
135mod tests {
136    use super::*;
137
138    #[test]
139    fn auto_traits() {
140        use crate::util::test::*;
141        let runtime = Runtime::noop();
142        assert_send(&runtime);
143        assert_sync(&runtime);
144        assert_clone(&runtime);
145    }
146}