1use std::{
7 convert::Infallible,
8 fmt::{self, Debug},
9};
10
11use crate::{
12 classify::Classify,
13 fail::{Fail, Fault, Level, Lift, Rejection},
14 lane::{Denied, Exhausted, Fatal, FatalKind, Lane, Transient},
15 profile::{LaneProfile, NoLanes, Profile},
16};
17
18#[doc(hidden)]
21pub mod kind {
22 pub struct Source;
25 pub struct Payload;
27 pub struct Fault;
29 pub struct Fail;
31
32 pub trait IntoFault {}
34 impl IntoFault for Source {}
35 impl IntoFault for Payload {}
36
37 pub trait IntoFail {}
39 impl IntoFail for Source {}
40 impl IntoFail for Payload {}
41 impl IntoFail for Fault {}
42
43 pub trait IntoBareLane {}
45 impl IntoBareLane for Source {}
46}
47
48#[doc(hidden)]
54#[diagnostic::on_unimplemented(
55 message = "`{Self}` does not enter the lanes",
56 note = "implement `errlanes::Classify` (or derive `Rejection` / `Classify`)"
57)]
58pub trait IntoLanes: Sized {
59 type Shape;
60 type Rejected;
61 type Lanes: LaneProfile;
62 fn into_lanes(self) -> Fail<Self::Rejected, Self::Lanes>;
63}
64
65impl<W: Classify> IntoLanes for W {
66 type Shape = kind::Source;
67 type Rejected = W::Rejected;
68 type Lanes = W::Lanes;
69 fn into_lanes(self) -> Fail<Self::Rejected, Self::Lanes> {
70 self.classify()
71 }
72}
73
74impl<L: LaneProfile> IntoLanes for Fault<L> {
75 type Shape = kind::Fault;
76 type Rejected = Infallible;
77 type Lanes = L;
78 fn into_lanes(self) -> Fail<Infallible, L> {
79 match self {
80 Fault::Denied(d) => Fail::Denied(d),
81 Fault::Transient(t) => Fail::Transient(t),
82 Fault::Fatal(f) => Fail::Fatal(f),
83 }
84 }
85}
86
87impl<D, L: LaneProfile> IntoLanes for Fail<D, L> {
88 type Shape = kind::Fail;
89 type Rejected = D;
90 type Lanes = L;
91 fn into_lanes(self) -> Fail<D, L> {
92 self
93 }
94}
95
96macro_rules! payload {
97 ($ty:ty, $d:literal, $t:literal, $f:literal, $variant:ident) => {
98 impl IntoLanes for $ty {
99 type Shape = kind::Payload;
100 type Rejected = Infallible;
101 type Lanes = Profile<$d, $t, $f>;
102 fn into_lanes(self) -> Fail<Infallible, Self::Lanes> {
103 Fail::$variant(self)
104 }
105 }
106 };
107}
108payload!(Transient, false, true, false, Transient);
109payload!(Fatal, false, false, true, Fatal);
110payload!(Denied, true, false, false, Denied);
111
112impl IntoLanes for Exhausted {
113 type Shape = kind::Payload;
114 type Rejected = Infallible;
115 type Lanes = Profile<false, false, true>;
116 fn into_lanes(self) -> Fail<Infallible, Self::Lanes> {
117 Fail::Fatal(Fatal::from_error(FatalKind::Exhausted, self))
118 }
119}
120
121impl IntoLanes for Infallible {
122 type Shape = kind::Payload;
123 type Rejected = Infallible;
124 type Lanes = NoLanes;
125 fn into_lanes(self) -> Fail<Infallible, NoLanes> {
126 match self {}
127 }
128}
129
130pub(crate) fn fail_into_fault<L: LaneProfile, M: LaneProfile>(f: Fail<Infallible, L>) -> Fault<M>
133where
134 L::Denied: Into<M::Denied>,
135 L::Transient: Into<M::Transient>,
136 L::Fatal: Into<M::Fatal>,
137{
138 match f {
139 Fail::Rejected(never) => match never {},
140 Fail::Denied(d) => Fault::Denied(d.into()),
141 Fail::Transient(t) => Fault::Transient(t.into()),
142 Fail::Fatal(x) => Fault::Fatal(x.into()),
143 }
144}
145
146impl<W: IntoLanes<Rejected = Infallible>, M: LaneProfile> From<W> for Fault<M>
157where
158 W::Shape: kind::IntoFault,
159 <W::Lanes as LaneProfile>::Denied: Into<M::Denied>,
160 <W::Lanes as LaneProfile>::Transient: Into<M::Transient>,
161 <W::Lanes as LaneProfile>::Fatal: Into<M::Fatal>,
162{
163 fn from(w: W) -> Self {
164 fail_into_fault(w.into_lanes())
165 }
166}
167
168impl<W: IntoLanes, D: Lift<W::Rejected, Unmapped = Infallible>, M: LaneProfile> From<W>
172 for Fail<D, M>
173where
174 W::Shape: kind::IntoFail,
175 <W::Lanes as LaneProfile>::Denied: Into<M::Denied>,
176 <W::Lanes as LaneProfile>::Transient: Into<M::Transient>,
177 <W::Lanes as LaneProfile>::Fatal: Into<M::Fatal>,
178{
179 fn from(w: W) -> Self {
180 fail_absorb(w.into_lanes())
181 }
182}
183
184fn fail_absorb<R, L: LaneProfile, D: Lift<R, Unmapped = Infallible>, M: LaneProfile>(
185 f: Fail<R, L>,
186) -> Fail<D, M>
187where
188 L::Denied: Into<M::Denied>,
189 L::Transient: Into<M::Transient>,
190 L::Fatal: Into<M::Fatal>,
191{
192 match f {
193 Fail::Rejected(r) => match D::lift(r) {
194 Ok(d) => Fail::Rejected(d),
195 Err(never) => match never {},
196 },
197 Fail::Denied(d) => Fail::Denied(d.into()),
198 Fail::Transient(t) => Fail::Transient(t.into()),
199 Fail::Fatal(x) => Fail::Fatal(x.into()),
200 }
201}
202
203macro_rules! profile_inclusion {
207 (($sd:literal,$st:literal,$sf:literal) => ($dd:literal,$dt:literal,$df:literal)) => {
208 impl From<Fault<Profile<$sd, $st, $sf>>> for Fault<Profile<$dd, $dt, $df>> {
209 #[allow(unreachable_code)]
210 fn from(value: Fault<Profile<$sd, $st, $sf>>) -> Self {
211 match value {
212 Fault::Denied(v) => Fault::Denied(v.into()),
213 Fault::Transient(v) => Fault::Transient(v.into()),
214 Fault::Fatal(v) => Fault::Fatal(v.into()),
215 }
216 }
217 }
218 impl<R> From<Fail<R, Profile<$sd, $st, $sf>>> for Fail<R, Profile<$dd, $dt, $df>> {
219 #[allow(unreachable_code)]
220 fn from(value: Fail<R, Profile<$sd, $st, $sf>>) -> Self {
221 match value {
222 Fail::Rejected(v) => Fail::Rejected(v),
223 Fail::Denied(v) => Fail::Denied(v.into()),
224 Fail::Transient(v) => Fail::Transient(v.into()),
225 Fail::Fatal(v) => Fail::Fatal(v.into()),
226 }
227 }
228 }
229 };
230}
231profile_inclusion!((false,false,false) => (true,false,false));
232profile_inclusion!((false,false,false) => (false,true,false));
233profile_inclusion!((false,false,false) => (false,false,true));
234profile_inclusion!((false,false,false) => (true,true,false));
235profile_inclusion!((false,false,false) => (true,false,true));
236profile_inclusion!((false,false,false) => (false,true,true));
237profile_inclusion!((false,false,false) => (true,true,true));
238profile_inclusion!((true,false,false) => (true,true,false));
239profile_inclusion!((true,false,false) => (true,false,true));
240profile_inclusion!((true,false,false) => (true,true,true));
241profile_inclusion!((false,true,false) => (true,true,false));
242profile_inclusion!((false,true,false) => (false,true,true));
243profile_inclusion!((false,true,false) => (true,true,true));
244profile_inclusion!((false,false,true) => (true,false,true));
245profile_inclusion!((false,false,true) => (false,true,true));
246profile_inclusion!((false,false,true) => (true,true,true));
247profile_inclusion!((true,true,false) => (true,true,true));
248profile_inclusion!((true,false,true) => (true,true,true));
249profile_inclusion!((false,true,true) => (true,true,true));
250
251impl<W: IntoLanes<Rejected = Infallible, Lanes = Profile<false, false, true>>> From<W> for Fatal
255where
256 W::Shape: kind::IntoBareLane,
257{
258 fn from(w: W) -> Self {
259 match w.into_lanes() {
260 Fail::Rejected(never) => match never {},
261 Fail::Denied(never) => match never {},
262 Fail::Transient(never) => match never {},
263 Fail::Fatal(x) => x,
264 }
265 }
266}
267
268impl<W: IntoLanes<Rejected = Infallible, Lanes = Profile<false, true, false>>> From<W> for Transient
270where
271 W::Shape: kind::IntoBareLane,
272{
273 fn from(w: W) -> Self {
274 match w.into_lanes() {
275 Fail::Rejected(never) => match never {},
276 Fail::Denied(never) => match never {},
277 Fail::Transient(t) => t,
278 Fail::Fatal(never) => match never {},
279 }
280 }
281}
282
283pub enum LaneRef<'a, R> {
290 Rejected(&'a R),
291 Denied(&'a Denied),
292 Transient(&'a Transient),
293 Fatal(&'a Fatal),
294}
295
296impl<R> Clone for LaneRef<'_, R> {
297 fn clone(&self) -> Self {
298 *self
299 }
300}
301
302impl<R> Copy for LaneRef<'_, R> {}
303
304impl<R: Debug> Debug for LaneRef<'_, R> {
305 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
306 match self {
307 LaneRef::Rejected(r) => f.debug_tuple("Rejected").field(r).finish(),
308 LaneRef::Denied(d) => f.debug_tuple("Denied").field(d).finish(),
309 LaneRef::Transient(t) => f.debug_tuple("Transient").field(t).finish(),
310 LaneRef::Fatal(x) => f.debug_tuple("Fatal").field(x).finish(),
311 }
312 }
313}
314
315impl<R> LaneRef<'_, R> {
316 pub fn lane(&self) -> Lane {
318 match self {
319 LaneRef::Rejected(_) => Lane::Rejected,
320 LaneRef::Denied(_) => Lane::Denied,
321 LaneRef::Transient(_) => Lane::Transient,
322 LaneRef::Fatal(_) => Lane::Fatal,
323 }
324 }
325}
326
327impl<R: LaneRejected> LaneRef<'_, R> {
328 pub fn message(&self) -> String {
334 match self {
335 LaneRef::Rejected(d) => d.code_string(),
336 LaneRef::Denied(d) => d.to_string(),
337 LaneRef::Transient(t) => crate::dynamic::message_chain(*t),
338 LaneRef::Fatal(x) => crate::dynamic::message_chain(*x),
339 }
340 }
341
342 pub fn level(&self) -> Level {
346 match self {
347 LaneRef::Rejected(d) => d.level(),
348 other => other.lane().level(),
349 }
350 }
351
352 #[cfg(feature = "tracing")]
354 pub(crate) fn record(&self, span: &tracing::Span) {
355 crate::record::record_lanes(span, *self);
356 }
357
358 #[cfg(feature = "tracing")]
360 pub(crate) fn emit(&self) {
361 crate::record::emit_lanes(*self);
362 }
363}
364
365#[doc(hidden)]
369pub trait LaneRejected {
370 fn code_string(&self) -> String;
371 fn code_str(&self) -> &'static str;
372 fn level(&self) -> Level;
373}
374
375impl<R: Rejection> LaneRejected for R {
376 fn code_string(&self) -> String {
377 self.code().to_string()
378 }
379 fn code_str(&self) -> &'static str {
380 Into::<&'static str>::into(self.code())
381 }
382 fn level(&self) -> Level {
383 Rejection::level(self)
384 }
385}
386
387impl LaneRejected for Infallible {
388 fn code_string(&self) -> String {
389 match *self {}
390 }
391 fn code_str(&self) -> &'static str {
392 match *self {}
393 }
394 fn level(&self) -> Level {
395 match *self {}
396 }
397}
398
399impl<L: LaneProfile> Fault<L> {
400 pub fn lanes(&self) -> LaneRef<'_, Infallible> {
402 use crate::profile::Slot;
403 match self {
404 Fault::Denied(d) => LaneRef::Denied(d.marker()),
405 Fault::Transient(t) => LaneRef::Transient(t.marker()),
406 Fault::Fatal(x) => LaneRef::Fatal(x.marker()),
407 }
408 }
409}
410
411impl<D, L: LaneProfile> Fail<D, L> {
412 pub fn lanes(&self) -> LaneRef<'_, D> {
414 use crate::profile::Slot;
415 match self {
416 Fail::Rejected(d) => LaneRef::Rejected(d),
417 Fail::Denied(d) => LaneRef::Denied(d.marker()),
418 Fail::Transient(t) => LaneRef::Transient(t.marker()),
419 Fail::Fatal(x) => LaneRef::Fatal(x.marker()),
420 }
421 }
422}