1 | use crate::loom::sync::Arc; |
2 | |
3 | use std::marker::PhantomData; |
4 | use std::mem::ManuallyDrop; |
5 | use std::ops::Deref; |
6 | use std::task::{RawWaker, RawWakerVTable, Waker}; |
7 | |
8 | /// Simplified waking interface based on Arcs. |
9 | pub(crate) trait Wake: Send + Sync + Sized + 'static { |
10 | /// Wake by value. |
11 | fn wake(arc_self: Arc<Self>); |
12 | |
13 | /// Wake by reference. |
14 | fn wake_by_ref(arc_self: &Arc<Self>); |
15 | } |
16 | |
17 | /// A `Waker` that is only valid for a given lifetime. |
18 | #[derive (Debug)] |
19 | pub(crate) struct WakerRef<'a> { |
20 | waker: ManuallyDrop<Waker>, |
21 | _p: PhantomData<&'a ()>, |
22 | } |
23 | |
24 | impl Deref for WakerRef<'_> { |
25 | type Target = Waker; |
26 | |
27 | fn deref(&self) -> &Waker { |
28 | &self.waker |
29 | } |
30 | } |
31 | |
32 | /// Creates a reference to a `Waker` from a reference to `Arc<impl Wake>`. |
33 | pub(crate) fn waker_ref<W: Wake>(wake: &Arc<W>) -> WakerRef<'_> { |
34 | let ptr: *const () = Arc::as_ptr(this:wake).cast::<()>(); |
35 | |
36 | let waker: Waker = unsafe { Waker::from_raw(waker:RawWaker::new(data:ptr, vtable:waker_vtable::<W>())) }; |
37 | |
38 | WakerRef { |
39 | waker: ManuallyDrop::new(waker), |
40 | _p: PhantomData, |
41 | } |
42 | } |
43 | |
44 | fn waker_vtable<W: Wake>() -> &'static RawWakerVTable { |
45 | &RawWakerVTable::new( |
46 | clone_arc_raw::<W>, |
47 | wake_arc_raw::<W>, |
48 | wake_by_ref_arc_raw::<W>, |
49 | drop_arc_raw::<W>, |
50 | ) |
51 | } |
52 | |
53 | unsafe fn clone_arc_raw<T: Wake>(data: *const ()) -> RawWaker { |
54 | Arc::<T>::increment_strong_count(ptr:data as *const T); |
55 | RawWaker::new(data, vtable:waker_vtable::<T>()) |
56 | } |
57 | |
58 | unsafe fn wake_arc_raw<T: Wake>(data: *const ()) { |
59 | let arc: Arc<T> = Arc::from_raw(ptr:data as *const T); |
60 | Wake::wake(arc_self:arc); |
61 | } |
62 | |
63 | // used by `waker_ref` |
64 | unsafe fn wake_by_ref_arc_raw<T: Wake>(data: *const ()) { |
65 | // Retain Arc, but don't touch refcount by wrapping in ManuallyDrop |
66 | let arc: ManuallyDrop> = ManuallyDrop::new(Arc::<T>::from_raw(ptr:data.cast())); |
67 | Wake::wake_by_ref(&arc); |
68 | } |
69 | |
70 | unsafe fn drop_arc_raw<T: Wake>(data: *const ()) { |
71 | drop(Arc::<T>::from_raw(ptr:data.cast())); |
72 | } |
73 | |