xrpl_wasm_stdlib/host/
assert.rs

1//! Assertion macros for WASM environments.
2//!
3//! This module provides assertion macros that work in WASM environments by using
4//! the trace functions to emit readable error messages when assertions fail.
5
6use crate::host::trace::{DataRepr, trace_data, trace_num};
7
8/// Trait for numeric types that can be traced with trace_num
9pub trait NumericTrace {
10    fn trace_as_num(msg: &str, value: &Self);
11}
12
13/// Trace a value of any type.
14///
15/// This function handles different types of values:
16/// - For array types like [u8; N], it uses trace_data with hex representation
17/// - For other types, it falls back to a generic message
18pub fn trace_value<T>(msg: &str, value: &T) {
19    // Use trace_data as the default for all types
20    let data_ptr = value as *const T as *const u8;
21    let data_len = core::mem::size_of::<T>();
22    let data_slice = unsafe { core::slice::from_raw_parts(data_ptr, data_len) };
23    let _ = trace_data(msg, data_slice, DataRepr::AsHex);
24}
25
26/// Trace a numeric value.
27///
28/// This function is specifically for numeric types that implement NumericTrace.
29/// It uses trace_num to display the value.
30pub fn trace_numeric_value<T: NumericTrace>(msg: &str, value: &T) {
31    NumericTrace::trace_as_num(msg, value);
32}
33
34// Specialized implementations for numeric types
35macro_rules! impl_numeric_trace {
36    ($($t:ty),*) => {
37        $(
38            impl NumericTrace for $t {
39                #[inline]
40                fn trace_as_num(msg: &str, value: &$t) {
41                    let _ = trace_num(msg, *value as i64);
42                }
43            }
44        )*
45    }
46}
47
48// Implement for common numeric types
49impl_numeric_trace!(i8, i16, i32, i64, u8, u16, u32, u64);
50
51/// Asserts that two expressions are equal.
52///
53/// If the assertion fails, a trace message is emitted with the values of both expressions,
54/// and then the program panics.
55///
56/// # Examples
57///
58/// ```
59/// // This will pass
60/// assert_eq!(1, 1);
61///
62/// // This would fail and emit a trace message
63/// // assert_eq!(1, 2);
64/// ```
65#[macro_export]
66macro_rules! assert_eq {
67    ($left:expr, $right:expr) => {
68        {
69            let left_val = $left;
70            let right_val = $right;
71            if left_val != right_val {
72                let _ = $crate::host::trace::trace(concat!("Assertion failed: ", stringify!($left), " != ", stringify!($right)));
73                $crate::host::assert::trace_value("  left: ", &left_val);
74                $crate::host::assert::trace_value("  right: ", &right_val);
75                panic!("assertion failed: {} != {}", stringify!($left), stringify!($right));
76            }
77        }
78    };
79    ($left:expr, $right:expr, $($arg:tt)+) => {
80        {
81            let left_val = $left;
82            let right_val = $right;
83            if left_val != right_val {
84                let _ = $crate::host::trace::trace(concat!("Assertion failed: ", stringify!($left), " != ", stringify!($right)));
85                $crate::host::assert::trace_value("  left: ", &left_val);
86                $crate::host::assert::trace_value("  right: ", &right_val);
87                let _ = $crate::host::trace::trace("  message: (see panic message for details)");
88                panic!("assertion failed: {} != {}: {}", stringify!($left), stringify!($right), format_args!($($arg)+));
89            }
90        }
91    };
92}
93
94/// Asserts that a condition is true.
95///
96/// If the assertion fails, a trace message is emitted with the condition,
97/// and then the program panics.
98///
99/// # Examples
100///
101/// ```
102/// // This will pass
103/// assert!(true);
104///
105/// // This would fail and emit a trace message
106/// // assert!(false);
107/// ```
108#[macro_export]
109macro_rules! assert {
110    ($cond:expr) => {
111        if !$cond {
112            let _ = $crate::host::trace::trace(concat!("Assertion failed: ", stringify!($cond)));
113            panic!("assertion failed: {}", stringify!($cond));
114        }
115    };
116    ($cond:expr, $($arg:tt)+) => {
117        if !$cond {
118            let _ = $crate::host::trace::trace(concat!("Assertion failed: ", stringify!($cond)));
119            let _ = $crate::host::trace::trace("  message: (see panic message for details)");
120            panic!("assertion failed: {}: {}", stringify!($cond), format_args!($($arg)+));
121        }
122    };
123}
124
125/// Asserts that two expressions are not equal.
126///
127/// If the assertion fails, a trace message is emitted with the values of both expressions,
128/// and then the program panics.
129///
130/// # Examples
131///
132/// ```
133/// // This will pass
134/// assert_ne!(1, 2);
135///
136/// // This would fail and emit a trace message
137/// // assert_ne!(1, 1);
138/// ```
139#[macro_export]
140macro_rules! assert_ne {
141    ($left:expr, $right:expr) => {
142        {
143            let left_val = $left;
144            let right_val = $right;
145            if left_val == right_val {
146                let _ = $crate::host::trace::trace(concat!("Assertion failed: ", stringify!($left), " == ", stringify!($right)));
147                $crate::host::assert::trace_value("  value: ", &left_val);
148                panic!("assertion failed: {} == {}", stringify!($left), stringify!($right));
149            }
150        }
151    };
152    ($left:expr, $right:expr, $($arg:tt)+) => {
153        {
154            let left_val = $left;
155            let right_val = $right;
156            if left_val == right_val {
157                let _ = $crate::host::trace::trace(concat!("Assertion failed: ", stringify!($left), " == ", stringify!($right)));
158                $crate::host::assert::trace_value("  value: ", &left_val);
159                let _ = $crate::host::trace::trace("  message: (see panic message for details)");
160                panic!("assertion failed: {} == {}: {}", stringify!($left), stringify!($right), format_args!($($arg)+));
161            }
162        }
163    };
164
165}