use std::rc::Rc;
use std::task::{RawWaker, RawWakerVTable, Waker};
use core::mem::ManuallyDrop;
use futures::task::WakerRef;
pub(super) trait RcWake {
fn wake(self: Rc<Self>) {
Self::wake_by_ref(&self)
}
fn wake_by_ref(rc_self: &Rc<Self>);
}
pub(super) fn waker_ref<W>(wake: &Rc<W>) -> WakerRef<'_>
where
W: RcWake + 'static,
{
let ptr = Rc::as_ptr(wake).cast::<()>();
let waker = ManuallyDrop::new(unsafe { Waker::from_raw(RawWaker::new(ptr, waker_vtable::<W>())) });
WakerRef::new_unowned(waker)
}
fn waker_vtable<W: RcWake + 'static>() -> &'static RawWakerVTable {
&RawWakerVTable::new(
clone_rc_raw::<W>,
wake_rc_raw::<W>,
wake_by_ref_rc_raw::<W>,
drop_rc_raw::<W>,
)
}
#[allow(clippy::redundant_clone)] unsafe fn increase_refcount<T: RcWake + 'static>(data: *const ()) {
let rc = ManuallyDrop::new(unsafe { Rc::<T>::from_raw(data.cast::<T>()) });
let _rc_clone: ManuallyDrop<_> = rc.clone();
}
unsafe fn clone_rc_raw<T: RcWake + 'static>(data: *const ()) -> RawWaker {
unsafe { increase_refcount::<T>(data) };
RawWaker::new(data, waker_vtable::<T>())
}
unsafe fn wake_rc_raw<T: RcWake + 'static>(data: *const ()) {
let rc: Rc<T> = unsafe { Rc::from_raw(data.cast::<T>()) };
RcWake::wake(rc);
}
unsafe fn wake_by_ref_rc_raw<T: RcWake + 'static>(data: *const ()) {
let rc = ManuallyDrop::new(unsafe { Rc::<T>::from_raw(data.cast::<T>()) });
RcWake::wake_by_ref(&rc);
}
unsafe fn drop_rc_raw<T: RcWake + 'static>(data: *const ()) {
drop(unsafe { Rc::<T>::from_raw(data.cast::<T>()) })
}