use embedded_runtime::run;
use std::{
future::Future,
pin::Pin,
sync::{
atomic::{AtomicBool, AtomicUsize, Ordering::SeqCst},
Arc, Mutex,
},
task::{Context, Poll, Waker},
thread,
time::{Duration, Instant},
};
pub mod runtime {
use std::{
sync::atomic::{AtomicBool, Ordering::SeqCst},
thread,
time::Duration,
};
static SIGNAL: AtomicBool = AtomicBool::new(false);
#[no_mangle]
#[allow(non_snake_case)]
pub fn _runtime_waitforevent_TBFzxdKN() {
SIGNAL.store(true, SeqCst);
}
#[no_mangle]
#[allow(non_snake_case)]
pub fn _runtime_sendevent_3YSaPmB7() {
const SPINLOOP_INTERVAL: Duration = Duration::from_millis(33);
while SIGNAL.compare_exchange(true, false, SeqCst, SeqCst).is_err() {
thread::sleep(SPINLOOP_INTERVAL);
}
}
}
struct TimerFuture {
waker: Arc<Mutex<Option<Waker>>>,
done: Arc<AtomicBool>,
polled: &'static AtomicUsize,
}
impl TimerFuture {
const DELAY_7S: Duration = Duration::from_secs(7);
const DELAY_3S: Duration = Duration::from_secs(3);
pub fn delay(duration: Duration, polled: &'static AtomicUsize) -> Self {
let this = Self { waker: Default::default(), done: Default::default(), polled };
let (waker, done) = (Arc::clone(&this.waker), Arc::clone(&this.done));
thread::spawn(move || {
thread::sleep(duration);
done.store(true, SeqCst);
let waker = waker.lock().expect("failed to lock waker slot");
if let Some(waker) = waker.as_ref() {
waker.wake_by_ref();
}
});
this
}
}
impl Future for TimerFuture {
type Output = ();
fn poll(self: Pin<&mut Self>, _cx: &mut Context) -> Poll<Self::Output> {
self.polled.fetch_add(1, SeqCst);
match self.done.load(SeqCst) {
true => Poll::Ready(()),
false => Poll::Pending,
}
}
}
struct CountdownFuture {
countdown: usize,
polled: &'static AtomicUsize,
}
impl CountdownFuture {
pub const fn new(countdown: usize, polled: &'static AtomicUsize) -> Self {
Self { countdown, polled }
}
}
impl Future for CountdownFuture {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
self.polled.fetch_add(1, SeqCst);
if self.countdown > 0 {
*self = Self::new(self.countdown - 1, self.polled);
cx.waker().wake_by_ref();
return Poll::Pending;
}
Poll::Ready(())
}
}
fn test_timer() {
static POLLED: AtomicUsize = AtomicUsize::new(0);
let start = Instant::now();
run!(TimerFuture::delay(TimerFuture::DELAY_3S, &POLLED)).expect("failed to execute timer");
assert!(Instant::now() - start >= TimerFuture::DELAY_3S, "executor finished too early");
assert!(POLLED.load(SeqCst) >= 2, "future has not been polled often enough");
}
fn test_mutliple_timers() {
static POLLED: AtomicUsize = AtomicUsize::new(0);
let start = Instant::now();
run! {
TimerFuture::delay(TimerFuture::DELAY_3S, &POLLED),
TimerFuture::delay(TimerFuture::DELAY_7S, &POLLED),
async {
TimerFuture::delay(TimerFuture::DELAY_3S, &POLLED).await;
TimerFuture::delay(TimerFuture::DELAY_7S, &POLLED).await;
}
}
.expect("failed to execute timer");
assert!(Instant::now() - start >= TimerFuture::DELAY_7S, "executor finished too early");
assert!(POLLED.load(SeqCst) >= 8, "future has not been polled often enough");
}
fn test_multipoll_immediately() {
static POLLED: AtomicUsize = AtomicUsize::new(0);
run!(CountdownFuture::new(7, &POLLED)).expect("failed to execute countdown");
assert!(POLLED.load(SeqCst) >= 8, "future has not been polled often enough");
}
fn test_yield() {
static POLLED: AtomicBool = AtomicBool::new(false);
let assert_polled = async {
embedded_runtime::spin_once().await;
assert!(POLLED.load(SeqCst), "second future has not been polled")
};
let set_polled = async {
POLLED.store(true, SeqCst);
};
run!(assert_polled, set_polled).expect("failed to execute futures");
}
#[test]
fn all() {
test_timer();
test_mutliple_timers();
test_multipoll_immediately();
test_yield();
}