4 releases (breaking)

0.4.0 Nov 6, 2024
0.3.0 May 24, 2024
0.2.0 Jul 21, 2023
0.1.2 Jul 15, 2023

#278 in Asynchronous

Download history 2/week @ 2024-09-17 9/week @ 2024-09-24 1/week @ 2024-10-08 1/week @ 2024-10-29 137/week @ 2024-11-05 7/week @ 2024-11-12 9/week @ 2024-11-19 4/week @ 2024-11-26

158 downloads per month
Used in 2 crates

BSD-2-Clause OR MIT

14KB
141 lines

License BSD-2-Clause License MIT AppVeyor CI docs.rs crates.io Download numbers dependency status

embedded-runtime

This crate provides a tiny async runtime, targeted at embedded devices. Therefore, it provides a single-threaded executor as well as a stack-allocated box to box futures.

Runtime setup

This crate is hardware-independent, and needs some dependency-injection to perform signal/wait on your target hardware.

To provide these dependencies, you need to define the following two extern "Rust" functions:

  • _runtime_waitforevent_TBFzxdKN: Blocks until an event occurs (may wake spuriously). Important: Events must not be lost. If an event has occurred between the last invocation and this invocation, this function must not block.
  • _runtime_sendevent_3YSaPmB7: Raises an event. Important: Events must not be lost. If an event is sent, but the receiver is not currently waiting, it must be retained until the receiver tries to wait again.

For an example on how to inject your implementation, see also embedded-runtime-rp2040, which is basically this crate with wfe/sev-based runtime functions for rp2040 boards.

Example

# use core::{
#     future::Future,
#     pin::Pin,
#     task::{Poll, Context}
# };
#
# /// Blocks until an event occurs (may wake spuriously)
# #[no_mangle]
# #[allow(non_snake_case)]
# pub fn _runtime_waitforevent_TBFzxdKN() {
#     // No-op
# }
# 
# /// Raises an event
# #[no_mangle]
# #[allow(non_snake_case)]
# pub fn _runtime_sendevent_3YSaPmB7() {
#     // No-op
# }
use embedded_runtime::run;

/// A countdown future that resolves to pending until the poll-countdown becomes zero
struct CountdownFuture {
    /// The current countdown value
    countdown: usize
}
impl CountdownFuture {
    /// Creates a new countdown future
    pub const fn new(countdown: usize) -> Self {
        Self { countdown }
    }
}
impl Future for CountdownFuture {
    type Output = ();

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
        // Decrement the value if we are still pending
        if self.countdown > 0 {
            // Print the countdown
            println!("{}!", self.countdown);

            // Decrement the future, wake the executor and return pending
            *self = Self::new(self.countdown - 1);
            cx.waker().wake_by_ref();
            return Poll::Pending;
        }

        // Return ready
        println!("Liftoff 🚀");
        Poll::Ready(())
    }
}

// This creates a new runtime and executes the given futures in an async context
run!(async {
    CountdownFuture::new(3).await;
    CountdownFuture::new(7).await;
}).expect("failed to perform countdowns");

No runtime deps