#[macro_export]
macro_rules! unwrap_or_warn {
($opt:expr, $default:expr, $context:expr) => {
match $opt {
Some(v) => v,
None => {
::tracing::warn!(
context = $context,
location = concat!(file!(), ":", line!()),
"Unexpected None — using default (was unwrap)"
);
$default
}
}
};
}
#[macro_export]
macro_rules! result_or_warn {
($result:expr, $default:expr, $context:expr) => {
match $result {
Ok(v) => v,
Err(e) => {
::tracing::warn!(
error = %e,
context = $context,
location = concat!(file!(), ":", line!()),
"Unexpected error — using default (was unwrap)"
);
$default
}
}
};
}
#[macro_export]
macro_rules! parse_or_warn {
($s:expr, $ty:ty, $default:expr, $context:expr) => {
match $s.parse::<$ty>() {
Ok(v) => v,
Err(e) => {
::tracing::warn!(
input = %$s,
error = %e,
context = $context,
location = concat!(file!(), ":", line!()),
"Parse failed — using default (was unwrap)"
);
$default
}
}
};
}
#[macro_export]
macro_rules! expect_or_error {
($opt:expr, $default:expr, $msg:expr) => {
match $opt {
Some(v) => v,
None => {
::tracing::error!(
expectation = $msg,
location = concat!(file!(), ":", line!()),
"EXPECT FAILED — invariant violated, using fallback (was expect/unwrap)"
);
$default
}
}
};
}
#[macro_export]
macro_rules! expect_result_or_error {
($result:expr, $default:expr, $msg:expr) => {
match $result {
Ok(v) => v,
Err(e) => {
::tracing::error!(
error = %e,
expectation = $msg,
location = concat!(file!(), ":", line!()),
"EXPECT FAILED — invariant violated, using fallback (was expect/unwrap)"
);
$default
}
}
};
}
#[cfg(test)]
mod tests {
#[test]
fn unwrap_or_warn_some() {
let val: Option<i32> = Some(42);
let result = unwrap_or_warn!(val, 0, "test");
assert_eq!(result, 42);
}
#[test]
fn unwrap_or_warn_none() {
let val: Option<i32> = None;
let result = unwrap_or_warn!(val, -1, "test fallback");
assert_eq!(result, -1);
}
#[test]
fn unwrap_or_warn_string_option() {
let val: Option<String> = None;
let result = unwrap_or_warn!(val, String::from("default"), "username lookup");
assert_eq!(result, "default");
}
#[test]
fn result_or_warn_ok() {
let val: Result<i32, String> = Ok(42);
let result = result_or_warn!(val, 0, "test");
assert_eq!(result, 42);
}
#[test]
fn result_or_warn_err() {
let val: Result<i32, String> = Err("broken".into());
let result = result_or_warn!(val, -1, "test fallback");
assert_eq!(result, -1);
}
#[test]
fn result_or_warn_io_error() {
let val: Result<String, std::io::Error> =
Err(std::io::Error::new(std::io::ErrorKind::NotFound, "gone"));
let result = result_or_warn!(val, String::from("fallback"), "file read");
assert_eq!(result, "fallback");
}
#[test]
fn parse_or_warn_success() {
let port = parse_or_warn!("3000", u16, 8080, "port config");
assert_eq!(port, 3000);
}
#[test]
fn parse_or_warn_failure() {
let port = parse_or_warn!("not_a_number", u16, 8080, "port config");
assert_eq!(port, 8080);
}
#[test]
fn parse_or_warn_float() {
let val = parse_or_warn!("3.14", f64, 0.0, "threshold");
assert!((val - 3.14).abs() < f64::EPSILON);
}
#[test]
fn parse_or_warn_empty_string() {
let val = parse_or_warn!("", i32, 0, "empty input");
assert_eq!(val, 0);
}
#[test]
fn expect_or_error_some() {
let val: Option<&str> = Some("hello");
let result = expect_or_error!(val, "fallback", "must exist");
assert_eq!(result, "hello");
}
#[test]
fn expect_or_error_none() {
let val: Option<&str> = None;
let result = expect_or_error!(val, "fallback", "config key required");
assert_eq!(result, "fallback");
}
#[test]
fn expect_result_or_error_ok() {
let val: Result<i32, String> = Ok(100);
let result = expect_result_or_error!(val, 0, "must succeed");
assert_eq!(result, 100);
}
#[test]
fn expect_result_or_error_err() {
let val: Result<i32, String> = Err("db crashed".into());
let result = expect_result_or_error!(val, 0, "db must be available");
assert_eq!(result, 0);
}
#[test]
fn real_pattern_option_chain() {
let config: Option<Vec<String>> = Some(vec!["a".into(), "b".into()]);
let first = unwrap_or_warn!(
config.as_ref().and_then(|v| v.first().cloned()),
String::from("default"),
"first config value"
);
assert_eq!(first, "a");
}
#[test]
fn macros_compile_in_if_block() {
if true {
let _ = unwrap_or_warn!(Some(1), 0, "test");
let _ = result_or_warn!(Ok::<i32, String>(1), 0, "test");
let _ = parse_or_warn!("1", i32, 0, "test");
let _ = expect_or_error!(Some(1), 0, "test");
let _ = expect_result_or_error!(Ok::<i32, String>(1), 0, "test");
}
}
#[test]
fn macros_with_mut_binding() {
let mut count = unwrap_or_warn!(Some(0i32), -1, "initial count");
count += 1;
assert_eq!(count, 1);
}
}