use std::{
sync::{
Arc,
atomic::{AtomicUsize, Ordering},
},
task::{RawWaker, RawWakerVTable, Wake, Waker},
};
#[derive(Default)]
pub(crate) struct CountingWake(pub(crate) AtomicUsize);
impl CountingWake {
pub(crate) fn wakes(&self) -> usize {
self.0.load(Ordering::Acquire)
}
}
impl Wake for CountingWake {
fn wake(self: Arc<Self>) {
self.wake_by_ref();
}
fn wake_by_ref(self: &Arc<Self>) {
self.0.fetch_add(1, Ordering::AcqRel);
}
}
static COUNTING_VTABLE: RawWakerVTable = RawWakerVTable::new(
clone_counting,
wake_counting,
wake_counting_by_ref,
drop_counting,
);
unsafe fn clone_counting(data: *const ()) -> RawWaker {
unsafe { Arc::increment_strong_count(data.cast::<CountingWake>()) };
RawWaker::new(data, &COUNTING_VTABLE)
}
unsafe fn wake_counting(data: *const ()) {
let target = unsafe { Arc::from_raw(data.cast::<CountingWake>()) };
target.0.fetch_add(1, Ordering::AcqRel);
}
unsafe fn wake_counting_by_ref(data: *const ()) {
let target = unsafe { &*data.cast::<CountingWake>() };
target.0.fetch_add(1, Ordering::AcqRel);
}
unsafe fn drop_counting(data: *const ()) {
drop(unsafe { Arc::from_raw(data.cast::<CountingWake>()) });
}
pub(crate) fn counting_waker() -> (Arc<CountingWake>, Waker) {
let target = Arc::new(CountingWake::default());
let data = Arc::into_raw(Arc::clone(&target)).cast::<()>();
let waker = unsafe { Waker::from_raw(RawWaker::new(data, &COUNTING_VTABLE)) };
(target, waker)
}