1use std::marker::PhantomData;
2use std::mem::ManuallyDrop;
3use std::ptr::NonNull;
4use std::task::{RawWaker, RawWakerVTable, Waker};
5use std::{fmt, rc::Rc};
6
7use crate::rt::task;
8
9const NATIVE: NonNull<()> = NonNull::dangling();
11const _: () = assert!(align_of::<RawWakerVTable>() > 1);
12
13#[repr(C)]
49pub struct LocalWaker {
50 data: *const (),
51 metadata: NonNull<()>,
53 _local: PhantomData<Rc<()>>,
54}
55
56#[cfg(target_pointer_width = "64")]
57const _: () = {
58 assert!(size_of::<LocalWaker>() == 16);
59 assert!(size_of::<Option<LocalWaker>>() == 16);
60};
61
62impl LocalWaker {
63 #[inline]
65 pub fn from_waker(waker: &Waker) -> Self {
66 if let Some(ptr) = task::local_waker_ptr(waker) {
67 unsafe { task::clone_local_waker(ptr) };
68 Self::native(ptr)
69 } else {
70 Self::fallback(waker.clone())
71 }
72 }
73
74 #[inline]
76 pub fn wake(self) {
77 if self.is_native() {
78 let this = ManuallyDrop::new(self);
79 unsafe { task::wake_local_waker(this.data, true) };
80 } else {
81 self.into_waker().wake();
82 }
83 }
84
85 #[inline]
87 pub fn wake_by_ref(&self) {
88 if self.is_native() {
89 unsafe { task::wake_local_waker(self.data, false) };
90 } else {
91 self.borrowed_waker().wake_by_ref();
92 }
93 }
94
95 #[inline]
100 pub fn will_wake(&self, waker: &Waker) -> bool {
101 self.borrowed_waker().will_wake(waker)
102 }
103
104 #[inline]
108 pub fn into_waker(self) -> Waker {
109 let this = ManuallyDrop::new(self);
110 if this.is_native() {
111 unsafe { task::into_waker(this.data) }
112 } else {
113 unsafe { Waker::from_raw(this.raw_waker()) }
114 }
115 }
116
117 fn native(data: *const ()) -> Self {
118 Self {
119 data,
120 metadata: NATIVE,
121 _local: PhantomData,
122 }
123 }
124
125 fn fallback(waker: Waker) -> Self {
126 let waker = ManuallyDrop::new(waker);
127 Self {
128 data: waker.data(),
129 metadata: NonNull::from(waker.vtable()).cast(),
130 _local: PhantomData,
131 }
132 }
133
134 fn is_native(&self) -> bool {
135 self.metadata == NATIVE
136 }
137
138 fn raw_waker(&self) -> RawWaker {
139 if self.is_native() {
140 task::raw_waker(self.data)
141 } else {
142 RawWaker::new(self.data, unsafe {
144 self.metadata.cast::<RawWakerVTable>().as_ref()
145 })
146 }
147 }
148
149 fn borrowed_waker(&self) -> ManuallyDrop<Waker> {
150 ManuallyDrop::new(unsafe { Waker::from_raw(self.raw_waker()) })
152 }
153}
154
155impl From<Waker> for LocalWaker {
156 #[inline]
158 fn from(waker: Waker) -> Self {
159 if let Some(ptr) = task::local_waker_ptr(&waker) {
160 unsafe { task::clone_local_waker(ptr) };
161 drop(waker);
162 Self::native(ptr)
163 } else {
164 Self::fallback(waker)
165 }
166 }
167}
168
169impl Clone for LocalWaker {
170 #[inline]
171 fn clone(&self) -> Self {
172 if self.is_native() {
173 unsafe { task::clone_local_waker(self.data) };
174 Self::native(self.data)
175 } else {
176 Self::fallback((*self.borrowed_waker()).clone())
177 }
178 }
179
180 #[inline]
181 fn clone_from(&mut self, source: &Self) {
182 if self.data != source.data || self.metadata != source.metadata {
183 *self = source.clone();
184 }
185 }
186}
187
188impl Drop for LocalWaker {
189 #[inline]
190 fn drop(&mut self) {
191 if self.is_native() {
192 unsafe { task::drop_local_waker(self.data) };
193 } else {
194 drop(unsafe { Waker::from_raw(self.raw_waker()) });
195 }
196 }
197}
198
199impl fmt::Debug for LocalWaker {
200 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201 f.debug_struct("LocalWaker")
202 .field("data", &self.data)
203 .field("native", &self.is_native())
204 .finish()
205 }
206}
207
208#[cfg(all(test, not(ntex_loom)))]
209#[path = "../tests/unit/local_waker.rs"]
210mod tests;