1 | use super::arc_wake::ArcWake; |
2 | use super::waker::waker_vtable; |
3 | use alloc::sync::Arc; |
4 | use core::marker::PhantomData; |
5 | use core::mem::ManuallyDrop; |
6 | use core::ops::Deref; |
7 | use core::task::{RawWaker, Waker}; |
8 | |
9 | /// A [`Waker`] that is only valid for a given lifetime. |
10 | /// |
11 | /// Note: this type implements [`Deref<Target = Waker>`](std::ops::Deref), |
12 | /// so it can be used to get a `&Waker`. |
13 | #[derive(Debug)] |
14 | pub struct WakerRef<'a> { |
15 | waker: ManuallyDrop<Waker>, |
16 | _marker: PhantomData<&'a ()>, |
17 | } |
18 | |
19 | impl<'a> WakerRef<'a> { |
20 | /// Create a new [`WakerRef`] from a [`Waker`] reference. |
21 | #[inline ] |
22 | pub fn new(waker: &'a Waker) -> Self { |
23 | // copy the underlying (raw) waker without calling a clone, |
24 | // as we won't call Waker::drop either. |
25 | let waker = ManuallyDrop::new(unsafe { core::ptr::read(waker) }); |
26 | Self { waker, _marker: PhantomData } |
27 | } |
28 | |
29 | /// Create a new [`WakerRef`] from a [`Waker`] that must not be dropped. |
30 | /// |
31 | /// Note: this if for rare cases where the caller created a [`Waker`] in |
32 | /// an unsafe way (that will be valid only for a lifetime to be determined |
33 | /// by the caller), and the [`Waker`] doesn't need to or must not be |
34 | /// destroyed. |
35 | #[inline ] |
36 | pub fn new_unowned(waker: ManuallyDrop<Waker>) -> Self { |
37 | Self { waker, _marker: PhantomData } |
38 | } |
39 | } |
40 | |
41 | impl Deref for WakerRef<'_> { |
42 | type Target = Waker; |
43 | |
44 | #[inline ] |
45 | fn deref(&self) -> &Waker { |
46 | &self.waker |
47 | } |
48 | } |
49 | |
50 | /// Creates a reference to a [`Waker`] from a reference to `Arc<impl ArcWake>`. |
51 | /// |
52 | /// The resulting [`Waker`] will call |
53 | /// [`ArcWake.wake()`](ArcWake::wake) if awoken. |
54 | #[inline ] |
55 | pub fn waker_ref<W>(wake: &Arc<W>) -> WakerRef<'_> |
56 | where |
57 | W: ArcWake, |
58 | { |
59 | // simply copy the pointer instead of using Arc::into_raw, |
60 | // as we don't actually keep a refcount by using ManuallyDrop.< |
61 | let ptr = Arc::as_ptr(wake).cast::<()>(); |
62 | |
63 | let waker = |
64 | ManuallyDrop::new(unsafe { Waker::from_raw(RawWaker::new(ptr, waker_vtable::<W>())) }); |
65 | WakerRef::new_unowned(waker) |
66 | } |
67 | |