claims/
assert_pending.rs

1/// Asserts that the expression matches a [`Poll::Pending`] variant.
2///
3/// ## Uses
4///
5/// Assertions are always checked in both debug and release builds, and cannot be disabled.
6/// See [`debug_assert_pending!`] for assertions that are not enabled in release builds by default.
7///
8/// ## Custom messages
9///
10/// This macro has a second form, where a custom panic message can be provided with or without
11/// arguments for formatting. See [`std::fmt`] for syntax for this form.
12///
13/// ## Examples
14///
15/// ```rust
16/// # #[macro_use] extern crate claims;
17/// # use std::task::Poll;
18/// # fn main() {
19/// let res: Poll<i32> = Poll::Pending;
20///
21/// assert_pending!(res);
22///
23/// // With a custom message
24/// assert_pending!(res, "Future is not ready yet");
25/// # }
26/// ```
27///
28/// A [`Poll::Pending`] variant will also be returned from this macro call:
29///
30/// ```rust
31/// # #[macro_use] extern crate claims;
32/// # use std::task::Poll;
33/// # fn main() {
34/// let res: Poll<i32> = Poll::Pending;
35///
36/// let value = assert_pending!(res);
37/// assert_eq!(value, Poll::Pending);
38/// # }
39/// ```
40///
41/// A [`Poll::Ready(_)`] variant will panic:
42///
43/// ```rust,should_panic
44/// # #[macro_use] extern crate claims;
45/// # use std::task::Poll;
46/// # fn main() {
47/// let res = Poll::Ready(42);
48///
49/// assert_pending!(res);  // Will panic
50/// # }
51/// ```
52///
53/// [`Poll::Ready(_)`]: https://doc.rust-lang.org/core/task/enum.Poll.html#variant.Ready
54/// [`Poll::Pending`]: https://doc.rust-lang.org/core/task/enum.Poll.html#variant.Pending
55/// [`std::fmt`]: https://doc.rust-lang.org/std/fmt/index.html
56/// [`debug_assert_pending!`]: crate::debug_assert_pending!
57#[macro_export]
58macro_rules! assert_pending {
59    ($cond:expr $(,)?) => {
60        match $cond {
61            pending @ ::core::task::Poll::Pending => pending,
62            ready @ ::core::task::Poll::Ready(_) => {
63                ::core::panic!("assertion failed, expected Pending, got {:?}", ready);
64            }
65        }
66    };
67    ($cond:expr, $($arg:tt)+) => {
68        match $cond {
69            pending @ ::core::task::Poll::Pending => pending,
70            ready @ ::core::task::Poll::Ready(_) => {
71                ::core::panic!("assertion failed, expected Pending, got {:?}: {}", ready, ::core::format_args!($($arg)+));
72            }
73        }
74    };
75}
76
77/// Asserts that the expression matches a [`Poll::Pending`] variant on debug builds.
78///
79/// This macro behaves the same as [`assert_pending!`] on debug builds. On release builds it is a
80/// no-op.
81///
82/// [`Poll::Pending`]: https://doc.rust-lang.org/core/task/enum.Poll.html#variant.Pending
83#[macro_export]
84macro_rules! debug_assert_pending {
85    ($($arg:tt)*) => {
86        #[allow(unused_must_use)]
87        #[cfg(debug_assertions)]
88        {
89            $crate::assert_pending!($($arg)*);
90        }
91    }
92}
93
94#[cfg(test)]
95mod tests {
96    use core::task::Poll::{Pending, Ready};
97
98    #[test]
99    fn pending() {
100        let _ = assert_pending!(Pending::<()>);
101    }
102
103    #[test]
104    #[should_panic(expected = "assertion failed, expected Pending, got Ready(())")]
105    fn not_pending() {
106        let _ = assert_pending!(Ready(()));
107    }
108
109    #[test]
110    #[should_panic(expected = "assertion failed, expected Pending, got Ready(()): foo")]
111    fn not_pending_custom_message() {
112        let _ = assert_pending!(Ready(()), "foo");
113    }
114
115    #[test]
116    #[cfg_attr(not(debug_assertions), ignore = "only run in debug mode")]
117    fn debug_pending() {
118        debug_assert_pending!(Pending::<()>);
119    }
120
121    #[test]
122    #[cfg_attr(not(debug_assertions), ignore = "only run in debug mode")]
123    #[should_panic(expected = "assertion failed, expected Pending, got Ready(())")]
124    fn debug_not_pending() {
125        debug_assert_pending!(Ready(()));
126    }
127
128    #[test]
129    #[cfg_attr(not(debug_assertions), ignore = "only run in debug mode")]
130    #[should_panic(expected = "assertion failed, expected Pending, got Ready(()): foo")]
131    fn debug_not_pending_custom_message() {
132        debug_assert_pending!(Ready(()), "foo");
133    }
134
135    #[test]
136    #[cfg_attr(debug_assertions, ignore = "only run in release mode")]
137    fn debug_release_not_pending() {
138        debug_assert_pending!(Ready(()));
139    }
140}