use super::arc_wake::ArcWake; use alloc::sync::Arc; use core::mem; use core::task::{RawWaker, RawWakerVTable, Waker}; pub(super) fn waker_vtable() -> &'static RawWakerVTable { &RawWakerVTable::new( clone_arc_raw::, wake_arc_raw::, wake_by_ref_arc_raw::, drop_arc_raw::, ) } /// Creates a [`Waker`] from an `Arc`. /// /// The returned [`Waker`] will call /// [`ArcWake.wake()`](ArcWake::wake) if awoken. pub fn waker(wake: Arc) -> Waker where W: ArcWake + 'static, { let ptr = Arc::into_raw(wake).cast::<()>(); unsafe { Waker::from_raw(RawWaker::new(ptr, waker_vtable::())) } } // FIXME: panics on Arc::clone / refcount changes could wreak havoc on the // code here. We should guard against this by aborting. #[allow(clippy::redundant_clone)] // The clone here isn't actually redundant. unsafe fn increase_refcount(data: *const ()) { // Retain Arc, but don't touch refcount by wrapping in ManuallyDrop let arc = mem::ManuallyDrop::new(unsafe { Arc::::from_raw(data.cast::()) }); // Now increase refcount, but don't drop new refcount either let _arc_clone: mem::ManuallyDrop<_> = arc.clone(); } // used by `waker_ref` #[inline(always)] unsafe fn clone_arc_raw(data: *const ()) -> RawWaker { unsafe { increase_refcount::(data) } RawWaker::new(data, waker_vtable::()) } unsafe fn wake_arc_raw(data: *const ()) { let arc: Arc = unsafe { Arc::from_raw(data.cast::()) }; ArcWake::wake(arc); } // used by `waker_ref` unsafe fn wake_by_ref_arc_raw(data: *const ()) { // Retain Arc, but don't touch refcount by wrapping in ManuallyDrop let arc = mem::ManuallyDrop::new(unsafe { Arc::::from_raw(data.cast::()) }); ArcWake::wake_by_ref(&arc); } unsafe fn drop_arc_raw(data: *const ()) { drop(unsafe { Arc::::from_raw(data.cast::()) }) }