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
//! Async test/bench toolkit including single stepping executors. No-std compatible.
//!
//! The primary user interface is the [`wookie!`] macro, which wraps a
//! future with an executor and pins it on the stack.:
//!
//! ```
//! use core::task::Poll;
//! use wookie::wookie;
//! wookie!(future: async { true });
//! assert_eq!(future.poll(), Poll::Ready(true));
//!
//! // you can also just give a variable name if you have one:
//! let future = async { true };
//! wookie!(future);
//! assert_eq!(future.poll(), Poll::Ready(true));
//!
//! // we can find out about the state of wakers any time:
//! assert_eq!(future.cloned(), 0);
//! assert_eq!(future.dropped(), 0);
//! assert_eq!(future.woken(), 0);
//! // or equivalently...
//! future.stats().assert(0, 0, 0);
//! ```
//!
//! If you do not have access to an allocator, you can use the [`local!`]
//! macro instead, however, polling is unsafe and you must be very careful to
//! maintain the invariants described in the `safety` sections of the
//! [`Local`] methods.
//!
//! ```
//! use core::task::Poll;
//! use wookie::local;
//! local!(future: async { true });
//! assert_eq!(unsafe { future.poll() }, Poll::Ready(true));
//!
//! // you can also just give a variable name if you have one:
//! let future = async { true };
//! local!(future);
//! assert_eq!(unsafe { future.poll() }, Poll::Ready(true));
//!
//! // we can find out about the state of wakers any time:
//! assert_eq!(future.cloned(), 0);
//! assert_eq!(future.dropped(), 0);
//! assert_eq!(future.woken(), 0);
//! // or equivalently...
//! future.stats().assert(0, 0, 0);
//! ```
//!
//! For benchmarking, we provide the [`dummy!`] macro, whose waker does
//! nothing, but quite quickly.
//!
//! ```
//! use core::task::Poll;
//! use wookie::dummy;
//! dummy!(future: async { true });
//! assert_eq!(future.poll(), Poll::Ready(true));
//! ```
//!
//! We have [`assert_pending!`] and [`assert_ready!`] to save some
//! typing in assertions:
//!
//! ```
//! use wookie::*;
//! use core::task::Poll;
//! assert_pending!(Poll::<i32>::Pending); // pass
//! // assert_pending!(Poll::Ready(())); // would fail
//!
//! // With 1 arg, assert_ready will returning the unwrapped value.
//! assert_eq!(42, assert_ready!(Poll::Ready(42)));
//! // assert_ready!(Poll::<i32>::Pending); // would fail
//!
//! // With 2 args, it's like [`assert_eq`] on the unwrapped value.
//! assert_ready!(42, Poll::Ready(42));
//! // assert_ready!(Poll::<i32>::Pending); // would fail
//! // assert_ready!(42, Poll::Ready(420)); // would fail
//! ```
//!
//! ## Features
//!
//! Default features: `alloc`.
//!
//! * `alloc` - enables use of an allocator. Required by [`Wookie`] / [`wookie!`].
#![no_std]

#[cfg(feature="alloc")]
extern crate alloc;

mod dummy;
#[doc(inline)]
pub use dummy::*;

mod local;
pub use local::*;

#[cfg(feature="alloc")]
mod wookie;
#[cfg(feature="alloc")]
pub use crate::wookie::*;

/// Statistics of waker activity for [`Wookie`] or [`Local`].
pub struct Stats {
    /// The number of times a Waker has been cloned. Usually equivalent to the
    /// number of times a waker has been set.
    pub cloned:  u16,
    /// The number of times a Waker has been dropped. Note that `wake` causes
    /// this count to be incremented as it takes ownership of the Waker.
    pub dropped: u16,
    /// The number of times a Waker has been woken. Includes calls to both
    /// `wake` and `wake_by_ref`.
    pub woken:   u16,
}

impl Stats {
    /// The number of live wakers, i.e. `cloned - dropped`.
    #[inline(always)]
    pub fn live(&self) -> u16 { self.cloned - self.dropped }

    /// Assert that `cloned`, `dropped` and `woken` are the provided values.
    pub fn assert(&self, cloned: u16, dropped: u16, woken: u16) {
        assert_eq!((cloned, dropped, woken), (self.cloned, self.dropped, self.woken));
    }
}

#[macro_export]
/// Asserts that a [`Poll`] is a [`Poll::Pending`]
///
/// ## Examples
///
/// ```
/// use wookie::assert_pending;
/// use core::task::Poll;
/// assert_pending!(Poll::<i32>::Pending); // pass
/// // assert_pending!(Poll::Ready(())); // would fail
/// ```
macro_rules! assert_pending {
    ($expr:expr) => {
        if let Poll::Ready(r) = $expr {
            panic!("Expected Poll::Pending, got Poll::Ready({:?})!", r);
        }
    }
}

#[macro_export]
/// Asserts that a [`Poll`] is a [`Poll::Ready`]
///
/// ## Examples
///
/// ```
/// use wookie::assert_ready;
/// use core::task::Poll;
///
/// // With 1 arg, just checks for ready, returning the unwrapped value.
/// assert_eq!(42, assert_ready!(Poll::Ready(42)));
/// // assert_ready!(Poll::<i32>::Pending); // would fail
///
/// // With 2 args, it's like [`assert_eq`] on the unwrapped value.
/// assert_ready!(42, Poll::Ready(42));
/// // assert_ready!(Poll::<i32>::Pending); // would fail
/// // assert_ready!(42, Poll::Ready(420)); // would fail
/// ```
macro_rules! assert_ready {
    ($expr:expr) => {
        match $expr {
            Poll::Ready(r) => r,
            Poll::Pending => panic!("Expected Poll::Ready, got Poll::Pending!"),
        }
    };
    ($expected:expr, $expr:expr) => {
        match $expr {
            Poll::Ready(r) => assert_eq!($expected, r),
            Poll::Pending => panic!("Expected Poll::Ready, got Poll::Pending!"),
        }
    }
}