use super::result::ExecResult;
#[derive(Debug, Clone)]
pub enum ControlFlow {
Normal(ExecResult),
Break { levels: usize, result: ExecResult },
Continue { levels: usize, result: ExecResult },
Return { value: ExecResult },
Exit { code: i64 },
}
impl ControlFlow {
pub fn ok(result: ExecResult) -> Self {
ControlFlow::Normal(result)
}
pub fn break_one() -> Self {
ControlFlow::Break {
levels: 1,
result: ExecResult::success(""),
}
}
pub fn break_n(n: usize) -> Self {
ControlFlow::Break {
levels: n,
result: ExecResult::success(""),
}
}
pub fn continue_one() -> Self {
ControlFlow::Continue {
levels: 1,
result: ExecResult::success(""),
}
}
pub fn continue_n(n: usize) -> Self {
ControlFlow::Continue {
levels: n,
result: ExecResult::success(""),
}
}
pub fn return_value(value: ExecResult) -> Self {
ControlFlow::Return { value }
}
pub fn exit_code(code: i64) -> Self {
ControlFlow::Exit { code }
}
pub fn is_normal(&self) -> bool {
matches!(self, ControlFlow::Normal(_))
}
pub fn into_result(self) -> Option<ExecResult> {
match self {
ControlFlow::Normal(r) => Some(r),
_ => None,
}
}
pub fn decrement_level(&mut self) -> bool {
match self {
ControlFlow::Break { levels, .. } | ControlFlow::Continue { levels, .. } => {
if *levels <= 1 {
true
} else {
*levels -= 1;
false
}
}
_ => false,
}
}
}
impl Default for ControlFlow {
fn default() -> Self {
ControlFlow::Normal(ExecResult::success(""))
}
}
impl From<ExecResult> for ControlFlow {
fn from(result: ExecResult) -> Self {
ControlFlow::Normal(result)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_normal_flow() {
let flow = ControlFlow::ok(ExecResult::success("test"));
assert!(flow.is_normal());
}
#[test]
fn test_break_decrement() {
let mut flow = ControlFlow::break_n(3);
assert!(!flow.decrement_level()); assert!(!flow.decrement_level()); assert!(flow.decrement_level()); }
#[test]
fn test_continue_decrement() {
let mut flow = ControlFlow::continue_n(2);
assert!(!flow.decrement_level()); assert!(flow.decrement_level()); }
#[test]
fn test_from_exec_result() {
let result = ExecResult::success("hello");
let flow: ControlFlow = result.into();
assert!(flow.is_normal());
}
}