pub const BREAKVAL_IN_NOT_LOOP :&str = "\
error[E0571]: `break` with value is invalid in a `for` or `while` loop. \
Use Break instead of BreakVal in `twist!` expression \
or use `twist!` with the `-val` flag.";
pub const BREAK_WITHOUT_VAL :&str = "\
error[E0308]: mismatched types. \
Breaking without a value when using `twist -val`. \
Use BreakVal instead of Break, or use `twist!` without `-val`";
pub const BAD_BREAKVAL_TYPE :&str = "\
error[E0308]: mismatched types. \
Looping::BreakVal has a value type different from the loop it's breaking from. \
Check you're breaking from the right loop, or use Break instead of BreakVal.";
#[allow(non_camel_case_types)]
pub enum Error0571__Tried_to_break_with_value_using_twist_without_val_flag__Use_Break_instead_of_BreakVal_or_add_the_dash_val_flag_to_twist{}
pub type BreakValError = Error0571__Tried_to_break_with_value_using_twist_without_val_flag__Use_Break_instead_of_BreakVal_or_add_the_dash_val_flag_to_twist;
#[derive(PartialEq, Debug, Clone)]
pub enum Looping<T, B> {
Resume(T),
Break {
label: Option<usize>
},
BreakVal {
label: Option<usize>,
value: B
},
Continue {
label: Option<usize>
}
}
#[macro_export]
macro_rules! __impl_twist {
( @parse-map [$($bk:tt)*] [$($bv:tt)*] ($e:expr => $f:expr) ) => {
$crate::twist! { @single [$($bk)*] [$($bv)*] ($crate::Judge::into_moral($e).resume_or_else($f)) }
};
( @parse-map [$($bk:tt)*] [$($bv:tt)*] ($e:expr) ) => {
$crate::twist! { @single [$($bk)*] [$($bv)*] ($e) }
};
( @parse-map [$($bk:tt)*] [$($bv:tt)*] ($($tokens:tt)*) ) => {
compile_error!(concat!(
"Expected either `$e` or `$e => $f` on the right-hand side, got: ",
stringify!($($tokens)*)))
};
( @label-parse ($($flag:tt)*) [ | $($rest:tt)* ] -> $($l:tt)* ) => {
$crate::__impl_twist! { @label-expr ($($flag)*) [$($rest)*] -> $($l)* }
};
( @label-parse ($($flag:tt)*) [ $token:tt $($rest:tt)* ] -> $($l:tt)* ) => {
$crate::__impl_twist! { @label-parse ($($flag)*) [$($rest)*] -> $($l)* $token }
};
( @label-parse ($($flag:tt)*) [ ] -> $($rest:tt)* ) => {
compile_error!("Missing `|` separator after labels in `twist! -label` macro invocation. Add labels, or use `twist!` without `-label`.")
};
( @label-expr ($($flag:tt)*) [ $e:expr ] -> $($l:tt)* ) => {
$crate::__impl_twist! { @label-labels ($($flag)*) 0, [$($l)* ,] -> [() ()] $e }
};
( @label-expr ($($flag:tt)*) [ $e:expr => $f:expr ] -> $($l:tt)* ) => {
$crate::__impl_twist! { @label-labels ($($flag)*) 0, [$($l)* ,] -> [() ()] $crate::Judge::into_moral($e).resume_or_else($f) }
};
( @label-expr ($($flag:tt)*) [ $($rest:tt)* ] $($whatever:tt)* ) => {
compile_error!(concat!("This failed to parse as an expression: ", stringify!($($rest)*)))
};
( @label-labels ($($flag:tt)*) $count:expr, [] -> [($($bk:tt)*) ($($bv:tt)*)] $e:expr ) => {
$crate::__impl_twist! { @label-box ($($flag)*) ($($bk)*) ($($bv)*) $e }
};
( @label-labels ($($flag:tt)*) $count:expr, [ $label:lifetime : $type:ty , $($rest:tt)* ] -> [($($bk:tt)*) ($($bv:tt)*)] $e:expr ) => {
$crate::__impl_twist! { @label-labels ($($flag)*) $count + 1, [$($rest)*] -> [($($bk)*) ( $($bv)* ($count, $label, $type) )] $e }
};
( @label-labels ($($flag:tt)*) $count:expr, [ $label:lifetime , $($rest:tt)* ] -> [($($bk:tt)*) ($($bv:tt)*)] $e:expr ) => {
$crate::__impl_twist! { @label-labels ($($flag)*) $count + 1, [$($rest)*] -> [( $($bk)* ($count, $label) ) ($($bv)*)] $e }
};
( @label-labels ($($flag:tt)*) $count:expr, [ $($rest:tt)* ] -> [($($bk:tt)*) ($($bv:tt)*)] $e:expr ) => {
compile_error!(concat!("Bad label syntax: ", stringify!($($rest)*)))
};
( @label-box ( ("unbox") -> $($flag:tt)* ) ($($bk:tt)*) ($($bv:tt)*) $e:expr ) => {
twist! { @boxed ($($flag)*) ($($bk)*) [ () ($($bv)*) ] $e }
};
( @label-box ( ("pass") -> $($flag:tt)* ) ($($bk:tt)*) ($($bv:tt)*) $e:expr ) => {
twist! { @boxed ($($flag)*) ($($bk)*) [ ($($bv)*) () ] $e }
};
}
#[macro_export]
macro_rules! twist {
( -label $($tokens:tt)* ) => {
$crate::__impl_twist! { @label-parse (("pass") -> ("break") () ()) [$($tokens)*] -> }
};
( -val $type:ty, -label $($tokens:tt)* ) => {
$crate::__impl_twist! { @label-parse (("pass") -> () ($type) ()) [$($tokens)*] -> }
};
( -box -label $($tokens:tt)* ) => {
$crate::__impl_twist! { @label-parse (("unbox") -> ("break") () ()) [$($tokens)*] -> }
};
( -box -val $type:ty, -label $($tokens:tt)* ) => {
$crate::__impl_twist! { @label-parse (("unbox") -> () () ($type)) [$($tokens)*] -> }
};
( @boxed ( ($($bk:tt)?) ($($bv:ty)?) ($($bx:ty)?) ) ( $( ($c:expr, $l:lifetime) )* ) [ ($( ($count:expr, $label:lifetime, $type:ty) )*) ($( ($bcount:expr, $blabel:lifetime, $btype:ty) )*) ] $e:expr
) => {
match $e {
$crate::Looping::Resume(v) => v,
$( $crate::Looping::Break { label: None } => { $crate::__unit!($bk); break; }, )?
$( $crate::Looping::Break { label: None } => { $crate::__unit!($bv); panic!("{}", $crate::BREAK_WITHOUT_VAL) }, )?
$( $crate::Looping::Break { label: None } => { $crate::__unit!($bx); panic!("{}", $crate::BREAK_WITHOUT_VAL) }, )?
$crate::Looping::Break { label: Some(l) } => {
match l {
$( x if x == $c => { break $l; }, )*
_ => panic!("Invalid label index in Looping::Break object."),
};
},
$crate::Looping::Continue { label: None } => continue,
$crate::Looping::Continue { label: Some(l) } => {
match l {
$( x if x == $c => { continue $l; }, )*
$( x if x == $count => { continue $label; }, )*
$( x if x == $bcount => { continue $blabel; }, )*
_ => panic!("Invalid label index in Looping::Continue object."),
};
},
$( $crate::Looping::BreakVal { label: None, .. } => { $crate::__unit!($bk); panic!("{}", $crate::BREAKVAL_IN_NOT_LOOP); }, )?
$( $crate::Looping::BreakVal { label: None, value: v } => { $crate::__unit!($bv); break v; }, )?
$( $crate::Looping::BreakVal { label: None, value: v } => { match v.downcast::<$bx>() {
Ok(v) => { break *v; },
_ => panic!("At label None with type {}: {}", stringify!($bx), $crate::BAD_BREAKVAL_TYPE),
};
}, )?
$crate::Looping::BreakVal $(::<_, $bv> )? { label: Some(l), value: v } => {
match l {
$( x if x == $count => { break $label v; }, )*
$( x if x == $bcount => { match v.downcast::<$btype>() {
Ok(v) => { break $blabel *v; }, _ => panic!("At label {} with type {}: {}", stringify!($blabel), stringify!($btype), $crate::BAD_BREAKVAL_TYPE),
}
}, )*
_ => panic!("Invalid label index in Looping::BreakVal object."),
};
},
};
};
( @single
[$( ($breaker:tt) ($($label:lifetime)?) )?] [$( ($breakval:tt) ($($vlabel:lifetime)?) )?] ($e:expr)
) => {
match $e {
$( _ if $crate::__bool!($breaker) => unreachable!(), $crate::Looping::Resume::<_, $crate::BreakValError>(v) => v, )?
$( _ if $crate::__bool!($breakval) => unreachable!(), $crate::Looping::Resume(v) => v, )?
$( _ if $crate::__bool!($breaker) => unreachable!(), $crate::Looping::Break { .. } => break $($label)?, )?
$( _ if $crate::__bool!($breakval) => unreachable!(), $crate::Looping::Break { .. } => panic!("{}", $crate::BREAK_WITHOUT_VAL), )?
$crate::Looping::Continue { .. } => continue $($($label)?)? $($($vlabel)?)?,
$( _ if $crate::__bool!($breaker) => unreachable!(), $crate::Looping::BreakVal { .. } => panic!("{}", $crate::BREAKVAL_IN_NOT_LOOP), )?
$( _ if $crate::__bool!($breakval) => unreachable!(), $crate::Looping::BreakVal { value: v, .. } => break $($vlabel)? v, )?
}
};
( -with $l:lifetime | $($tokens:tt)* ) => {
$crate::__impl_twist! { @parse-map [("break") ($l)] [] ($($tokens)*) }
};
( -val -with $l:lifetime | $($tokens:tt)* ) => {
$crate::__impl_twist! { @parse-map [] [("breakval") ($l)] ($($tokens)*) }
};
( -val $($tokens:tt)* ) => {
$crate::__impl_twist! { @parse-map [] [("breakval") ()] ($($tokens)*) }
};
( $($tokens:tt)* ) => {
$crate::__impl_twist! { @parse-map [("break") ()] [] ($($tokens)*) }
};
}
#[macro_export]
macro_rules! next_if {
( $c:expr $( , $($b:tt)* )? ) => {
$crate::twist! {
if $c {
{ $($($b)*)? };
$crate::next!()
} else {
$crate::resume!(())
}
}
};
( let $p:pat = $e:expr $( , $($b:tt)* )? ) => {
$crate::twist! {
if let $p = $e {
{ $($($b)*)? };
$crate::next!()
} else {
$crate::resume!(())
}
}
};
}
#[macro_export]
macro_rules! last_if {
( $c:expr $( , $($b:tt)* )? ) => {
$crate::twist! {
if $c {
{ $($($b)*)? };
$crate::last!()
} else {
$crate::resume!(())
}
}
};
( let $p:pat = $e:expr $( , $($b:tt)* )? ) => {
$crate::twist! {
if let $p = $e {
{ $($($b)*)? };
$crate::last!()
} else {
$crate::resume!(())
}
}
};
}