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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
//! The executor for this runtime

mod waker;

use crate::{err, error::Error, runtime};
use core::{future::Future, pin::Pin, task::Context};

/// A tiny, single-threaded async executor suitable for embedded runtimes
///
/// # Generics
/// - `'a`: Tied to the lifetime of the pinned futures to execute (i.e. this executor must not outlive the futures it
///   executes)
/// - `T`: The type of futures to execute (e.g. `dyn Future<Output = ()>`)
/// - `LEN`: The maximum amount of top-level futures this executor can execute (defaults to `32`)
pub struct Executor<'a, T, const LEN: usize = 32>
where
    T: ?Sized,
{
    /// The registered futures
    futures: [Option<Pin<&'a mut T>>; LEN],
    /// The current length of `futures`
    len: usize,
}
impl<'a, T, const LEN: usize> Executor<'a, T, LEN>
where
    T: Future<Output = ()> + ?Sized,
{
    /// Initialization value for const initializer
    const INIT: Option<Pin<&'a mut T>> = None;

    /// Creates a new executor
    #[allow(clippy::new_without_default)]
    pub fn new() -> Self {
        Self { futures: [Self::INIT; LEN], len: 0 }
    }

    /// Registers a new future for execution
    pub fn register(&mut self, future: Pin<&'a mut T>) -> Result<&mut Self, Error> {
        // Get the next free slot
        let Some(slot) = self.futures.get_mut(self.len) else {
            return Err(err!("Executor has not enough storage to register more futures"));
        };

        // Box and store the future
        *slot = Some(future);
        self.len += 1;
        Ok(self)
    }

    /// Runs the executor
    pub fn run(&mut self) {
        // Create waker and context
        let waker = waker::new();
        let mut context = Context::from_waker(&waker);

        // Repeatedly poll all futures until they have completed
        let mut remaining = self.len;
        while remaining > 0 {
            // Poll each future
            'poll_loop: for index in 0..self.len {
                // Get the future if any
                let Some(future) = &mut self.futures[index] else {
                    continue 'poll_loop;
                };

                // Poll the future
                if future.as_mut().poll(&mut context).is_ready() {
                    // Unregister the future if it is dome
                    self.futures[index] = None;
                    remaining -= 1;
                }
            }

            // Wait until at least one future signales that it is ready
            // Note: We do this *after* the polling to ensure that each future is at least polled once
            unsafe { runtime::_runtime_waitforevent_TBFzxdKN() };
        }
    }
}

/// Creates an executor and executes the given futures
#[macro_export]
macro_rules! run {
    ($($futures:expr),+) => {{
        /// Executes the given futures
        let execute = || -> core::result::Result<(), $crate::error::Error> {
            // Create executor
            let mut executor: $crate::executor::Executor<'_, dyn core::future::Future<Output = ()>> =
                $crate::executor::Executor::new();

            // Register futures
            $(
                let future = core::pin::pin!($futures);
                executor.register(future as core::pin::Pin<&mut dyn core::future::Future<Output = ()>>)?;
            )*

            // Execute the futures
            executor.run();
            Ok(())
        };

        // Execute all futures
        execute()
    }};
}