1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
//! Utilities to aid implementing [`Waker`s](std::task::Waker) and working with
//! tasks.
//!
//! The highlight of this crate is [`Wake`], which allows you to construct
//! wakers from your own types by implementing this trait.
//!
//! # Examples
//!
//! Implementing your own `block_on` function using this crate:
//!
//! ```
//! use std::{
//!     future::Future,
//!     pin::Pin,
//!     task::{Context, Poll},
//!     thread,
//! };
//! use wakeful::Wake;
//!
//! fn block_on<F: Future>(mut future: F) -> F::Output {
//!     let waker = thread::current().into_waker();
//!     let mut context = Context::from_waker(&waker);
//!     let mut future = unsafe { Pin::new_unchecked(&mut future) };
//!
//!     loop {
//!         match future.as_mut().poll(&mut context) {
//!             Poll::Ready(output) => return output,
//!             Poll::Pending => thread::park(),
//!         }
//!     }
//! }
//! ```

#![warn(
    future_incompatible,
    missing_debug_implementations,
    missing_docs,
    rust_2018_idioms,
    unreachable_pub,
    unused,
    clippy::all
)]

use std::{
    mem, ptr,
    sync::Arc,
    task::{RawWaker, RawWakerVTable, Waker},
};

/// Zero-cost helper trait that makes it easier to implement wakers.
///
/// Implementing this trait provides you with [`Wake::into_waker`], which allows
/// you to construct a [`Waker`] from any type implementing [`Wake`]. The only
/// method you must implement is [`Wake::wake_by_ref`] which can encapsulate all
/// your custom wake-up behavior.
///
/// Your custom wakers must also implement [`Clone`], [`Send`], and [`Sync`] to
/// comply with the contract of [`Waker`]. You are free to choose any strategy
/// you like to handle cloning; bundling your state in an inner [`Arc`] is
/// common and plays nicely with this trait.
///
/// # Provided implementations
///
/// A simple waker implementation is provided for [`std::thread::Thread`], which
/// merely calls `unpark()`. This almost trivializes implementing your own
/// single-threaded `block_on` executor. An example of this is provided in the
/// `examples/` directory.
///
/// # Optimizations
///
/// If the size of `Self` is less than or equal to pointer size, as an
/// optimization the underlying implementation will pass `self` in directly to
/// [`RawWakerVTable`] functions. For types larger than a pointer, an allocation
/// will be made on creation and when cloning.
///
/// # Examples
///
/// ```
/// use wakeful::Wake;
///
/// /// Doesn't actually do anything except print a message when wake is called.
/// #[derive(Clone)]
/// struct PrintWaker;
///
/// impl Wake for PrintWaker {
///     fn wake_by_ref(&self) {
///         println!("wake called!");
///     }
/// }
///
/// let waker = PrintWaker.into_waker();
/// waker.wake(); // prints "wake called!"
/// ```
///
/// ```
/// use std::task::Waker;
/// use wakeful::Wake;
///
/// /// Delegates wake calls to multiple wakers.
/// #[derive(Clone)]
/// struct MultiWaker(Vec<Waker>);
///
/// impl Wake for MultiWaker {
///     fn wake(self) {
///         for waker in self.0 {
///             waker.wake();
///         }
///     }
///
///     fn wake_by_ref(&self) {
///         for waker in &self.0 {
///             waker.wake_by_ref();
///         }
///     }
/// }
/// ```
pub trait Wake: Send + Sync + Clone {
    /// Wake up the task associated with this waker, consuming the waker. When
    /// converted into a waker handle, this method is invoked whenever
    /// [`Waker::wake`] is called.
    ///
    /// By default, this delegates to [`Wake::wake_by_ref`], but can be
    /// overridden if a more efficient owned implementation is possible.
    fn wake(self) {
        self.wake_by_ref();
    }

    /// Wake up the task associated with this waker, consuming the waker. When
    /// converted into a waker handle, this method is invoked whenever
    /// [`Waker::wake_by_ref`] is called.
    fn wake_by_ref(&self);

