use std::ops::ControlFlow;
use private::Sealed;
mod private {
pub trait Sealed {}
}
pub trait BoolFlow: Sealed {
fn r#break(self) -> ControlFlow<()>;
fn break_with<T>(self, value: T) -> ControlFlow<T>;
fn break_lazy<T>(self, value: impl FnOnce() -> T) -> ControlFlow<T>;
fn r#continue(self) -> ControlFlow<()>;
fn continue_or<T>(self, value: T) -> ControlFlow<T>;
fn continue_or_else<T>(self, f: impl FnOnce() -> T) -> ControlFlow<T>;
}
impl Sealed for bool {}
impl BoolFlow for bool {
fn r#break(self) -> ControlFlow<()> {
match self {
true => ControlFlow::Break(()),
false => ControlFlow::Continue(()),
}
}
fn break_with<T>(self, value: T) -> ControlFlow<T> {
match self {
true => ControlFlow::Break(value),
false => ControlFlow::Continue(()),
}
}
fn break_lazy<T>(self, f: impl FnOnce() -> T) -> ControlFlow<T> {
match self {
true => ControlFlow::Break(f()),
false => ControlFlow::Continue(()),
}
}
fn r#continue(self) -> ControlFlow<()> {
match self {
true => ControlFlow::Continue(()),
false => ControlFlow::Break(()),
}
}
fn continue_or<T>(self, value: T) -> ControlFlow<T> {
match self {
true => ControlFlow::Continue(()),
false => ControlFlow::Break(value),
}
}
fn continue_or_else<T>(self, f: impl FnOnce() -> T) -> ControlFlow<T> {
match self {
true => ControlFlow::Continue(()),
false => ControlFlow::Break(f()),
}
}
}
#[cfg(test)]
mod tests {
use std::ops::ControlFlow;
use crate::BoolFlow;
#[test]
fn break_works() {
fn r#break(condition: bool) -> ControlFlow<()> {
BoolFlow::r#break(condition)?;
ControlFlow::Continue(())
}
fn break_with(condition: bool) -> ControlFlow<bool> {
condition.r#break_with(true)?;
ControlFlow::Break(false)
}
fn break_lazy(condition: bool) -> ControlFlow<bool> {
condition.r#break_lazy(|| true)?;
ControlFlow::Break(false)
}
assert_eq!(r#break(true), ControlFlow::Break(()));
assert_eq!(break_with(true), ControlFlow::Break(true));
assert_eq!(break_lazy(true), ControlFlow::Break(true));
assert_eq!(r#break(false), ControlFlow::Continue(()));
assert_eq!(break_with(false), ControlFlow::Break(false));
assert_eq!(break_lazy(false), ControlFlow::Break(false));
}
#[test]
fn continue_works() {
fn should_continue(condition: bool, continued: &mut bool) -> ControlFlow<()> {
BoolFlow::r#continue(condition)?;
*continued = true;
ControlFlow::Break(())
}
fn test_continue_or(condition: bool) -> ControlFlow<bool> {
condition.continue_or(true)?;
ControlFlow::Break(false)
}
fn test_continue_or_else(condition: bool) -> ControlFlow<bool> {
condition.continue_or_else(|| true)?;
ControlFlow::Break(false)
}
{
let mut continued = false;
should_continue(true, &mut continued);
assert!(continued);
}
assert_eq!(test_continue_or(true), ControlFlow::Break(false));
assert_eq!(test_continue_or_else(true), ControlFlow::Break(false));
{
let mut continued = false;
should_continue(false, &mut continued);
assert!(!continued);
}
assert_eq!(test_continue_or(false), ControlFlow::Break(true));
assert_eq!(test_continue_or_else(false), ControlFlow::Break(true));
}
}