use std::sync::atomic::{AtomicBool, Ordering};
use std::task::{RawWaker, RawWakerVTable, Waker};
pub(crate) struct AtomicWakeTracker {
woken: AtomicBool,
}
impl AtomicWakeTracker {
#[expect(
clippy::unnecessary_box_returns,
reason = "the Box ensures a stable address for the raw waker data pointer"
)]
pub(crate) fn new() -> Box<Self> {
Box::new(Self {
woken: AtomicBool::new(false),
})
}
pub(crate) unsafe fn waker(&self) -> Waker {
let data: *const () = std::ptr::from_ref(self).cast();
unsafe { Waker::from_raw(RawWaker::new(data, &ATOMIC_VTABLE)) }
}
pub(crate) fn was_woken(&self) -> bool {
self.woken.load(Ordering::Relaxed)
}
}
fn atomic_clone_fn(data: *const ()) -> RawWaker {
RawWaker::new(data, &ATOMIC_VTABLE)
}
fn atomic_wake_fn(data: *const ()) {
atomic_wake_by_ref_fn(data);
}
fn atomic_wake_by_ref_fn(data: *const ()) {
let this = unsafe { &*(data as *const AtomicWakeTracker) };
this.woken.store(true, Ordering::Relaxed);
}
fn atomic_drop_fn(_data: *const ()) {}
static ATOMIC_VTABLE: RawWakerVTable = RawWakerVTable::new(
atomic_clone_fn,
atomic_wake_fn,
atomic_wake_by_ref_fn,
atomic_drop_fn,
);