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 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, vtable: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>(data: *const ()) { |
33 | // Retain Arc, but don't touch refcount by wrapping in ManuallyDrop |
34 | let arc: ManuallyDrop> = mem::ManuallyDrop::new(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 | unsafe fn clone_arc_raw<T: ArcWake>(data: *const ()) -> RawWaker { |
41 | increase_refcount::<T>(data); |
42 | RawWaker::new(data, vtable:waker_vtable::<T>()) |
43 | } |
44 | |
45 | unsafe fn wake_arc_raw<T: ArcWake>(data: *const ()) { |
46 | let arc: Arc<T> = Arc::from_raw(ptr:data.cast::<T>()); |
47 | ArcWake::wake(self:arc); |
48 | } |
49 | |
50 | // used by `waker_ref` |
51 | unsafe fn wake_by_ref_arc_raw<T: ArcWake>(data: *const ()) { |
52 | // Retain Arc, but don't touch refcount by wrapping in ManuallyDrop |
53 | let arc: ManuallyDrop> = mem::ManuallyDrop::new(Arc::<T>::from_raw(ptr:data.cast::<T>())); |
54 | ArcWake::wake_by_ref(&arc); |
55 | } |
56 | |
57 | unsafe fn drop_arc_raw<T: ArcWake>(data: *const ()) { |
58 | drop(Arc::<T>::from_raw(ptr:data.cast::<T>())) |
59 | } |
60 | |