toki_no/
lib.rs

1//! toki-no: A minimal and fast async runtime.
2
3use std::future::Future;
4use std::pin::Pin;
5use std::task::{Context, Poll};
6use std::thread;
7use std::time::{Duration, Instant};
8
9mod pin_utils;
10mod waker_fn;
11
12/// The `toki-no` async runtime.
13///
14/// The runtime is the entry point for running async code and holds
15/// state for managing tasks and resources.
16#[derive(Default)]
17pub struct Runtime;
18
19impl Runtime {
20    /// Creates a new `Runtime` instance with default configuration.
21    pub fn new() -> Self {
22        Runtime {}
23    }
24
25    /// Runs a future to completion on the current thread.
26    /// This function will block the calling thread until the given future is complete.
27    pub fn block_on<F: Future>(&self, future: F) -> F::Output {
28        // Pin the future on the stack. `pin_mut!` is a safe macro.
29        pin_mut!(future);
30
31        let thread = thread::current();
32        let waker = waker_fn::waker_fn(move || thread.unpark());
33        let mut context = Context::from_waker(&waker);
34
35        loop {
36            match future.as_mut().poll(&mut context) {
37                Poll::Ready(output) => return output,
38                Poll::Pending => thread::park(),
39            }
40        }
41    }
42}
43
44/// A future that completes after a specified duration.
45#[must_use = "futures do nothing unless you `.await` or poll them"]
46pub struct Sleep {
47    target_time: Instant,
48}
49
50/// Creates a new future that will complete after the given `duration`.
51// TODO: create with global timer thread instead of os thread.
52pub fn sleep(duration: Duration) -> Sleep {
53    Sleep {
54        target_time: Instant::now() + duration,
55    }
56}
57
58impl Future for Sleep {
59    type Output = ();
60
61    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
62        if Instant::now() >= self.target_time {
63            return Poll::Ready(());
64        }
65
66        // Schedule the waker to be called when the timer fires.
67        let waker = cx.waker().clone();
68        let target_time = self.target_time;
69        thread::spawn(move || {
70            let now = Instant::now();
71            if now < target_time {
72                thread::sleep(target_time - now);
73            }
74            waker.wake();
75        });
76
77        Poll::Pending
78    }
79}
80
81#[cfg(test)]
82mod tests {
83    use super::*;
84    use std::time::Duration;
85
86    #[test]
87    fn it_works_with_a_simple_future() {
88        // 1. Create the runtime
89        let rt = Runtime::new();
90
91        let future = async { 5 };
92
93        // 2. Call the block_on method
94        assert_eq!(rt.block_on(future), 5);
95    }
96
97    #[test]
98    fn it_works_with_a_future_that_yields() {
99        // 1. Create the runtime
100        let rt = Runtime::new();
101
102        let future = async {
103            println!("Going to sleep...");
104            sleep(Duration::from_millis(50)).await;
105            println!("Woke up!");
106            10
107        };
108
109        // 2. Call the block_on method
110        assert_eq!(rt.block_on(future), 10);
111    }
112}