use super::arc_wake::ArcWake; use core::mem; use core::task::{Waker, RawWaker, RawWakerVTable}; use alloc::sync::Arc; 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) as *const (); 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(Arc::::from_raw(data as *const T)); // Now increase refcount, but don't drop new refcount either let _arc_clone: mem::ManuallyDrop<_> = arc.clone(); } // used by `waker_ref` unsafe fn clone_arc_raw(data: *const ()) -> RawWaker { increase_refcount::(data); RawWaker::new(data, waker_vtable::()) } unsafe fn wake_arc_raw(data: *const ()) { let arc: Arc = Arc::from_raw(data as *const T); 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(Arc::::from_raw(data as *const T)); ArcWake::wake_by_ref(&arc); } unsafe fn drop_arc_raw(data: *const ()) { drop(Arc::::from_raw(data as *const T)) }