1use std::{convert::Infallible, error::Error};
12
13use crate::{
14 fail::{Fail, Fault, Lift, Rejection, UnmappedInto},
15 lane::{Fatal, Transient},
16 profile::{LaneProfile, Profile},
17};
18
19pub trait RejectedSlot: Send + Sync + 'static {}
23impl RejectedSlot for Infallible {}
24impl<R: Rejection> RejectedSlot for R {}
25
26#[doc(hidden)]
35pub trait RejectedUnion<Other: RejectedSlot>: RejectedSlot {
36 type Out: RejectedSlot;
37}
38impl RejectedUnion<Infallible> for Infallible {
39 type Out = Infallible;
40}
41impl<R: Rejection> RejectedUnion<Infallible> for R {
42 type Out = R;
43}
44impl<R: Rejection> RejectedUnion<R> for Infallible {
45 type Out = R;
46}
47impl<R: Rejection> RejectedUnion<R> for R {
48 type Out = R;
49}
50
51#[diagnostic::on_unimplemented(
60 message = "`{Self}` does not say how it enters the lanes",
61 note = "derive `errlanes::Rejection` if a caller can correct it, or `errlanes::Classify` \
62 with a lane (`#[classify(fatal(Kind))]`, …); a foreign error is wrapped in a \
63 local type first"
64)]
65pub trait Classify: Error + Send + Sync + 'static {
66 type Rejected: RejectedSlot;
67 type Lanes: LaneProfile;
68
69 fn classify(self) -> Fail<Self::Rejected, Self::Lanes>;
70}
71
72impl<R: Rejection> Classify for R {
75 type Rejected = R;
76 type Lanes = crate::profile::NoLanes;
77
78 fn classify(self) -> Fail<R, Self::Lanes> {
79 Fail::Rejected(self)
80 }
81}
82
83impl<W: Classify, D: Lift<W::Rejected, Unmapped = Infallible>, M: LaneProfile> From<W>
89 for Fail<D, M>
90where
91 <W::Lanes as LaneProfile>::Denied: Into<M::Denied>,
92 <W::Lanes as LaneProfile>::Transient: Into<M::Transient>,
93 <W::Lanes as LaneProfile>::Fatal: Into<M::Fatal>,
94{
95 fn from(w: W) -> Self {
96 match w.classify() {
97 Fail::Rejected(r) => match D::lift(r) {
98 Ok(d) => Fail::Rejected(d),
99 Err(never) => match never {},
100 },
101 Fail::Denied(d) => Fail::Denied(d.into()),
102 Fail::Transient(t) => Fail::Transient(t.into()),
103 Fail::Fatal(x) => Fail::Fatal(x.into()),
104 }
105 }
106}
107
108impl<W: Classify<Rejected = Infallible>, M: LaneProfile> From<W> for Fault<M>
112where
113 <W::Lanes as LaneProfile>::Denied: Into<M::Denied>,
114 <W::Lanes as LaneProfile>::Transient: Into<M::Transient>,
115 <W::Lanes as LaneProfile>::Fatal: Into<M::Fatal>,
116{
117 fn from(w: W) -> Self {
118 match w.classify() {
119 Fail::Rejected(never) => match never {},
120 Fail::Denied(d) => Fault::Denied(d.into()),
121 Fail::Transient(t) => Fault::Transient(t.into()),
122 Fail::Fatal(x) => Fault::Fatal(x.into()),
123 }
124 }
125}
126
127impl<W: Classify<Rejected = Infallible, Lanes = Profile<false, false, true>>> From<W> for Fatal {
131 fn from(w: W) -> Self {
132 match w.classify() {
133 Fail::Rejected(never) => match never {},
134 Fail::Denied(never) => match never {},
135 Fail::Transient(never) => match never {},
136 Fail::Fatal(x) => x,
137 }
138 }
139}
140
141impl<W: Classify<Rejected = Infallible, Lanes = Profile<false, true, false>>> From<W>
143 for Transient
144{
145 fn from(w: W) -> Self {
146 match w.classify() {
147 Fail::Rejected(never) => match never {},
148 Fail::Denied(never) => match never {},
149 Fail::Transient(t) => t,
150 Fail::Fatal(never) => match never {},
151 }
152 }
153}
154
155impl<T, C: Classify, P: Lift<C::Rejected>, M: LaneProfile> crate::fail::WidenResult<T, Fail<P, M>>
160 for Result<T, C>
161where
162 <C::Lanes as LaneProfile>::Denied: Into<M::Denied>,
163 <C::Lanes as LaneProfile>::Transient: Into<M::Transient>,
164 <C::Lanes as LaneProfile>::Fatal: Into<M::Fatal>,
165 P::Unmapped: UnmappedInto<M::Fatal>,
166{
167 fn widen(self) -> Result<T, Fail<P, M>> {
168 self.map_err(|c| match c.classify() {
169 Fail::Rejected(r) => match P::lift(r) {
170 Ok(p) => Fail::Rejected(p),
171 Err(u) => Fail::Fatal(u.unmapped_into()),
172 },
173 Fail::Denied(d) => Fail::Denied(d.into()),
174 Fail::Transient(t) => Fail::Transient(t.into()),
175 Fail::Fatal(x) => Fail::Fatal(x.into()),
176 })
177 }
178}
179
180pub trait ClassifyResult<T, E> {
185 fn classify<W: Classify + From<E>>(self) -> Result<T, W>;
186}
187
188impl<T, E> ClassifyResult<T, E> for Result<T, E> {
189 fn classify<W: Classify + From<E>>(self) -> Result<T, W> {
190 self.map_err(W::from)
191 }
192}