waker_fn/
lib.rs

1//! Convert closures into wakers.
2//!
3//! A [`Waker`] is just a fancy callback. This crate converts regular closures into wakers.
4
5#![no_std]
6#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
7
8extern crate alloc;
9
10use alloc::sync::Arc;
11use core::mem::{self, ManuallyDrop};
12use core::task::{RawWaker, RawWakerVTable, Waker};
13
14/// Converts a closure into a [`Waker`].
15///
16/// The closure gets called every time the waker is woken.
17///
18/// # Examples
19///
20/// ```
21/// use waker_fn::waker_fn;
22///
23/// let waker = waker_fn(|| println!("woken"));
24///
25/// waker.wake_by_ref(); // Prints "woken".
26/// waker.wake();        // Prints "woken".
27/// ```
28pub fn waker_fn<F: Fn() + Send + Sync + 'static>(f: F) -> Waker {
29    let raw = Arc::into_raw(Arc::new(f)) as *const ();
30    let vtable = &Helper::<F>::VTABLE;
31    unsafe { Waker::from_raw(RawWaker::new(raw, vtable)) }
32}
33
34struct Helper<F>(F);
35
36impl<F: Fn() + Send + Sync + 'static> Helper<F> {
37    const VTABLE: RawWakerVTable = RawWakerVTable::new(
38        Self::clone_waker,
39        Self::wake,
40        Self::wake_by_ref,
41        Self::drop_waker,
42    );
43
44    unsafe fn clone_waker(ptr: *const ()) -> RawWaker {
45        let arc = ManuallyDrop::new(Arc::from_raw(ptr as *const F));
46        mem::forget(arc.clone());
47        RawWaker::new(ptr, &Self::VTABLE)
48    }
49
50    unsafe fn wake(ptr: *const ()) {
51        let arc = Arc::from_raw(ptr as *const F);
52        (arc)();
53    }
54
55    unsafe fn wake_by_ref(ptr: *const ()) {
56        let arc = ManuallyDrop::new(Arc::from_raw(ptr as *const F));
57        (arc)();
58    }
59
60    unsafe fn drop_waker(ptr: *const ()) {
61        drop(Arc::from_raw(ptr as *const F));
62    }
63}