#![allow(clippy::needless_return)]
#[macro_export]
macro_rules! throw {
($($arg:tt)*) => {
panic!($($arg),*)
};
}
#[macro_export]
macro_rules! try_catch {
(try $try_block:block catch ($err:ident) $catch_block:block) => {
let original_hook = std::panic::take_hook();
std::panic::set_hook(Box::new(|_| {
// Do nothing
}));
match std::panic::catch_unwind(|| $try_block) {
Err(e) => {
if let Some(&$err) = e.downcast_ref::<&str>() {
$catch_block
} else {
unreachable!();
}
}
Ok(v) => v,
}
std::panic::set_hook(original_hook);
};
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn divide_by_zero() {
fn divide(x: u32, y: u32) -> u32 {
if y == 0 {
throw!("y cannot be zero");
}
return x / y;
}
try_catch! {
try {
let _ = divide(10, 0);
unreachable!("divide should always throw an exception (panic)");
} catch (e) {
assert_eq!(e, "y cannot be zero");
}
};
}
}