Created
February 24, 2021 16:16
-
-
Save dbofmmbt/ef1b476f776e87bdda3a8fab35912172 to your computer and use it in GitHub Desktop.
Example of new possibility with the Try trait v2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// 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)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment