use std::{convert::Infallible, error::Error};
use crate::{
fail::{Fail, Fault, Lift, Rejection, UnmappedInto},
lane::{Fatal, Transient},
profile::{LaneProfile, Profile},
};
pub trait RejectedSlot: Send + Sync + 'static {}
impl RejectedSlot for Infallible {}
impl<R: Rejection> RejectedSlot for R {}
#[doc(hidden)]
pub trait RejectedUnion<Other: RejectedSlot>: RejectedSlot {
type Out: RejectedSlot;
}
impl RejectedUnion<Infallible> for Infallible {
type Out = Infallible;
}
impl<R: Rejection> RejectedUnion<Infallible> for R {
type Out = R;
}
impl<R: Rejection> RejectedUnion<R> for Infallible {
type Out = R;
}
impl<R: Rejection> RejectedUnion<R> for R {
type Out = R;
}
#[diagnostic::on_unimplemented(
message = "`{Self}` does not say how it enters the lanes",
note = "derive `errlanes::Rejection` if a caller can correct it, or `errlanes::Classify` \
with a lane (`#[classify(fatal(Kind))]`, …); a foreign error is wrapped in a \
local type first"
)]
pub trait Classify: Error + Send + Sync + 'static {
type Rejected: RejectedSlot;
type Lanes: LaneProfile;
fn classify(self) -> Fail<Self::Rejected, Self::Lanes>;
}
impl<R: Rejection> Classify for R {
type Rejected = R;
type Lanes = crate::profile::NoLanes;
fn classify(self) -> Fail<R, Self::Lanes> {
Fail::Rejected(self)
}
}
impl<W: Classify, D: Lift<W::Rejected, Unmapped = Infallible>, M: LaneProfile> From<W>
for Fail<D, M>
where
<W::Lanes as LaneProfile>::Denied: Into<M::Denied>,
<W::Lanes as LaneProfile>::Transient: Into<M::Transient>,
<W::Lanes as LaneProfile>::Fatal: Into<M::Fatal>,
{
fn from(w: W) -> Self {
match w.classify() {
Fail::Rejected(r) => match D::lift(r) {
Ok(d) => Fail::Rejected(d),
Err(never) => match never {},
},
Fail::Denied(d) => Fail::Denied(d.into()),
Fail::Transient(t) => Fail::Transient(t.into()),
Fail::Fatal(x) => Fail::Fatal(x.into()),
}
}
}
impl<W: Classify<Rejected = Infallible>, M: LaneProfile> From<W> for Fault<M>
where
<W::Lanes as LaneProfile>::Denied: Into<M::Denied>,
<W::Lanes as LaneProfile>::Transient: Into<M::Transient>,
<W::Lanes as LaneProfile>::Fatal: Into<M::Fatal>,
{
fn from(w: W) -> Self {
match w.classify() {
Fail::Rejected(never) => match never {},
Fail::Denied(d) => Fault::Denied(d.into()),
Fail::Transient(t) => Fault::Transient(t.into()),
Fail::Fatal(x) => Fault::Fatal(x.into()),
}
}
}
impl<W: Classify<Rejected = Infallible, Lanes = Profile<false, false, true>>> From<W> for Fatal {
fn from(w: W) -> Self {
match w.classify() {
Fail::Rejected(never) => match never {},
Fail::Denied(never) => match never {},
Fail::Transient(never) => match never {},
Fail::Fatal(x) => x,
}
}
}
impl<W: Classify<Rejected = Infallible, Lanes = Profile<false, true, false>>> From<W>
for Transient
{
fn from(w: W) -> Self {
match w.classify() {
Fail::Rejected(never) => match never {},
Fail::Denied(never) => match never {},
Fail::Transient(t) => t,
Fail::Fatal(never) => match never {},
}
}
}
impl<T, C: Classify, P: Lift<C::Rejected>, M: LaneProfile> crate::fail::WidenResult<T, Fail<P, M>>
for Result<T, C>
where
<C::Lanes as LaneProfile>::Denied: Into<M::Denied>,
<C::Lanes as LaneProfile>::Transient: Into<M::Transient>,
<C::Lanes as LaneProfile>::Fatal: Into<M::Fatal>,
P::Unmapped: UnmappedInto<M::Fatal>,
{
fn widen(self) -> Result<T, Fail<P, M>> {
self.map_err(|c| match c.classify() {
Fail::Rejected(r) => match P::lift(r) {
Ok(p) => Fail::Rejected(p),
Err(u) => Fail::Fatal(u.unmapped_into()),
},
Fail::Denied(d) => Fail::Denied(d.into()),
Fail::Transient(t) => Fail::Transient(t.into()),
Fail::Fatal(x) => Fail::Fatal(x.into()),
})
}
}