kona_common/
executor.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//! This module contains utilities for handling async functions in the no_std environment. This
//! allows for usage of async/await syntax for futures in a single thread.

use alloc::boxed::Box;
use core::{
    future::Future,
    task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
};

/// This function busy waits on a future until it is ready. It uses a no-op waker to poll the future
/// in a thread-blocking loop.
pub fn block_on<T>(f: impl Future<Output = T>) -> T {
    let mut f = Box::pin(f);

    // Construct a no-op waker.
    fn noop_clone(_: *const ()) -> RawWaker {
        noop_raw_waker()
    }
    const fn noop(_: *const ()) {}
    fn noop_raw_waker() -> RawWaker {
        let vtable = &RawWakerVTable::new(noop_clone, noop, noop, noop);
        RawWaker::new(core::ptr::null(), vtable)
    }
    let waker = unsafe { Waker::from_raw(noop_raw_waker()) };
    let mut context = Context::from_waker(&waker);

    loop {
        // Safety: This is safe because we only poll the future once per loop iteration,
        // and we do not move the future after pinning it.
        if let Poll::Ready(v) = f.as_mut().poll(&mut context) {
            return v;
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use core::future::ready;

    #[test]
    fn test_block_on() {
        let f = async { 42 };
        assert_eq!(block_on(f), 42);
    }

    #[test]
    fn test_block_on_ready() {
        let f = ready(42);
        assert_eq!(block_on(f), 42);
    }
}