wookie/
lib.rs

1//! Async test/bench toolkit including single stepping executors. No-std compatible.
2//!
3//! The primary user interface is the [`wookie!`] macro, which wraps a
4//! future with an executor and pins it on the stack.:
5//!
6//! ```
7//! use core::task::Poll;
8//! use wookie::wookie;
9//! wookie!(future: async { true });
10//! assert_eq!(future.poll(), Poll::Ready(true));
11//!
12//! // you can also just give a variable name if you have one:
13//! let future = async { true };
14//! wookie!(future);
15//! assert_eq!(future.poll(), Poll::Ready(true));
16//!
17//! // we can find out about the state of wakers any time:
18//! assert_eq!(future.cloned(), 0);
19//! assert_eq!(future.dropped(), 0);
20//! assert_eq!(future.woken(), 0);
21//! // or equivalently...
22//! future.stats().assert(0, 0, 0);
23//! ```
24//!
25//! If you do not have access to an allocator, you can use the [`local!`]
26//! macro instead, however, polling is unsafe and you must be very careful to
27//! maintain the invariants described in the `safety` sections of the
28//! [`Local`] methods.
29//!
30//! ```
31//! use core::task::Poll;
32//! use wookie::local;
33//! local!(future: async { true });
34//! assert_eq!(unsafe { future.poll() }, Poll::Ready(true));
35//!
36//! // you can also just give a variable name if you have one:
37//! let future = async { true };
38//! local!(future);
39//! assert_eq!(unsafe { future.poll() }, Poll::Ready(true));
40//!
41//! // we can find out about the state of wakers any time:
42//! assert_eq!(future.cloned(), 0);
43//! assert_eq!(future.dropped(), 0);
44//! assert_eq!(future.woken(), 0);
45//! // or equivalently...
46//! future.stats().assert(0, 0, 0);
47//! ```
48//!
49//! For benchmarking, we provide the [`dummy!`] macro, whose waker does
50//! nothing, but quite quickly.
51//!
52//! ```
53//! use core::task::Poll;
54//! use wookie::dummy;
55//! dummy!(future: async { true });
56//! assert_eq!(future.poll(), Poll::Ready(true));
57//! ```
58//!
59//! We have [`assert_pending!`] and [`assert_ready!`] to save some
60//! typing in assertions:
61//!
62//! ```
63//! use wookie::*;
64//! use core::task::Poll;
65//! assert_pending!(Poll::<i32>::Pending); // pass
66//! // assert_pending!(Poll::Ready(())); // would fail
67//!
68//! // With 1 arg, assert_ready will returning the unwrapped value.
69//! assert_eq!(42, assert_ready!(Poll::Ready(42)));
70//! // assert_ready!(Poll::<i32>::Pending); // would fail
71//!
72//! // With 2 args, it's like [`assert_eq`] on the unwrapped value.
73//! assert_ready!(42, Poll::Ready(42));
74//! // assert_ready!(Poll::<i32>::Pending); // would fail
75//! // assert_ready!(42, Poll::Ready(420)); // would fail
76//! ```
77//!
78//! ## Features
79//!
80//! Default features: `alloc`.
81//!
82//! * `alloc` - enables use of an allocator. Required by [`Wookie`] / [`wookie!`].
83#![no_std]
84
85#[cfg(feature="alloc")]
86extern crate alloc;
87
88mod dummy;
89#[doc(inline)]
90pub use dummy::*;
91
92mod local;
93pub use local::*;
94
95#[cfg(feature="alloc")]
96mod wookie;
97#[cfg(feature="alloc")]
98pub use crate::wookie::*;
99
100/// Statistics of waker activity for [`Wookie`] or [`Local`].
101pub struct Stats {
102    /// The number of times a Waker has been cloned. Usually equivalent to the
103    /// number of times a waker has been set.
104    pub cloned:  u16,
105    /// The number of times a Waker has been dropped. Note that `wake` causes
106    /// this count to be incremented as it takes ownership of the Waker.
107    pub dropped: u16,
108    /// The number of times a Waker has been woken. Includes calls to both
109    /// `wake` and `wake_by_ref`.
110    pub woken:   u16,
111}
112
113impl Stats {
114    /// The number of live wakers, i.e. `cloned - dropped`.
115    #[inline(always)]
116    pub fn live(&self) -> u16 { self.cloned - self.dropped }
117
118    /// Assert that `cloned`, `dropped` and `woken` are the provided values.
119    pub fn assert(&self, cloned: u16, dropped: u16, woken: u16) {
120        assert_eq!((cloned, dropped, woken), (self.cloned, self.dropped, self.woken));
121    }
122}
123
124#[macro_export]
125/// Asserts that a [`Poll`] is a [`Poll::Pending`]
126///
127/// ## Examples
128///
129/// ```
130/// use wookie::assert_pending;
131/// use core::task::Poll;
132/// assert_pending!(Poll::<i32>::Pending); // pass
133/// // assert_pending!(Poll::Ready(())); // would fail
134/// ```
135macro_rules! assert_pending {
136    ($expr:expr) => {
137        if let Poll::Ready(r) = $expr {
138            panic!("Expected Poll::Pending, got Poll::Ready({:?})!", r);
139        }
140    }
141}
142
143#[macro_export]
144/// Asserts that a [`Poll`] is a [`Poll::Ready`]
145///
146/// ## Examples
147///
148/// ```
149/// use wookie::assert_ready;
150/// use core::task::Poll;
151///
152/// // With 1 arg, just checks for ready, returning the unwrapped value.
153/// assert_eq!(42, assert_ready!(Poll::Ready(42)));
154/// // assert_ready!(Poll::<i32>::Pending); // would fail
155///
156/// // With 2 args, it's like [`assert_eq`] on the unwrapped value.
157/// assert_ready!(42, Poll::Ready(42));
158/// // assert_ready!(Poll::<i32>::Pending); // would fail
159/// // assert_ready!(42, Poll::Ready(420)); // would fail
160/// ```
161macro_rules! assert_ready {
162    ($expr:expr) => {
163        match $expr {
164            Poll::Ready(r) => r,
165            Poll::Pending => panic!("Expected Poll::Ready, got Poll::Pending!"),
166        }
167    };
168    ($expected:expr, $expr:expr) => {
169        match $expr {
170            Poll::Ready(r) => assert_eq!($expected, r),
171            Poll::Pending => panic!("Expected Poll::Ready, got Poll::Pending!"),
172        }
173    }
174}