#[must_use = "Without using the `Command` it doesn't do anything. You should execute it through `run!()` or `run_loop!()`."]
pub enum Command<R, T> {
Give(T),
Return(R),
Break,
Continue,
}
#[macro_export]
macro_rules! defer {
(return $val:expr) => { $crate::Command::Return($val) };
(return) => { defer!(return ()) };
(break) => { $crate::Command::Break };
(continue) => { $crate::Command::Continue };
($val:expr) => { $crate::Command::Give($val) };
() => { defer!(()) }
}
#[macro_export]
macro_rules! run {
($command:expr) => {
match $command {
$crate::Command::Give(x) => x,
$crate::Command::Return(x) => return x,
_ => panic!("\
Using loop-dependent `Command` variants without loop mode enabled. Consider using \
`control_loop` instead.
"),
}
}
}
#[macro_export]
macro_rules! run_loop {
($command:expr) => {
match $command {
$crate::Command::Give(x) => x,
$crate::Command::Return(x) => return x,
$crate::Command::Break => break,
$crate::Command::Continue => continue,
}
}
}
#[cfg(test)]
mod tests {
#[test]
fn loop_break() {
let mut x = true;
loop {
run_loop!(defer!(break));
x = false;
}
assert!(x);
}
#[test]
fn loop_continue() {
let mut x = true;
for _ in 0..100 {
assert!(x);
run_loop!(defer!(continue));
x = false;
}
}
#[test]
#[allow(unused_assignments)]
fn return_early() {
let x = false;
run!(defer!(return));
assert!(x);
}
#[test]
#[allow(unused_assignments)]
fn store_ctrl() {
assert!((|| {
let mut x = defer!(return false);
x = defer!(return true);
run!(x);
unreachable!();
})());
}
#[test]
fn direct_value() {
assert!(run!(defer!(true)));
assert_eq!(run!(defer!()), ());
}
}