Skip to main content

trillium_async_std/
runtime.rs

1use async_std::{stream, task};
2use futures_lite::future::FutureExt;
3use std::{future::Future, sync::Arc, time::Duration};
4use trillium_server_common::{DroppableFuture, Runtime, RuntimeTrait, Stream};
5
6/// async-std runtime
7#[derive(Clone, Copy, Default, Debug)]
8pub struct AsyncStdRuntime(());
9
10impl RuntimeTrait for AsyncStdRuntime {
11    fn spawn<Fut>(
12        &self,
13        fut: Fut,
14    ) -> DroppableFuture<impl Future<Output = Option<Fut::Output>> + Send + 'static>
15    where
16        Fut: Future + Send + 'static,
17        Fut::Output: Send + 'static,
18    {
19        let join_handle = task::spawn(fut);
20        DroppableFuture::new(async move { join_handle.catch_unwind().await.ok() })
21    }
22
23    async fn delay(&self, duration: Duration) {
24        task::sleep(duration).await
25    }
26
27    fn interval(&self, period: Duration) -> impl Stream<Item = ()> + Send + 'static {
28        stream::interval(period)
29    }
30
31    fn block_on<Fut: Future>(&self, fut: Fut) -> Fut::Output {
32        task::block_on(fut)
33    }
34
35    #[cfg(unix)]
36    fn hook_signals(
37        &self,
38        signals: impl IntoIterator<Item = i32>,
39    ) -> impl Stream<Item = i32> + Send + 'static {
40        signal_hook_async_std::Signals::new(signals).unwrap()
41    }
42}
43
44impl AsyncStdRuntime {
45    /// Spawn a future on the runtime, returning a future that has detach-on-drop semantics
46    ///
47    /// Spawned tasks conform to the following behavior:
48    ///
49    /// * detach on drop: If the returned [`DroppableFuture`] is dropped immediately, the task will
50    ///   continue to execute until completion.
51    ///
52    /// * unwinding: If the spawned future panics, this must not propagate to the join handle.
53    ///   Instead, the awaiting the join handle returns None in case of panic.
54    pub fn spawn<Fut>(
55        &self,
56        fut: Fut,
57    ) -> DroppableFuture<impl Future<Output = Option<Fut::Output>> + Send + 'static + use<Fut>>
58    where
59        Fut: Future + Send + 'static,
60        Fut::Output: Send + 'static,
61    {
62        let join_handle = task::spawn(fut);
63        DroppableFuture::new(async move { join_handle.catch_unwind().await.ok() })
64    }
65
66    /// Wake in this amount of wall time
67    pub async fn delay(&self, duration: Duration) {
68        task::sleep(duration).await
69    }
70
71    /// Returns a [`Stream`] that yields a `()` on the provided period
72    pub fn interval(&self, period: Duration) -> impl Stream<Item = ()> + Send + 'static + use<> {
73        stream::interval(period)
74    }
75
76    /// Runtime implementation hook for blocking on a top level future.
77    pub fn block_on<Fut: Future>(&self, fut: Fut) -> Fut::Output {
78        task::block_on(fut)
79    }
80
81    /// Race a future against the provided duration, returning None in case of timeout.
82    pub async fn timeout<Fut>(&self, duration: Duration, fut: Fut) -> Option<Fut::Output>
83    where
84        Fut: Future + Send,
85        Fut::Output: Send + 'static,
86    {
87        RuntimeTrait::timeout(self, duration, fut).await
88    }
89}
90
91impl From<AsyncStdRuntime> for Runtime {
92    fn from(value: AsyncStdRuntime) -> Self {
93        Arc::new(value).into()
94    }
95}