Skip to main content

traffic_light/
executor.rs

1//! The traffic-light Executor.
2//!
3//! # Examples
4//!
5//! ```
6//! use std::{error, result};
7//!
8//! use traffic_light::executor::Executor;
9//!
10//! fn main() -> result::Result<(), Box<dyn error::Error>> {
11//!     Executor::block_on(async {
12//!         // ...
13//!         Ok::<(), Box<dyn error::Error>>(())
14//!     })?;
15//!
16//!     Ok(())
17//! }
18//! ```
19
20use std::{
21    pin::pin,
22    sync::Arc,
23    task::{Context, Poll, Waker},
24    thread,
25};
26
27use crate::thread::Thread;
28
29thread_local! {
30    static WAKER: Waker = Waker::from(Arc::new(Thread::default()));
31}
32
33/// The traffic-light Executor.
34pub struct Executor;
35
36impl Executor {
37    /// Blocks the current thread until the future is ready.
38    ///
39    /// # Panics
40    ///
41    /// Panics if the provided future panics.
42    ///
43    /// # Examples
44    ///
45    /// ```
46    /// # use std::{error,result};
47    /// #
48    /// use traffic_light::executor::Executor;
49    ///
50    /// # fn main() -> result::Result<(), Box<dyn error::Error>> {
51    /// let x: result::Result<(), Box<dyn error::Error>> =
52    ///     Executor::block_on(async {
53    ///         // ...
54    ///         Ok(())
55    ///     });
56    ///
57    /// assert!(x.is_ok());
58    /// #
59    /// #     Ok(())
60    /// # }
61    /// ```
62    pub fn block_on<F: IntoFuture>(f: F) -> F::Output {
63        let mut f = pin!(f.into_future());
64
65        WAKER.with(|waker| {
66            let mut cx = Context::from_waker(waker);
67
68            loop {
69                match f.as_mut().poll(&mut cx) {
70                    Poll::Ready(x) => return x,
71                    Poll::Pending => thread::park(),
72                }
73            }
74        })
75    }
76}
77
78#[rustfmt::skip]
79#[cfg(test)]
80mod tests {
81    use std::{
82        error,
83        result,
84    };
85
86    use super::*;
87
88    #[test]
89    fn block_on_result_ok() {
90        let x: result::Result<(), Box<dyn error::Error>> =
91            Executor::block_on(async {
92                Ok(())
93            });
94
95        assert!(x.is_ok());
96    }
97
98    #[test]
99    fn block_on_result_err() {
100        let x: result::Result<(), &str> =
101            Executor::block_on(async {
102                Err("")
103            });
104
105        assert!(x.is_err());
106    }
107}