Skip to main content

traffic_light/
executor.rs

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