    /// Convert this into a [`Waker`] handle.
    fn into_waker(self) -> Waker {
        // There's a fair bit of magic going on here, so watch out. There are
        // two possible implementations for this function, and which one we
        // invoke is decided at compile time based on the memory size of `Self`.
        //
        // When the size of `Self` is less than or equal to pointer size, we can
        // avoid allocations altogether by treating the data pointer used in the
        // waker vtable as the waker itself.
        //
        // If `Self` is larger than a pointer, then we take the more obvious
        // approach of putting the waker on the heap and passing around a
        // pointer to it.
        //
        // The pointer-size optimization is extremely useful when you want to
        // combine your waker implementation with things like `Arc`, which is
        // already pointer sized. With this approach, such wakers automatically
        // use the best possible implementation as the arc pointer is
        // essentially being passed around directly with no indirection without
        // any extra effort from the implementer.

        /// Convert a wake into a [`RawWaker`] handle.
        fn create_raw_waker<W: Wake>(wake: W) -> RawWaker {
            if mem::size_of::<W>() <= mem::size_of::<*const ()>() {
                create_thin(wake)
            } else {
                create_boxed(wake)
            }
        }

        /// Convert a wake into a [`RawWaker`] handle by allocating a box.
        ///
        /// This is the easier implementation to understand. We create a data
        /// pointer by moving self into a box and then getting its raw pointer.
        fn create_boxed<W: Wake>(wake: W) -> RawWaker {
            RawWaker::new(
                Box::into_raw(Box::new(wake)) as *const (),
                &RawWakerVTable::new(
                    |data| unsafe {
                        create_raw_waker((&*(data as *const W)).clone())
                    },
                    |data| unsafe {
                        Box::from_raw(data as *mut W).wake();
                    },
                    |data| unsafe {
                        (&*(data as *const W)).wake_by_ref();
                    },
                    |data| unsafe {
                        Box::from_raw(data as *mut W);
                    },
                ),
            )
        }

        /// Convert a wake into a [`RawWaker`] handle by transmuting into a data
        /// pointer.
        ///
        /// This is the trickier implementation, where we treat the data pointer
        /// as a plain `usize` and store the bits of self in it.
        fn create_thin<W: Wake>(wake: W) -> RawWaker {
            let mut data = ptr::null();

            // The following code will unleash the kraken if this invariant
            // isn't upheld.
            debug_assert!(mem::size_of::<W>() <= mem::size_of_val(&data));

            // The size of `W` might be _smaller_ than a pointer, so we can't
            // simply transmute here as that would potentially read off the end
            // of `wake`. Instead, we copy from `wake` to `data` (not the
            // _target_ of `data`, which has no meaning to us).
            unsafe {
                ptr::copy_nonoverlapping(
                    &wake as *const W,
                    &mut data as *mut *const () as *mut W,
                    1,
                );
            }

            // We moved `wake` into `data`, so make sure we don't keep the old
            // copy around (there can be only one!).
            mem::forget(wake);

            RawWaker::new(
                data,
                &RawWakerVTable::new(
                    |data| unsafe {
                        create_raw_waker((&*(&data as *const *const () as *const W)).clone())
                    },
                    |data| unsafe {
                        mem::transmute_copy::<_, W>(&data).wake();
                    },
                    |data| unsafe {
                        (&*(&data as *const *const () as *const W)).wake_by_ref();
                    },
                    |data| unsafe {
                        mem::transmute_copy::<_, W>(&data);
                    },
                ),
            )
        }

        unsafe { Waker::from_raw(create_raw_waker(self)) }
    }
}

impl Wake for std::thread::Thread {
    fn wake_by_ref(&self) {
        self.unpark();
    }
}

/// Create a waker from a closure.
///
/// # Examples
///
/// ```
/// let waker = wakeful::waker_fn(move || {
///     println!("time for work!");
/// });
///
/// waker.wake();
/// ```
pub fn waker_fn(f: impl Fn() + Send + Sync + 'static) -> Waker {
    struct Impl<F>(Arc<F>);

    impl<F> Clone for Impl<F> {
        fn clone(&self) -> Self {
            Impl(self.0.clone())
        }
    }

    impl<F: Fn() + Send + Sync + 'static> Wake for Impl<F> {
        fn wake_by_ref(&self) {
            (self.0)()
        }
    }

    Impl(Arc::new(f)).into_waker()
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::sync::{
        atomic::{AtomicUsize, Ordering},
        Arc,
    };

    #[test]
    fn zero_sized_impl() {
        static WOKE: AtomicUsize = AtomicUsize::new(0);

        #[derive(Clone)]
        struct Impl;

        impl Wake for Impl {
            fn wake_by_ref(&self) {
                WOKE.fetch_add(1, Ordering::SeqCst);
            }
        }

        let waker = Impl.into_waker();
        waker.wake_by_ref();
        assert_eq!(WOKE.load(Ordering::SeqCst), 1);

        waker.clone().wake();
        assert_eq!(WOKE.load(Ordering::SeqCst), 2);
    }

    #[test]
    fn ptr_sized_impl() {
        #[derive(Clone, Default)]
        struct Impl(Arc<AtomicUsize>);

        impl Wake for Impl {
            fn wake_by_ref(&self) {
                self.0.fetch_add(1, Ordering::SeqCst);
            }
        }

        let woke = Arc::new(AtomicUsize::new(0));

        let waker = Impl(woke.clone()).into_waker();
        waker.wake_by_ref();
        assert_eq!(woke.load(Ordering::SeqCst), 1);

        waker.clone().wake();
        assert_eq!(woke.load(Ordering::SeqCst), 2);
    }

    #[test]
    fn bigger_than_ptr_sized_impl() {
        #[derive(Clone)]
        struct Impl(Arc<AtomicUsize>, usize);

        impl Wake for Impl {
            fn wake_by_ref(&self) {
                self.0.fetch_add(1, Ordering::SeqCst);
            }
        }

        let woke = Arc::new(AtomicUsize::new(0));

        let waker = Impl(woke.clone(), 0).into_waker();
        waker.wake_by_ref();
        assert_eq!(woke.load(Ordering::SeqCst), 1);

        waker.clone().wake();
        assert_eq!(woke.load(Ordering::SeqCst), 2);
    }
}