Skip to main content

agnostic_lite/
smol.rs

1use core::future::Future;
2
3cfg_time!(
4  mod after;
5  pub use after::*;
6  use crate::async_io::*;
7  use std::time::{Duration, Instant};
8);
9
10use crate::{AsyncBlockingSpawner, AsyncLocalSpawner, AsyncSpawner, Yielder};
11
12pub use crate::spawner::handle::JoinError;
13
14/// A [`AsyncSpawner`] that uses the [`smol`] runtime.
15///
16/// [`smol`]: https://docs.rs/smol
17#[derive(Debug, Clone, Copy)]
18pub struct SmolSpawner;
19
20impl Yielder for SmolSpawner {
21  async fn yield_now() {
22    ::smol::future::yield_now().await
23  }
24
25  async fn yield_now_local() {
26    ::smol::future::yield_now().await
27  }
28}
29
30impl AsyncSpawner for SmolSpawner {
31  type JoinHandle<O>
32    = JoinHandle<O>
33  where
34    O: Send + 'static;
35
36  fn spawn<F>(future: F) -> Self::JoinHandle<F::Output>
37  where
38    F::Output: Send + 'static,
39    F: Future + Send + 'static,
40  {
41    ::smol::spawn(future).into()
42  }
43
44  fn spawn_detach<F>(future: F)
45  where
46    F::Output: Send + 'static,
47    F: Future + Send + 'static,
48  {
49    ::smol::spawn(future).detach()
50  }
51}
52
53/// # Panics
54///
55/// Both local-spawn methods **always panic**: smol has no ambient thread-local
56/// executor to target, so a correct local spawn needs a `smol::LocalExecutor`
57/// the caller owns and drives — spawn onto it directly instead. (Before 0.7
58/// these methods spawned onto a temporary `LocalExecutor` that dropped at the
59/// end of the statement, cancelling the task: a silent no-op for
60/// `spawn_local_detach`, and a "task polled after completion" panic on
61/// awaiting `spawn_local`'s handle. A loud, immediate panic replaces that
62/// silent loss.)
63impl AsyncLocalSpawner for SmolSpawner {
64  type JoinHandle<O>
65    = JoinHandle<O>
66  where
67    O: 'static;
68
69  fn spawn_local<F>(_future: F) -> Self::JoinHandle<F::Output>
70  where
71    F::Output: 'static,
72    F: Future + 'static,
73  {
74    panic!(
75      "agnostic-lite: smol has no ambient thread-local executor to spawn onto; drive a \
76       smol::LocalExecutor yourself and spawn onto it directly"
77    )
78  }
79
80  fn spawn_local_detach<F>(_future: F)
81  where
82    F::Output: 'static,
83    F: Future + 'static,
84  {
85    panic!(
86      "agnostic-lite: smol has no ambient thread-local executor to spawn onto; drive a \
87       smol::LocalExecutor yourself and spawn onto it directly"
88    )
89  }
90}
91
92join_handle!(::smol::Task<T>);
93
94impl<T> super::JoinHandle<T> for JoinHandle<T> {
95  type JoinError = super::spawner::handle::JoinError;
96
97  fn detach(self) {
98    ::smol::Task::detach(self.handle)
99  }
100
101  fn abort(self) {
102    drop(self);
103  }
104}
105
106impl<T> super::LocalJoinHandle<T> for JoinHandle<T> {
107  type JoinError = super::spawner::handle::JoinError;
108
109  fn detach(self) {
110    ::smol::Task::detach(self.handle)
111  }
112}
113
114impl AsyncBlockingSpawner for SmolSpawner {
115  type JoinHandle<R>
116    = JoinHandle<R>
117  where
118    R: Send + 'static;
119
120  fn spawn_blocking<F, R>(f: F) -> Self::JoinHandle<R>
121  where
122    F: FnOnce() -> R + Send + 'static,
123    R: Send + 'static,
124  {
125    ::smol::unblock(f).into()
126  }
127
128  fn spawn_blocking_detach<F, R>(f: F)
129  where
130    F: FnOnce() -> R + Send + 'static,
131    R: Send + 'static,
132  {
133    ::smol::unblock(f).detach()
134  }
135}
136
137/// Concrete [`RuntimeLite`](crate::RuntimeLite) implementation based on [`smol`] runtime.
138///
139/// [`smol`]: https://docs.rs/smol
140#[derive(Debug, Clone, Copy)]
141pub struct SmolRuntime;
142
143impl core::fmt::Display for SmolRuntime {
144  fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
145    write!(f, "smol")
146  }
147}
148
149impl super::LocalRuntimeLite for SmolRuntime {
150  type LocalSpawner = SmolSpawner;
151  type BlockingSpawner = SmolSpawner;
152
153  cfg_time!(
154    type Instant = Instant;
155    type LocalInterval = AsyncIoInterval;
156    type LocalSleep = AsyncIoSleep;
157    type LocalDelay<F>
158      = AsyncIoDelay<F>
159    where
160      F: Future;
161    type LocalTimeout<F>
162      = AsyncIoTimeout<F>
163    where
164      F: Future;
165  );
166
167  fn new() -> Self {
168    Self
169  }
170
171  fn name() -> &'static str {
172    "smol"
173  }
174
175  fn fqname() -> &'static str {
176    "smol"
177  }
178
179  fn block_on<F: Future>(f: F) -> F::Output {
180    ::smol::block_on(f)
181  }
182
183  cfg_time!(
184    fn interval_local(interval: Duration) -> Self::LocalInterval {
185      AsyncIoInterval::interval(interval)
186    }
187
188    fn interval_local_at(start: Instant, period: Duration) -> Self::LocalInterval {
189      AsyncIoInterval::interval_at(start, period)
190    }
191
192    fn sleep_local(duration: Duration) -> Self::LocalSleep {
193      use crate::time::AsyncSleepExt;
194
195      AsyncIoSleep::sleep(duration)
196    }
197
198    fn sleep_local_until(instant: Instant) -> Self::LocalSleep {
199      use crate::time::AsyncSleepExt;
200
201      AsyncIoSleep::sleep_until(instant)
202    }
203
204    fn delay_local<F>(duration: Duration, fut: F) -> Self::LocalDelay<F>
205    where
206      F: Future,
207    {
208      use crate::time::AsyncLocalDelayExt;
209
210      <AsyncIoDelay<F> as AsyncLocalDelayExt<F>>::delay(duration, fut)
211    }
212
213    fn delay_local_at<F>(deadline: Instant, fut: F) -> Self::LocalDelay<F>
214    where
215      F: Future,
216    {
217      use crate::time::AsyncLocalDelayExt;
218
219      <AsyncIoDelay<F> as AsyncLocalDelayExt<F>>::delay_at(deadline, fut)
220    }
221
222    fn timeout_local<F>(duration: Duration, future: F) -> Self::LocalTimeout<F>
223    where
224      F: Future,
225    {
226      use crate::time::AsyncLocalTimeout;
227
228      <AsyncIoTimeout<F> as AsyncLocalTimeout<F>>::timeout_local(duration, future)
229    }
230
231    fn timeout_local_at<F>(deadline: Instant, future: F) -> Self::LocalTimeout<F>
232    where
233      F: Future,
234    {
235      use crate::time::AsyncLocalTimeout;
236
237      <AsyncIoTimeout<F> as AsyncLocalTimeout<F>>::timeout_local_at(deadline, future)
238    }
239  );
240}
241
242impl super::RuntimeLite for SmolRuntime {
243  type Spawner = SmolSpawner;
244
245  cfg_time!(
246    type AfterSpawner = SmolSpawner;
247    type Interval = AsyncIoInterval;
248    type Sleep = AsyncIoSleep;
249    type Delay<F>
250      = AsyncIoDelay<F>
251    where
252      F: Future + Send;
253    type Timeout<F>
254      = AsyncIoTimeout<F>
255    where
256      F: Future + Send;
257  );
258
259  async fn yield_now() {
260    ::smol::future::yield_now().await
261  }
262
263  cfg_time!(
264    fn interval(interval: Duration) -> Self::Interval {
265      AsyncIoInterval::interval(interval)
266    }
267
268    fn interval_at(start: Instant, period: Duration) -> Self::Interval {
269      AsyncIoInterval::interval_at(start, period)
270    }
271
272    fn sleep(duration: Duration) -> Self::Sleep {
273      use crate::time::AsyncSleepExt;
274
275      AsyncIoSleep::sleep(duration)
276    }
277
278    fn sleep_until(instant: Instant) -> Self::Sleep {
279      use crate::time::AsyncSleepExt;
280
281      AsyncIoSleep::sleep_until(instant)
282    }
283
284    fn delay<F>(duration: Duration, fut: F) -> Self::Delay<F>
285    where
286      F: Future + Send,
287    {
288      use crate::time::AsyncDelayExt;
289
290      <AsyncIoDelay<F> as AsyncDelayExt<F>>::delay(duration, fut)
291    }
292
293    fn delay_at<F>(deadline: Instant, fut: F) -> Self::Delay<F>
294    where
295      F: Future + Send,
296    {
297      use crate::time::AsyncDelayExt;
298
299      <AsyncIoDelay<F> as AsyncDelayExt<F>>::delay_at(deadline, fut)
300    }
301
302    fn timeout<F>(duration: Duration, future: F) -> Self::Timeout<F>
303    where
304      F: Future + Send,
305    {
306      use crate::time::AsyncTimeout;
307
308      <AsyncIoTimeout<F> as AsyncTimeout<F>>::timeout(duration, future)
309    }
310
311    fn timeout_at<F>(deadline: Instant, future: F) -> Self::Timeout<F>
312    where
313      F: Future + Send,
314    {
315      use crate::time::AsyncTimeout;
316
317      <AsyncIoTimeout<F> as AsyncTimeout<F>>::timeout_at(deadline, future)
318    }
319  );
320}