use std::cell::Cell;
use std::sync::atomic::{AtomicBool, Ordering};
use std::task::{RawWaker, RawWakerVTable, Waker};
pub(crate) struct ReentrantWakerData {
action: Box<dyn Fn()>,
was_woken: Cell<bool>,
}
impl ReentrantWakerData {
#[expect(
clippy::unnecessary_box_returns,
reason = "the Box ensures a stable address for the raw waker data pointer"
)]
pub(crate) fn new(action: impl Fn() + 'static) -> Box<Self> {
Box::new(Self {
action: Box::new(action),
was_woken: Cell::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, &VTABLE)) }
}
pub(crate) fn was_woken(&self) -> bool {
self.was_woken.get()
}
}
fn clone_fn(data: *const ()) -> RawWaker {
RawWaker::new(data, &VTABLE)
}
fn wake_fn(data: *const ()) {
wake_by_ref_fn(data);
}
fn wake_by_ref_fn(data: *const ()) {
let this = unsafe { &*(data as *const ReentrantWakerData) };
this.was_woken.set(true);
(this.action)();
}
fn drop_fn(_data: *const ()) {}
static VTABLE: RawWakerVTable = RawWakerVTable::new(clone_fn, wake_fn, wake_by_ref_fn, drop_fn);
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,
);