use std::fmt::Debug;
use std::sync::Arc;
use std::task::{RawWaker, RawWakerVTable, Waker};
use crate::{defer_wake, Key};
struct WakerDataArc {
schedule_fn: Box<dyn Fn() + Send + Sync>,
}
impl WakerDataArc {
fn new<E: Debug + Clone + Send + Sync + 'static>(key: Key<E>, event: E) -> Arc<Self> {
Arc::new(Self {
schedule_fn: Box::new(move || {
defer_wake(key, event.clone());
}),
})
}
fn wake(&self) {
(self.schedule_fn)();
}
}
static DES_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(
des_waker_clone,
des_waker_wake,
des_waker_wake_by_ref,
des_waker_drop,
);
unsafe fn des_waker_clone(data: *const ()) -> RawWaker {
Arc::increment_strong_count(data as *const WakerDataArc);
RawWaker::new(data, &DES_WAKER_VTABLE)
}
unsafe fn des_waker_wake(data: *const ()) {
let arc = Arc::from_raw(data as *const WakerDataArc);
arc.wake();
}
unsafe fn des_waker_wake_by_ref(data: *const ()) {
let waker_data = &*(data as *const WakerDataArc);
waker_data.wake();
}
unsafe fn des_waker_drop(data: *const ()) {
drop(Arc::from_raw(data as *const WakerDataArc));
}
pub fn create_des_waker<E: Debug + Clone + Send + Sync + 'static>(key: Key<E>, event: E) -> Waker {
let arc = WakerDataArc::new(key, event);
let raw_waker = RawWaker::new(Arc::into_raw(arc) as *const (), &DES_WAKER_VTABLE);
unsafe { Waker::from_raw(raw_waker) }
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug, Clone)]
struct TestEvent(usize);
#[test]
fn test_waker_clone() {
let key: Key<TestEvent> = Key::new_with_id(uuid::Uuid::from_u128(1));
let waker = create_des_waker(key, TestEvent(42));
let waker2 = waker.clone();
let waker3 = waker2.clone();
drop(waker);
drop(waker3);
drop(waker2);
}
#[test]
fn test_waker_will_wake() {
let key: Key<TestEvent> = Key::new_with_id(uuid::Uuid::from_u128(1));
let waker1 = create_des_waker(key, TestEvent(1));
let waker2 = waker1.clone();
assert!(waker1.will_wake(&waker2));
}
}