noop_waker/lib.rs
1// MIT/Apache2 License
2
3//! A waker that does nothing when it is woken. Useful for "now or never" type scenarioes where a future is
4//! unlikely to be polled more than once, or for "spinning" executors.
5//!
6//! # Example
7//!
8//! A very inefficient implementation of the `block_on` function that polls the future over and over.
9//!
10//! ```
11//! use core::{future::Future, hint::spin_loop, task::{Context, Poll}};
12//! use futures_lite::future::poll_fn;
13//! use noop_waker::noop_waker;
14//!
15//! fn block_on<R>(f: impl Future<Output = R>) -> R {
16//! // pin the future to the stack
17//! futures_lite::pin!(f);
18//!
19//! // create the context
20//! let waker = noop_waker();
21//! let mut ctx = Context::from_waker(&waker);
22//!
23//! // poll future in a loop
24//! loop {
25//! match f.as_mut().poll(&mut ctx) {
26//! Poll::Ready(o) => return o,
27//! Poll::Pending => spin_loop(),
28//! }
29//! }
30//! }
31//!
32//! // this future returns pending 5 times before returning ready
33//!
34//! let mut counter = 0;
35//! let my_future = poll_fn(|ctx| {
36//! if counter < 5 {
37//! counter += 1;
38//! ctx.waker().wake_by_ref();
39//! Poll::Pending
40//! } else {
41//! Poll::Ready(7)
42//! }
43//! });
44//!
45//! assert_eq!(block_on(my_future), 7);
46//! ```
47
48#![no_std]
49#![warn(clippy::pedantic)]
50
51use core::{ptr, task::{Waker, RawWaker, RawWakerVTable}};
52
53/// The whole point. Returns a waker that does nothing.
54#[inline]
55#[must_use]
56pub fn noop_waker() -> Waker {
57 let raw = RawWaker::new(ptr::null(), &NOOP_WAKER_VTABLE);
58
59 // SAFETY: the contracts for RawWaker and RawWakerVTable are upheld
60 unsafe { Waker::from_raw(raw) }
61}
62
63const NOOP_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(noop_clone, noop, noop, noop);
64
65unsafe fn noop_clone(_p: *const ()) -> RawWaker {
66 // SAFETY: this retains all of the waker's resources, of which there are none
67 RawWaker::new(ptr::null(), &NOOP_WAKER_VTABLE)
68}
69
70unsafe fn noop(_p: *const ()) {}