direct_executor/
lib.rs

1//! # `direct-executor`
2//!
3//! An executor that directly executes futures, with an optional customizable wait operation.
4#![no_std]
5#![deny(
6    missing_docs,
7    missing_debug_implementations,
8    missing_copy_implementations,
9    trivial_casts,
10    trivial_numeric_casts,
11    unstable_features,
12    unused_import_braces,
13    unused_qualifications,
14    clippy::all
15)]
16
17use core::future;
18use core::task;
19
20/// Runs the provided future by spin-looping until polling succeeds.
21///
22/// This is equivalent to `run(future, || core::sync::atomic::spin_loop_hint())`.
23pub fn run_spinning<F>(future: F) -> F::Output
24where
25    F: future::Future,
26{
27    run(future, || core::sync::atomic::spin_loop_hint())
28}
29
30/// Runs the provided future until polling succeeds, calling the provided `wait` closure in between
31/// each polling attempt.
32///
33/// A common pattern is to let `wait` simply be some delay function (like `sleep()`), or in certain
34/// environments (such as on embedded devices), it might make sense to call `wfi` to wait for
35/// peripheral interrupts, if you know that to be the source of future completion.
36pub fn run<F>(future: F, wait: impl FnMut()) -> F::Output
37where
38    F: future::Future,
39{
40    run_with_wake(future, wait, || {})
41}
42
43/// Runs the provided future until polling succeeds, calling the provided `wait` closure in between
44/// each polling attempt.
45///
46/// When this thread is supposed to wake up again, the provided `wake` closure will be called.  This
47/// allows the user to provide custom "unpark" functionality, if necessary.
48///
49/// A common pattern is to let `wait` simply be some delay function (like `sleep()`), or in certain
50/// environments (such as on embedded devices), it might make sense to call `wfi` to wait for
51/// peripheral interrupts, if you know that to be the source of future completion.
52pub fn run_with_wake<F>(future: F, mut wait: impl FnMut(), wake: fn()) -> F::Output
53where
54    F: future::Future,
55{
56    pin_utils::pin_mut!(future);
57
58    let raw_waker = raw_waker(&wake);
59    let waker = unsafe { task::Waker::from_raw(raw_waker) };
60    let mut context = task::Context::from_waker(&waker);
61
62    loop {
63        if let task::Poll::Ready(result) = future.as_mut().poll(&mut context) {
64            return result;
65        }
66        wait();
67    }
68}
69
70static VTABLE: task::RawWakerVTable = task::RawWakerVTable::new(clone, wake, wake, drop);
71
72fn raw_waker(wake_ptr: *const fn()) -> task::RawWaker {
73    task::RawWaker::new(wake_ptr as *const (), &VTABLE)
74}
75
76fn clone(wake_ptr: *const ()) -> task::RawWaker {
77    raw_waker(wake_ptr as *const fn())
78}
79
80fn wake(wake_ptr: *const ()) {
81    let wake = unsafe { (wake_ptr as *const fn()).as_ref() }.unwrap();
82    wake();
83}
84
85fn drop(_wake_ptr: *const ()) {}