local_waker/lib.rs
1//! A synchronization primitive for thread-local task wakeup.
2//!
3//! See docs for [`LocalWaker`].
4
5#![no_std]
6#![deny(rust_2018_idioms, nonstandard_style)]
7#![warn(future_incompatible, missing_docs)]
8
9use core::{cell::Cell, fmt, marker::PhantomData, task::Waker};
10
11/// A synchronization primitive for task wakeup.
12///
13/// Sometimes the task interested in a given event will change over time. A `LocalWaker` can
14/// coordinate concurrent notifications with the consumer, potentially "updating" the underlying
15/// task to wake up. This is useful in scenarios where a computation completes in another task and
16/// wants to notify the consumer, but the consumer is in the process of being migrated to a new
17/// logical task.
18///
19/// Consumers should call [`register`] before checking the result of a computation and producers
20/// should call [`wake`] after producing the computation (this differs from the usual `thread::park`
21/// pattern). It is also permitted for [`wake`] to be called _before_ [`register`]. This results in
22/// a no-op.
23///
24/// A single `LocalWaker` may be reused for any number of calls to [`register`] or [`wake`].
25///
26/// [`register`]: LocalWaker::register
27/// [`wake`]: LocalWaker::wake
28#[derive(Default)]
29pub struct LocalWaker {
30 pub(crate) waker: Cell<Option<Waker>>,
31 // mark LocalWaker as a !Send type.
32 _phantom: PhantomData<*const ()>,
33}
34
35impl LocalWaker {
36 /// Creates a new, empty `LocalWaker`.
37 pub fn new() -> Self {
38 LocalWaker::default()
39 }
40
41 /// Registers the waker to be notified on calls to `wake`.
42 ///
43 /// Returns `true` if waker was registered before.
44 #[inline]
45 pub fn register(&self, waker: &Waker) -> bool {
46 let last_waker = self.waker.replace(Some(waker.clone()));
47 last_waker.is_some()
48 }
49
50 /// Calls `wake` on the last `Waker` passed to `register`.
51 ///
52 /// If `register` has not been called yet, then this does nothing.
53 #[inline]
54 pub fn wake(&self) {
55 if let Some(waker) = self.take() {
56 waker.wake();
57 }
58 }
59
60 /// Returns the last `Waker` passed to `register`, so that the user can wake it.
61 ///
62 /// If a waker has not been registered, this returns `None`.
63 #[inline]
64 pub fn take(&self) -> Option<Waker> {
65 self.waker.take()
66 }
67}
68
69impl fmt::Debug for LocalWaker {
70 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71 write!(f, "LocalWaker")
72 }
73}