Skip to main content Skip to main content
Pigweed's logo Pigweed
code_xml
  1. Home
  2. Reference
  3. Rust
  4. src
  5. pw_assert/pw_assert.rs

pw_assert/
pw_assert.rs

1// Copyright 2025 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14#![no_std]
15
16//! # pw_assert
17//!
18//! `pw_assert` provides crash-safe assert and panic macros that route to a
19//! configured backend. This is designed for embedded systems where standard
20//! library panics might not be suitable, or where specific logging/recovery
21//! behavior is needed.
22//!
23//! The macros in this crate are designed to be drop-in replacements for
24//! `core::panic!`, `core::assert!`, etc., and delegate to backend macros:
25//! - [`panic!`] and [`debug_panic!`] -> `panic_backend!`
26//! - [`assert!`] and [`debug_assert!`] -> `assert_unary_backend!`
27//! - [`eq!`], [`ne!`], [`debug_eq!`], and [`debug_ne!`] -> `assert_binary_backend!`
28//!
29//! # Example
30//!
31//! ```no_run
32//! pw_assert::assert!(42 == 16, "Stack start is not aligned");
33//!
34//! pw_assert::panic!("Unhandled interrupt: irq={}", 16 as u32);
35//!
36//! pw_assert::debug_assert!(1 == 0);
37//!
38//! pw_assert::debug_panic!("Next monotonic tick overflow");
39//! ```
40
41// Re-export backend macros for use by facade macros.
42#[doc(hidden)]
43pub mod __private {
44    pub use pw_assert_backend::{assert_binary_backend, assert_unary_backend, panic_backend};
45}
46
47/// Panics unconditionally.
48///
49/// This macro delegates to the backend macro `panic_backend!`.
50///
51/// # Examples
52///
53/// ```no_run
54/// pw_assert::panic!("Something went terribly wrong!");
55///
56/// pw_assert::panic!("Error code: {}", 42 as i32);
57/// ```
58#[macro_export]
59macro_rules! panic {
60    ($($arg:tt)*) => {
61        $crate::__private::panic_backend!($($arg)*)
62    };
63}
64
65/// Panics unconditionally when debug_assertions are enabled
66///
67/// If `debug_assertions` are enabled, this behaves exactly like [`panic!`]
68/// (delegating to `panic_backend!`).
69/// If `debug_assertions` are disabled, this macro is a no-op.
70///
71/// `debug_assertions` can be enabled by setting this bazel label to `True`
72/// `@pigweed//pw_assert/rust:debug_assertions`.
73///
74/// # Examples
75///
76/// ```no_run
77/// pw_assert::debug_panic!("This should never happen in debug mode.");
78/// ```
79#[macro_export]
80#[cfg(feature = "debug_assertions")]
81macro_rules! debug_panic {
82    ($($arg:tt)*) => {
83        $crate::__private::panic_backend!($($arg)*)
84    };
85}
86
87/// Panics unconditionally when debug_assertions are enabled.
88#[macro_export]
89#[cfg(not(feature = "debug_assertions"))]
90macro_rules! debug_panic {
91    ($format_string:literal $(, $args:expr)* $(,)?) => {{
92        #[allow(clippy::unnecessary_cast)]
93        if false {
94            let _: &str = $format_string;
95            $(let _ = $args;)*
96        }
97    }};
98}
99
100/// Asserts that a condition is true.
101///
102/// If the condition evaluates to `false`, this macro delegates to the backend
103/// macro `assert_unary_backend!`.
104///
105/// # Examples
106///
107/// ```no_run
108/// let x = 5;
109/// pw_assert::assert!(x > 0);
110/// pw_assert::assert!(x == 5, "x should be 5, but was {}", x as i32);
111/// ```
112#[macro_export]
113macro_rules! assert {
114    ($condition:expr $(,)?) => {{
115        $crate::__private::assert_unary_backend!($condition);
116    }};
117
118    ($condition:expr, $($args:expr),* $(,)?) => {{
119        $crate::__private::assert_unary_backend!($condition, $($args),*);
120    }};
121}
122
123/// Asserts that a condition is true when debug_assertions are enabled.
124///
125/// If `debug_assertions` are enabled, this behaves exactly like [`assert!`]
126/// (delegating to `assert_unary_backend!` if the condition evaluates to `false`).
127/// If `debug_assertions` are disabled, this macro is a no-op.
128///
129/// `debug_assertions` can be enabled by setting this bazel label to `True`
130/// `@pigweed//pw_assert/rust:debug_assertions`.
131///
132/// # Examples
133///
134/// ```no_run
135/// let x = 5;
136/// pw_assert::debug_assert!(x == 5);
137/// ```
138#[macro_export]
139#[cfg(feature = "debug_assertions")]
140macro_rules! debug_assert {
141    ($condition:expr $(,)?) => {{
142        $crate::__private::assert_unary_backend!($condition);
143    }};
144
145    ($condition:expr, $($args:expr),* $(,)?) => {{
146        $crate::__private::assert_unary_backend!($condition, $($args),*);
147    }};
148}
149
150/// Asserts that a condition is true when debug_assertions are enabled.
151#[macro_export]
152#[cfg(not(feature = "debug_assertions"))]
153macro_rules! debug_assert {
154    ($condition:expr $(, $format_string:literal $(, $args:expr)*)? $(,)?) => {{
155        #[allow(clippy::unnecessary_cast)]
156        if false {
157            let _: bool = $condition;
158            $(
159                let _: &str = $format_string;
160                $(let _ = $args;)*
161            )?
162        }
163    }};
164}
165
166/// Asserts that two expressions are equal (equivalent to `assert_eq!`).
167///
168/// If the expressions are not equal, this macro delegates to the backend macro
169/// `assert_binary_backend!`.
170///
171/// Note that depending on the backend, both expressions may need to be cast
172/// expressions (e.g., `x as i32`).
173///
174/// # Examples
175///
176/// ```no_run
177/// let x = 5;
178/// pw_assert::eq!(x as i32, 5 as i32);
179/// pw_assert::eq!(x as i32, 5 as i32, "x should be 5");
180/// ```
181#[macro_export]
182macro_rules! eq {
183    ($lhs:expr, $rhs:expr $(,)?) => {{
184        $crate::__private::assert_binary_backend!($lhs, ==, $rhs);
185    }};
186
187    ($lhs:expr, $rhs:expr, $($args:expr),* $(,)?) => {{
188        $crate::__private::assert_binary_backend!($lhs, ==, $rhs, $($args),*);
189    }};
190}
191
192/// Asserts that two expressions are not equal (equivalent to `assert_ne!`).
193///
194/// If the expressions are equal, this macro delegates to the backend macro
195/// `assert_binary_backend!`.
196///
197/// Note that depending on the backend, both expressions may need to be cast
198/// expressions (e.g., `x as i32`).
199///
200/// # Examples
201///
202/// ```no_run
203/// let x = 5;
204/// pw_assert::ne!(x as i32, 6 as i32);
205/// pw_assert::ne!(x as i32, 6 as i32, "x should not be 6");
206/// ```
207#[macro_export]
208macro_rules! ne {
209    ($lhs:expr, $rhs:expr $(,)?) => {{
210        $crate::__private::assert_binary_backend!($lhs, !=, $rhs);
211    }};
212
213    ($lhs:expr, $rhs:expr, $($args:expr),* $(,)?) => {{
214        $crate::__private::assert_binary_backend!($lhs, !=, $rhs, $($args),*);
215    }};
216}
217
218/// Asserts that two expressions are equal when debug_assertions are enabled.
219///
220/// If `debug_assertions` are enabled, this behaves exactly like [`eq!`].
221/// If `debug_assertions` are disabled, this macro is a no-op.
222///
223/// `debug_assertions` can be enabled by setting this bazel label to `True`
224/// `@pigweed//pw_assert/rust:debug_assertions`.
225///
226/// # Examples
227///
228/// ```no_run
229/// let x = 5;
230/// pw_assert::debug_eq!(x as i32, 5 as i32);
231/// ```
232#[macro_export]
233#[cfg(feature = "debug_assertions")]
234macro_rules! debug_eq {
235    ($lhs:expr, $rhs:expr $(,)?) => {{
236        $crate::__private::assert_binary_backend!($lhs, ==, $rhs);
237    }};
238
239    ($lhs:expr, $rhs:expr, $($args:expr),* $(,)?) => {{
240        $crate::__private::assert_binary_backend!($lhs, ==, $rhs, $($args),*);
241    }};
242}
243
244/// Asserts that two expressions are equal when debug_assertions are enabled.
245#[macro_export]
246#[cfg(not(feature = "debug_assertions"))]
247macro_rules! debug_eq {
248    ($lhs:expr, $rhs:expr $(, $format_string:literal $(, $args:expr)*)? $(,)?) => {{
249        #[allow(clippy::unnecessary_cast)]
250        if false {
251            let _ = $lhs == $rhs;
252            $(
253                let _: &str = $format_string;
254                $(let _ = $args;)*
255            )?
256        }
257    }};
258}
259
260/// Asserts that two expressions are not equal when debug_assertions are enabled.
261///
262/// If `debug_assertions` are enabled, this behaves exactly like [`ne!`].
263/// If `debug_assertions` are disabled, this macro is a no-op.
264///
265/// `debug_assertions` can be enabled by setting this bazel label to `True`
266/// `@pigweed//pw_assert/rust:debug_assertions`.
267///
268/// # Examples
269///
270/// ```no_run
271/// let x = 5;
272/// pw_assert::debug_ne!(x as i32, 6 as i32);
273/// ```
274#[macro_export]
275#[cfg(feature = "debug_assertions")]
276macro_rules! debug_ne {
277    ($lhs:expr, $rhs:expr $(,)?) => {{
278        $crate::__private::assert_binary_backend!($lhs, !=, $rhs);
279    }};
280
281    ($lhs:expr, $rhs:expr, $($args:expr),* $(,)?) => {{
282        $crate::__private::assert_binary_backend!($lhs, !=, $rhs, $($args),*);
283    }};
284}
285
286/// Asserts that two expressions are not equal when debug_assertions are enabled.
287#[macro_export]
288#[cfg(not(feature = "debug_assertions"))]
289macro_rules! debug_ne {
290    ($lhs:expr, $rhs:expr $(, $format_string:literal $(, $args:expr)*)? $(,)?) => {{
291        #[allow(clippy::unnecessary_cast)]
292        if false {
293            let _ = $lhs != $rhs;
294            $(
295                let _: &str = $format_string;
296                $(let _ = $args;)*
297            )?
298        }
299    }};
300}