Skip to main content

async_rs/implementors/
smol.rs

1//! smol implementation of async runtime definition traits
2
3use crate::{
4    Runtime,
5    sys::AsSysFd,
6    traits::{Executor, Reactor, RuntimeKit},
7    util::{IOHandle, Task},
8};
9use futures_core::Stream;
10use futures_io::{AsyncRead, AsyncWrite};
11use smol::{Async, Timer};
12use std::{
13    future::Future,
14    io::{self, Read, Write},
15    net::{SocketAddr, TcpStream},
16    time::{Duration, Instant},
17};
18
19use task::STask;
20
21/// Type alias for the smol runtime
22pub type SmolRuntime = Runtime<Smol>;
23
24impl SmolRuntime {
25    /// Create a new SmolRuntime
26    pub fn smol() -> Self {
27        Self::new(Smol)
28    }
29}
30
31/// Dummy object implementing async common interfaces on top of smol
32#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
33pub struct Smol;
34
35impl RuntimeKit for Smol {}
36
37impl Executor for Smol {
38    type Task<T: Send + 'static> = STask<T>;
39
40    fn block_on<T, F: Future<Output = T>>(&self, f: F) -> T {
41        smol::block_on(f)
42    }
43
44    fn spawn<T: Send + 'static, F: Future<Output = T> + Send + 'static>(
45        &self,
46        f: F,
47    ) -> Task<Self::Task<T>> {
48        STask(Some(smol::spawn(f))).into()
49    }
50
51    fn spawn_blocking<T: Send + 'static, F: FnOnce() -> T + Send + 'static>(
52        &self,
53        f: F,
54    ) -> Task<Self::Task<T>> {
55        STask(Some(smol::unblock(f))).into()
56    }
57}
58
59impl Reactor for Smol {
60    type TcpStream = Async<TcpStream>;
61    type Sleep = Timer;
62
63    fn register<H: Read + Write + AsSysFd + Send + 'static>(
64        &self,
65        socket: H,
66    ) -> io::Result<impl AsyncRead + AsyncWrite + Send + Unpin + 'static> {
67        Async::new(IOHandle::new(socket))
68    }
69
70    fn sleep(&self, dur: Duration) -> Self::Sleep {
71        Timer::after(dur)
72    }
73
74    fn interval(&self, dur: Duration) -> impl Stream<Item = Instant> + Send + 'static {
75        Timer::interval(dur)
76    }
77
78    fn tcp_connect_addr(
79        &self,
80        addr: SocketAddr,
81    ) -> impl Future<Output = io::Result<Self::TcpStream>> + Send + 'static {
82        async move {
83            let stream = Async::<TcpStream>::connect(addr).await?;
84            stream.get_ref().set_nodelay(true)?;
85            Ok(stream)
86        }
87    }
88}
89
90mod task {
91    use crate::util::TaskImpl;
92    use async_trait::async_trait;
93    use std::{
94        future::Future,
95        pin::Pin,
96        task::{Context, Poll},
97    };
98
99    /// A smol task
100    #[derive(Debug)]
101    pub struct STask<T: Send + 'static>(pub(super) Option<smol::Task<T>>);
102
103    #[async_trait]
104    impl<T: Send + 'static> TaskImpl for STask<T> {
105        async fn cancel(&mut self) -> Option<T> {
106            self.0.take()?.cancel().await
107        }
108
109        fn detach(&mut self) {
110            if let Some(task) = self.0.take() {
111                task.detach();
112            }
113        }
114    }
115
116    impl<T: Send + 'static> Future for STask<T> {
117        type Output = T;
118
119        fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
120            Pin::new(self.0.as_mut().expect("task canceled")).poll(cx)
121        }
122    }
123}
124
125#[cfg(test)]
126mod tests {
127    use super::*;
128
129    #[test]
130    fn auto_traits() {
131        use crate::util::test::*;
132        let runtime = Runtime::smol();
133        assert_send(&runtime);
134        assert_sync(&runtime);
135        assert_clone(&runtime);
136    }
137}