1use core::convert::Infallible;
2use core::ops::ControlFlow;
3
4type Residual<T> = <T as Try>::TryType<Infallible>;
5
6mod sealed {
7 use super::NeverShortCircuit;
8 pub trait Sealed {}
9
10 impl<T> Sealed for Option<T> {}
11 impl<T, E> Sealed for Result<T, E> {}
12 impl<T> Sealed for NeverShortCircuit<T> {}
13}
14
15pub trait Try: sealed::Sealed {
16 type Output;
17 type TryType<T>;
18
19 fn from_element<ELM>(e: ELM) -> Self::TryType<ELM>;
20 fn from_residual<T>(residual: Residual<Self>) -> Self::TryType<T>;
21 fn branch(self) -> ControlFlow<Residual<Self>, Self::Output>;
22}
23
24
25macro_rules! try_impl {
26 (
27 $T: ident < T $(, $($generics: tt),* )? >,
28 $success:ident ($output:ident),
29 $fail: ident $(($err:ident))?
30 ) => {
31 impl<T $(, $($generics)*)?> Try for $T<T $(, $($generics)*)?> {
32 type Output = T;
33 type TryType<TT> = $T<TT $(, $($generics)* )?>;
34
35 #[inline(always)]
36 fn from_element<ELM>(e: ELM) -> Self::TryType<ELM> {
37 $success(e)
38 }
39
40 #[inline(always)]
41 fn from_residual<TT>(residual: Residual<Self>) -> Self::TryType<TT> {
42 match residual {
43 $success(infallible) => match infallible {},
44 $fail$(($err))? => {$fail$(($err))?}
45 }
46 }
47
48 #[inline(always)]
49 fn branch(self) -> ControlFlow<Residual<Self>, Self::Output> {
50 match self {
51 $success($output) => ControlFlow::Continue($output),
52 $fail$(($err))? => ControlFlow::Break($fail$(($err))?)
53 }
54 }
55 }
56 };
57}
58
59try_impl! {
60 Option<T>, Some(out), None
61}
62try_impl! {
63 Result<T, E>, Ok(out), Err(err)
64}
65
66
67pub(crate) struct NeverShortCircuit<T>(pub T);
68
69impl<T> NeverShortCircuit<T> {
70 #[inline(always)]
71 pub fn wrap_fn<Arg>(mut f: impl FnMut(Arg) -> T) -> impl FnMut(Arg) -> NeverShortCircuit<T> {
72 move |arg| NeverShortCircuit(f(arg))
73 }
74}
75
76impl<T> Try for NeverShortCircuit<T> {
77 type Output = T;
78 type TryType<TT> = TT;
79
80 #[inline(always)]
81 fn from_element<ELM>(e: ELM) -> Self::TryType<ELM> { e }
82
83 #[inline(always)]
84 fn from_residual<TT>(infallible: Residual<Self>) -> Self::TryType<TT> {
85 match infallible {}
86 }
87
88 #[inline(always)]
89 fn branch(self) -> ControlFlow<Residual<Self>, Self::Output> {
90 ControlFlow::Continue(self.0)
91 }
92}