use core::cell::Cell;
use core::cmp::min;
use core::ptr::NonNull;
use core::task::Waker;
use embassy_executor_timer_queue::TimerQueueItem;
#[derive(Default)]
struct QueueItem {
pub next: Cell<Option<NonNull<QueueItem>>>,
pub expires_at: u64,
pub waker: Option<Waker>,
}
unsafe impl Sync for QueueItem {}
pub struct Queue {
head: Cell<Option<NonNull<QueueItem>>>,
}
impl core::fmt::Debug for Queue {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Queue").finish()
}
}
unsafe impl Send for Queue {}
unsafe impl Sync for Queue {}
impl Queue {
pub const fn new() -> Self {
Self { head: Cell::new(None) }
}
pub fn schedule_wake(&mut self, at: u64, waker: &Waker) -> bool {
let item = unsafe {
TimerQueueItem::from_embassy_waker(waker)
};
self.schedule_wake_queue_item(at, item, waker)
}
pub fn schedule_wake_queue_item(&mut self, at: u64, item: &mut TimerQueueItem, waker: &Waker) -> bool {
let item = unsafe { item.as_mut::<QueueItem>() };
match item.waker.as_ref() {
Some(_) if at <= item.expires_at => {
item.expires_at = at;
true
}
Some(_) => {
false
}
None => {
let mut item_ptr = NonNull::from(item);
let prev = self.head.replace(Some(item_ptr));
let item = unsafe { item_ptr.as_mut() };
item.expires_at = at;
item.waker = Some(waker.clone());
item.next.set(prev);
true
}
}
}
pub fn next_expiration(&mut self, now: u64) -> u64 {
let mut next_expiration = u64::MAX;
self.retain(|item| {
if item.expires_at <= now {
if let Some(waker) = item.waker.take() {
waker.wake();
}
false
} else {
next_expiration = min(next_expiration, item.expires_at);
item.expires_at != u64::MAX
}
});
next_expiration
}
fn retain(&mut self, mut f: impl FnMut(&mut QueueItem) -> bool) {
let mut prev = &self.head;
while let Some(mut p) = prev.get() {
let mut item = unsafe { p.as_mut() };
if f(&mut item) {
prev = &item.next;
} else {
prev.set(item.next.get());
item.next.set(None);
item.waker = None;
}
}
}
}