//! Creates a Waker that can be observed from tests. use std::mem::forget; use std::sync::atomic::{AtomicU32, Ordering}; use std::sync::Arc; use std::task::{RawWaker, RawWakerVTable, Waker}; #[derive(Default)] pub struct WakerHandle { clone_count: AtomicU32, drop_count: AtomicU32, wake_count: AtomicU32, } impl WakerHandle { pub fn clone_count(&self) -> u32 { self.clone_count.load(Ordering::Relaxed) } pub fn drop_count(&self) -> u32 { self.drop_count.load(Ordering::Relaxed) } pub fn wake_count(&self) -> u32 { self.wake_count.load(Ordering::Relaxed) } } pub fn waker() -> (Waker, Arc) { let waker_handle = Arc::new(WakerHandle::default()); let waker_handle_ptr = Arc::into_raw(waker_handle.clone()); let raw_waker = RawWaker::new(waker_handle_ptr as *const _, waker_vtable()); (unsafe { Waker::from_raw(raw_waker) }, waker_handle) } pub(super) fn waker_vtable() -> &'static RawWakerVTable { &RawWakerVTable::new(clone_raw, wake_raw, wake_by_ref_raw, drop_raw) } unsafe fn clone_raw(data: *const ()) -> RawWaker { let handle: Arc = Arc::from_raw(data as *const _); handle.clone_count.fetch_add(1, Ordering::Relaxed); forget(handle.clone()); forget(handle); RawWaker::new(data, waker_vtable()) } unsafe fn wake_raw(data: *const ()) { let handle: Arc = Arc::from_raw(data as *const _); handle.wake_count.fetch_add(1, Ordering::Relaxed); handle.drop_count.fetch_add(1, Ordering::Relaxed); } unsafe fn wake_by_ref_raw(data: *const ()) { let handle: Arc = Arc::from_raw(data as *const _); handle.wake_count.fetch_add(1, Ordering::Relaxed); forget(handle) } unsafe fn drop_raw(data: *const ()) { let handle: Arc = Arc::from_raw(data as *const _); handle.drop_count.fetch_add(1, Ordering::Relaxed); drop(handle) }