/// This code was built on @scottmcm 's PR for the new Try trait design. #![feature(try_trait_v2)] #![feature(control_flow_enum)] #![feature(never_type)] #![allow(dead_code)] use std::ops::{ControlFlow, FromResidual, Try}; enum MyFlow { Stay(S), Up(T), } struct MyFlowResidual(T); impl Try for MyFlow { type Ok = S; type Residual = MyFlowResidual; fn from_output(v: ::Ok) -> Self { Self::Stay(v) } fn branch(self) -> ControlFlow<::Residual, ::Ok> { match self { Self::Stay(it) => ControlFlow::Continue(it), Self::Up(payload) => ControlFlow::Break(MyFlowResidual(payload)), } } } impl FromResidual for MyFlow { fn from_residual(x: ::Residual) -> Self { MyFlow::Up(x.0.into()) } } impl FromResidual> for Result { fn from_residual(r: MyFlowResidual) -> Self { Ok(r.0) } } impl FromResidual> for Result { fn from_residual(x: MyFlow) -> Self { match x { MyFlow::Up(it) => Ok(it), // I thought that this match would be exaustive without this line below (because of `!` in x), but the compiler complained to me. MyFlow::Stay(_) => panic!(), } } } /// Early Exit for the happy case. trait Lift { type Break; type Continue; fn lift(self) -> MyFlow; } impl Lift for Result { type Break = T; type Continue = E; fn lift(self) -> MyFlow { match self { Ok(t) => MyFlow::Up(t), Err(e) => MyFlow::Stay(e), } } } fn main() { println!("Hello, world!"); } fn test() -> Result { a().lift()?; b().lift()?; c().lift()?; Err("end".to_string()) } fn a() -> Result { Err(()) } fn b() -> Result { Ok(42) } fn c() -> Result { Ok(7) } #[cfg(test)] mod tests { use crate::test; #[test] fn it_works() { assert_eq!(test(), Ok(42)); } }