Skip to content

Instantly share code, notes, and snippets.

@dbofmmbt
Created February 24, 2021 16:16
Show Gist options
  • Select an option

  • Save dbofmmbt/ef1b476f776e87bdda3a8fab35912172 to your computer and use it in GitHub Desktop.

Select an option

Save dbofmmbt/ef1b476f776e87bdda3a8fab35912172 to your computer and use it in GitHub Desktop.

Revisions

  1. dbofmmbt created this gist Feb 24, 2021.
    107 changes: 107 additions & 0 deletions main.rs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,107 @@
    /// 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<T, S = ()> {
    Stay(S),
    Up(T),
    }

    struct MyFlowResidual<T>(T);

    impl<T, S> Try for MyFlow<T, S> {
    type Ok = S;
    type Residual = MyFlowResidual<T>;

    fn from_output(v: <Self as Try>::Ok) -> Self {
    Self::Stay(v)
    }

    fn branch(self) -> ControlFlow<<Self as Try>::Residual, <Self as Try>::Ok> {
    match self {
    Self::Stay(it) => ControlFlow::Continue(it),
    Self::Up(payload) => ControlFlow::Break(MyFlowResidual(payload)),
    }
    }
    }

    impl<T, S> FromResidual for MyFlow<T, S> {
    fn from_residual(x: <Self as Try>::Residual) -> Self {
    MyFlow::Up(x.0.into())
    }
    }

    impl<T, E> FromResidual<MyFlowResidual<T>> for Result<T, E> {
    fn from_residual(r: MyFlowResidual<T>) -> Self {
    Ok(r.0)
    }
    }

    impl<T, E> FromResidual<MyFlow<T, !>> for Result<T, E> {
    fn from_residual(x: MyFlow<T, !>) -> 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<Self::Break, Self::Continue>;
    }

    impl<T, E> Lift for Result<T, E> {
    type Break = T;
    type Continue = E;

    fn lift(self) -> MyFlow<Self::Break, Self::Continue> {
    match self {
    Ok(t) => MyFlow::Up(t),
    Err(e) => MyFlow::Stay(e),
    }
    }
    }

    fn main() {
    println!("Hello, world!");
    }

    fn test() -> Result<usize, String> {
    a().lift()?;
    b().lift()?;
    c().lift()?;

    Err("end".to_string())
    }

    fn a() -> Result<usize, ()> {
    Err(())
    }

    fn b() -> Result<usize, ()> {
    Ok(42)
    }

    fn c() -> Result<usize, ()> {
    Ok(7)
    }

    #[cfg(test)]
    mod tests {
    use crate::test;

    #[test]
    fn it_works() {
    assert_eq!(test(), Ok(42));
    }
    }