s2n_quic_core/
macros.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4/// Asserts that a boolean expression is true at runtime, only if debug_assertions are enabled.
5///
6/// Otherwise, the compiler is told to assume that the expression is always true and can perform
7/// additional optimizations.
8///
9/// # Safety
10///
11/// The caller _must_ ensure this condition is never possible, otherwise the compiler
12/// may optimize based on false assumptions and behave incorrectly.
13#[macro_export]
14macro_rules! assume {
15    (false) => {
16        assume!(false, "assumption failed")
17    };
18    (false $(, $fmtarg:expr)* $(,)?) => {{
19        if cfg!(not(debug_assertions)) {
20            core::hint::unreachable_unchecked();
21        }
22
23        panic!($($fmtarg),*)
24    }};
25    ($cond:expr) => {
26        $crate::assume!($cond, "assumption failed: {}", stringify!($cond));
27    };
28    ($cond:expr $(, $fmtarg:expr)* $(,)?) => {
29        let v = $cond;
30
31        debug_assert!(v $(, $fmtarg)*);
32        if cfg!(not(debug_assertions)) && !v {
33            core::hint::unreachable_unchecked();
34        }
35    };
36}
37
38#[macro_export]
39#[doc(hidden)]
40macro_rules! __tracing_noop__ {
41    ($($fmt:tt)*) => {};
42}
43
44#[doc(hidden)]
45#[cfg(feature = "branch-tracing")]
46pub use tracing::trace as _trace_branch;
47
48#[doc(hidden)]
49#[cfg(not(feature = "branch-tracing"))]
50pub use __tracing_noop__ as _trace_branch;
51
52/// Traces a branch value if the `branch-tracing` feature is enabled. Otherwise it is a no-op.
53#[macro_export]
54macro_rules! branch {
55    ($cond:expr) => {{
56        let result = $cond;
57        $crate::macros::_trace_branch!(
58            branch = stringify!($cond),
59            result,
60            file = file!(),
61            line = line!(),
62        );
63        result
64    }};
65    ($cond:expr, $outcome:expr) => {
66        $crate::branch!($cond, stringify!($cond), stringify!($outcome))
67    };
68    ($cond:expr, $branch:expr, $outcome:expr) => {{
69        let result = $cond;
70        if result {
71            $crate::macros::_trace_branch!(
72                branch = $branch,
73                result,
74                file = file!(),
75                line = line!(),
76            );
77        } else {
78            $crate::macros::_trace_branch!(
79                branch = $branch,
80                result,
81                outcome = $outcome,
82                file = file!(),
83                line = line!(),
84            );
85        }
86        result
87    }};
88}
89
90#[macro_export]
91macro_rules! ready {
92    ($expr:expr) => {
93        match $expr {
94            ::core::task::Poll::Pending => {
95                $crate::branch!(false, stringify!($expr), "return Poll::Pending");
96                return ::core::task::Poll::Pending;
97            }
98            ::core::task::Poll::Ready(v) => {
99                $crate::branch!(true, stringify!($expr), "");
100                v
101            }
102        }
103    };
104}
105
106/// Checks that the first argument is true, otherwise returns the second value
107#[macro_export]
108macro_rules! ensure {
109    (let $pat:pat = $expr:expr, continue) => {
110        let $pat = $expr else {
111            $crate::branch!(false, stringify!(let $pat = $expr), stringify!(continue));
112            continue;
113        };
114        $crate::branch!(true, stringify!(let $pat = $expr), "");
115    };
116    (let $pat:pat = $expr:expr, break $($ret:expr)?) => {
117        let $pat = $expr else {
118            $crate::branch!(false, stringify!(let $pat = $expr), stringify!(break $($ret)?));
119            break $($ret)?;
120        };
121        $crate::branch!(true, stringify!(let $pat = $expr), "");
122    };
123    (let $pat:pat = $expr:expr, return $($ret:expr)?) => {
124        let $pat = $expr else {
125            $crate::branch!(false, stringify!(let $pat = $expr), stringify!(return $($ret)?));
126            return $($ret)?;
127        };
128        $crate::branch!(true, stringify!(let $pat = $expr), "");
129    };
130    (let $pat:pat = $expr:expr $(, $ret:expr)?) => {
131        $crate::ensure!(let $pat = $expr, return $($ret)?)
132    };
133    ($cond:expr, continue) => {
134        if !$crate::branch!($cond, continue) {
135            continue;
136        }
137    };
138    ($cond:expr, break $($expr:expr)?) => {
139        if !$crate::branch!($cond, break $($expr)?) {
140            break $($expr)?;
141        }
142    };
143    ($cond:expr, return $($expr:expr)?) => {
144        if !$crate::branch!($cond, return $($expr)?) {
145            return $($expr)?;
146        }
147    };
148    ($cond:expr $(, $ret:expr)?) => {
149        $crate::ensure!($cond, return $($ret)?);
150    };
151}
152
153/// Implements a future that wraps `T::poll_ready` and yields after ready
154macro_rules! impl_ready_future {
155    ($name:ident, $fut:ident, $output:ty) => {
156        pub struct $fut<'a, T: ?Sized>(&'a mut T);
157
158        impl<'a, T: $name> core::future::Future for $fut<'a, T> {
159            type Output = $output;
160
161            #[inline]
162            fn poll(
163                mut self: core::pin::Pin<&mut Self>,
164                cx: &mut core::task::Context,
165            ) -> core::task::Poll<Self::Output> {
166                self.0.poll_ready(cx)
167            }
168        }
169    };
170}