tiered_result/
try_trait.rs1use crate::{ClientResponse, FatalOrOk, FatalResult, TieredResult};
2use core::{
3    convert::Infallible,
4    ops::{ControlFlow, FromResidual, Try},
5};
6use nullable_result::NullableResult;
7
8pub struct Residual<F>(F);
9
10impl<T, E, F> Try for TieredResult<T, E, F> {
11    type Output = NullableResult<T, E>;
12    type Residual = Residual<F>;
13
14    fn from_output(output: Self::Output) -> Self {
15        match output {
16            NullableResult::Ok(item) => TieredResult::Ok(item),
17            NullableResult::Err(err) => TieredResult::Err(err),
18            NullableResult::Null => TieredResult::Null,
19        }
20    }
21
22    fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
23        use ControlFlow::*;
24        use NullableResult::*;
25
26        match self {
27            TieredResult::Ok(item) => Continue(Ok(item)),
28            TieredResult::Err(err) => Continue(Err(err)),
29            TieredResult::Null => Continue(Null),
30            TieredResult::Fatal(fatality) => Break(Residual(fatality)),
31        }
32    }
33}
34
35impl<T, E, F> FromResidual<Residual<F>> for TieredResult<T, E, F> {
36    fn from_residual(residual: Residual<F>) -> Self {
37        TieredResult::Fatal(residual.0)
38    }
39}
40
41impl<T, E1, E2, F> FromResidual<NullableResult<Infallible, E1>>
42    for TieredResult<T, E2, F>
43where
44    E1: Into<E2>,
45{
46    fn from_residual(residual: NullableResult<Infallible, E1>) -> Self {
47        match residual {
48            NullableResult::Ok(_) => unreachable!(),
49            NullableResult::Err(err) => TieredResult::Err(err.into()),
50            NullableResult::Null => TieredResult::Null,
51        }
52    }
53}
54
55impl<T, E1, E2, F> FromResidual<Result<Infallible, E1>>
56    for TieredResult<T, E2, F>
57where
58    E1: Into<E2>,
59{
60    fn from_residual(residual: Result<Infallible, E1>) -> Self {
61        match residual {
62            Ok(_) => unreachable!(),
63            Err(err) => TieredResult::Err(err.into()),
64        }
65    }
66}
67
68impl<T, E, F> FromResidual<Option<Infallible>> for TieredResult<T, E, F> {
69    fn from_residual(_: Option<Infallible>) -> Self {
70        TieredResult::Null
71    }
72}
73
74impl<T, F> Try for FatalResult<T, F> {
75    type Output = Option<T>;
76    type Residual = Residual<F>;
77
78    fn from_output(output: Self::Output) -> Self {
79        match output {
80            Some(value) => FatalResult::Ok(value),
81            None => FatalResult::Null,
82        }
83    }
84
85    fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
86        use ControlFlow::*;
87
88        match self {
89            FatalResult::Ok(value) => Continue(Some(value)),
90            FatalResult::Null => Continue(None),
91            FatalResult::Fatal(fatality) => Break(Residual(fatality)),
92        }
93    }
94}
95
96impl<T, F> FromResidual<Residual<F>> for FatalResult<T, F> {
97    fn from_residual(residual: Residual<F>) -> Self {
98        FatalResult::Fatal(residual.0)
99    }
100}
101
102impl<T, F> FromResidual<Option<Infallible>> for FatalResult<T, F> {
103    fn from_residual(_: Option<Infallible>) -> Self {
104        FatalResult::Null
105    }
106}
107
108impl<T, F> Try for FatalOrOk<T, F> {
109    type Output = T;
110    type Residual = Residual<F>;
111
112    fn from_output(output: Self::Output) -> Self {
113        FatalOrOk::Ok(output)
114    }
115
116    fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
117        use ControlFlow::*;
118
119        match self {
120            FatalOrOk::Ok(value) => Continue(value),
121            FatalOrOk::Fatal(fatality) => Break(Residual(fatality)),
122        }
123    }
124}
125
126impl<T, F> FromResidual<Residual<F>> for FatalOrOk<T, F> {
127    fn from_residual(residual: Residual<F>) -> Self {
128        FatalOrOk::Fatal(residual.0)
129    }
130}
131
132impl<F, C> Try for ClientResponse<F, C> {
133    type Output = C;
134    type Residual = Residual<F>;
135
136    fn from_output(output: Self::Output) -> Self {
137        ClientResponse::Continue(output)
138    }
139
140    fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
141        use ControlFlow::*;
142
143        match self {
144            ClientResponse::Throw(err) => Break(Residual(err)),
145            ClientResponse::Continue(continuation) => Continue(continuation),
146        }
147    }
148}
149
150impl<F, C> FromResidual<Residual<F>> for ClientResponse<F, C> {
151    fn from_residual(residual: Residual<F>) -> Self {
152        ClientResponse::Throw(residual.0)
153    }
154}