| 1 | use super::arc_wake::ArcWake; |
| 2 | use alloc::sync::Arc; |
| 3 | use core::mem; |
| 4 | use core::task::{RawWaker, RawWakerVTable, Waker}; |
| 5 | |
| 6 | pub(super) fn waker_vtable<W: ArcWake + 'static>() -> &'static RawWakerVTable { |
| 7 | &RawWakerVTable::new( |
| 8 | clone_arc_raw::<W>, |
| 9 | wake_arc_raw::<W>, |
| 10 | wake_by_ref_arc_raw::<W>, |
| 11 | drop_arc_raw::<W>, |
| 12 | ) |
| 13 | } |
| 14 | |
| 15 | /// Creates a [`Waker`] from an `Arc<impl ArcWake>`. |
| 16 | /// |
| 17 | /// The returned [`Waker`] will call |
| 18 | /// [`ArcWake.wake()`](ArcWake::wake) if awoken. |
| 19 | pub fn waker<W>(wake: Arc<W>) -> Waker |
| 20 | where |
| 21 | W: ArcWake + 'static, |
| 22 | { |
| 23 | let ptr: *const () = Arc::into_raw(this:wake).cast::<()>(); |
| 24 | |
| 25 | unsafe { Waker::from_raw(waker:RawWaker::new(data:ptr, waker_vtable::<W>())) } |
| 26 | } |
| 27 | |
| 28 | // FIXME: panics on Arc::clone / refcount changes could wreak havoc on the |
| 29 | // code here. We should guard against this by aborting. |
| 30 | |
| 31 | #[allow (clippy::redundant_clone)] // The clone here isn't actually redundant. |
| 32 | unsafe fn increase_refcount<T: ArcWake + 'static>(data: *const ()) { |
| 33 | // Retain Arc, but don't touch refcount by wrapping in ManuallyDrop |
| 34 | let arc: ManuallyDrop> = mem::ManuallyDrop::new(unsafe { Arc::<T>::from_raw(ptr:data.cast::<T>()) }); |
| 35 | // Now increase refcount, but don't drop new refcount either |
| 36 | let _arc_clone: mem::ManuallyDrop<_> = arc.clone(); |
| 37 | } |
| 38 | |
| 39 | // used by `waker_ref` |
| 40 | #[inline (always)] |
| 41 | unsafe fn clone_arc_raw<T: ArcWake + 'static>(data: *const ()) -> RawWaker { |
| 42 | unsafe { increase_refcount::<T>(data) } |
| 43 | RawWaker::new(data, waker_vtable::<T>()) |
| 44 | } |
| 45 | |
| 46 | unsafe fn wake_arc_raw<T: ArcWake + 'static>(data: *const ()) { |
| 47 | let arc: Arc<T> = unsafe { Arc::from_raw(ptr:data.cast::<T>()) }; |
| 48 | ArcWake::wake(self:arc); |
| 49 | } |
| 50 | |
| 51 | // used by `waker_ref` |
| 52 | unsafe fn wake_by_ref_arc_raw<T: ArcWake + 'static>(data: *const ()) { |
| 53 | // Retain Arc, but don't touch refcount by wrapping in ManuallyDrop |
| 54 | let arc: ManuallyDrop> = mem::ManuallyDrop::new(unsafe { Arc::<T>::from_raw(ptr:data.cast::<T>()) }); |
| 55 | ArcWake::wake_by_ref(&arc); |
| 56 | } |
| 57 | |
| 58 | unsafe fn drop_arc_raw<T: ArcWake + 'static>(data: *const ()) { |
| 59 | drop(unsafe { Arc::<T>::from_raw(ptr:data.cast::<T>()) }) |
| 60 | } |
| 61 | |