polyoxide_rt/runtime.rs
1//! The `Runtime` trait.
2
3use std::fmt;
4use std::time::Duration;
5
6use crate::{BoxFuture, Instant};
7
8/// What a polyoxide crate needs of an async runtime: a detached spawn, a
9/// sleep, a yield to the host, and a monotonic clock. Everything else in this
10/// crate (`spawn`'s `Task`, `timeout`, `Interval`) is built on these, so an
11/// implementor writes only these.
12///
13/// A client takes its runtime from its builder, and falls back to
14/// `default_runtime()`; nothing is process-wide.
15pub trait Runtime: Send + Sync + fmt::Debug + 'static {
16 /// Run `task` to completion, detached.
17 fn spawn(&self, task: BoxFuture<()>);
18
19 /// Complete after `duration`. Any duration, `Duration::MAX` included, is
20 /// valid.
21 fn sleep(&self, duration: Duration) -> BoxFuture<()>;
22
23 /// Hand the thread back to the host once: work already queued (other
24 /// tasks, I/O callbacks, a browser's messages) runs before the caller
25 /// continues, and no timer is involved.
26 ///
27 /// It has no default because nothing generic really yields: re-waking the
28 /// task at once only re-queues it, which under a browser's microtask queue
29 /// never reaches the event loop, and a zero sleep is no timer at all
30 /// there. Tokio's runtime defers to `tokio::task::yield_now`; the
31 /// browser's resumes on the next macrotask, through a `MessageChannel`
32 /// post, which no timer clamp delays.
33 fn yield_now(&self) -> BoxFuture<()>;
34
35 /// The runtime's monotonic clock.
36 fn now(&self) -> Instant;
37
38 /// Complete at `deadline`, at once when it has passed.
39 fn sleep_until(&self, deadline: Instant) -> BoxFuture<()> {
40 self.sleep(deadline.saturating_duration_since(self.now()))
41 }
42}