use std::convert::Infallible;
use crate::{
carrier::{Carrier, IntoLanes, fail_into_fault, kind},
classify::Classify,
fail::{Fail, Fault, Laned, Lift, Rejection, UnmappedInto},
lane::{Denied, Fatal},
profile::{LaneProfile, NarrowDenied, WithoutDenied},
};
#[doc(hidden)]
#[diagnostic::on_unimplemented(
message = "`{Self}` has no rejected lane to narrow",
note = "`narrow_rejected` is for a `Fail<D, L>`, or a bare `Rejection`, with no \
caller left to correct the rejection; a `Fault<L>` has no rejected lane at all"
)]
pub trait NarrowRejectedLane: narrow_sealed::Sealed {
type Narrowed;
fn narrow_rejected(self) -> Self::Narrowed;
}
mod narrow_sealed {
use crate::carrier::IntoLanes;
pub trait Sealed {}
impl<S: IntoLanes> Sealed for S {}
}
impl<S: IntoLanes> NarrowRejectedLane for S
where
S::Shape: NarrowRejectedBy<S>,
{
type Narrowed = <S::Shape as NarrowRejectedBy<S>>::Narrowed;
fn narrow_rejected(self) -> Self::Narrowed {
<S::Shape as NarrowRejectedBy<S>>::narrow(self)
}
}
#[doc(hidden)]
pub trait NarrowRejectedBy<S> {
type Narrowed;
fn narrow(s: S) -> Self::Narrowed;
}
impl<D: Rejection, L: LaneProfile<Fatal = Fatal>> NarrowRejectedBy<Fail<D, L>> for kind::Fail {
type Narrowed = Fault<L>;
fn narrow(s: Fail<D, L>) -> Fault<L> {
Fail::narrow_rejected(s)
}
}
impl<R: Rejection> NarrowRejectedBy<R> for kind::Source {
type Narrowed = Fatal;
fn narrow(s: R) -> Fatal {
crate::fail::invariant_from_rejection(s)
}
}
impl<C: Carrier> NarrowRejectedBy<C> for kind::CarrierShape
where
C::Repr: NarrowRejectedLane,
{
type Narrowed = <C::Repr as NarrowRejectedLane>::Narrowed;
fn narrow(s: C) -> Self::Narrowed {
s.into_repr().narrow_rejected()
}
}
#[doc(hidden)]
#[diagnostic::on_unimplemented(
message = "`{Self}` has no denied lane to narrow",
note = "`narrow_denied` is only available on a profile whose `Denied` lane is enabled"
)]
pub trait NarrowDeniedLane: crate::fail::sealed::Sealed {
type Narrowed;
fn narrow_denied(self) -> Self::Narrowed;
}
impl<D: Rejection, L> NarrowDeniedLane for Fail<D, L>
where
L: LaneProfile<Denied = Denied>,
L::Denied: NarrowDenied<L::Fatal>,
{
type Narrowed = Fail<D, WithoutDenied<L>>;
fn narrow_denied(self) -> Self::Narrowed {
Fail::narrow_denied(self)
}
}
impl<L> NarrowDeniedLane for Fault<L>
where
L: LaneProfile<Denied = Denied>,
L::Denied: NarrowDenied<L::Fatal>,
{
type Narrowed = Fault<WithoutDenied<L>>;
fn narrow_denied(self) -> Self::Narrowed {
Fault::narrow_denied(self)
}
}
impl<C: Carrier> NarrowDeniedLane for C
where
C::Repr: NarrowDeniedLane,
{
type Narrowed = <C::Repr as NarrowDeniedLane>::Narrowed;
fn narrow_denied(self) -> Self::Narrowed {
self.into_repr().narrow_denied()
}
}
#[doc(hidden)]
#[diagnostic::on_unimplemented(
message = "`{Self}` can reject and cannot enter `Fault`",
note = "handle the rejection, call `.narrow_rejected()` when justified, or use `.into_fail()`"
)]
pub trait FaultSource: IntoLanes {
fn own_fault(self) -> Fault<Self::Lanes>;
}
impl<W: IntoLanes<Rejected = Infallible>> FaultSource for W {
fn own_fault(self) -> Fault<Self::Lanes> {
fail_into_fault(self.into_lanes())
}
}
#[doc(hidden)]
#[diagnostic::on_unimplemented(
message = "`{Self}` never rejects",
note = "use `.into_fault()` instead"
)]
pub trait FailSource: IntoLanes {
fn own_fail(self) -> Fail<Self::Rejected, Self::Lanes>;
}
impl<W: IntoLanes> FailSource for W
where
W::Rejected: Rejection,
{
fn own_fail(self) -> Fail<Self::Rejected, Self::Lanes> {
self.into_lanes()
}
}
pub trait ResultExt<T, E>: Sized {
fn lift<P>(self) -> Result<T, Fail<P, <E::Lanes as LaneProfile>::WithFatal>>
where
E: IntoLanes,
E::Rejected: Rejection,
P: Rejection + Lift<E::Rejected>,
<E::Lanes as LaneProfile>::Fatal: Into<Fatal>,
P::Unmapped: UnmappedInto<Fatal>;
fn narrow_rejected(self) -> Result<T, E::Narrowed>
where
E: NarrowRejectedLane;
fn narrow_transient(self, attempts: u32) -> Result<T, E::WithoutTransient>
where
E: Laned;
fn narrow_denied(self) -> Result<T, E::Narrowed>
where
E: NarrowDeniedLane;
fn rejected(self) -> Result<Result<T, E::Rejected>, Fault<E::Lanes>>
where
E: IntoLanes,
E::Rejected: Rejection;
fn map_rejected<D2>(self, f: impl FnOnce(E::Rejected) -> D2) -> Result<T, Fail<D2, E::Lanes>>
where
E: IntoLanes,
E::Rejected: Rejection;
fn into_fault(self) -> Result<T, Fault<E::Lanes>>
where
E: FaultSource;
fn into_fail(self) -> Result<T, Fail<E::Rejected, E::Lanes>>
where
E: FailSource;
fn classify<W: Classify + From<E>>(self) -> Result<T, W>;
#[cfg(feature = "tracing")]
fn record(self) -> Self
where
E: Laned;
}
impl<T, E> ResultExt<T, E> for Result<T, E> {
fn lift<P>(self) -> Result<T, Fail<P, <E::Lanes as LaneProfile>::WithFatal>>
where
E: IntoLanes,
E::Rejected: Rejection,
P: Rejection + Lift<E::Rejected>,
<E::Lanes as LaneProfile>::Fatal: Into<Fatal>,
P::Unmapped: UnmappedInto<Fatal>,
{
self.map_err(|e| e.into_lanes().lift())
}
fn narrow_rejected(self) -> Result<T, E::Narrowed>
where
E: NarrowRejectedLane,
{
self.map_err(NarrowRejectedLane::narrow_rejected)
}
fn narrow_transient(self, attempts: u32) -> Result<T, E::WithoutTransient>
where
E: Laned,
{
self.map_err(|e| e.narrow_transient(attempts))
}
fn narrow_denied(self) -> Result<T, E::Narrowed>
where
E: NarrowDeniedLane,
{
self.map_err(NarrowDeniedLane::narrow_denied)
}
fn rejected(self) -> Result<Result<T, E::Rejected>, Fault<E::Lanes>>
where
E: IntoLanes,
E::Rejected: Rejection,
{
match self {
Ok(value) => Ok(Ok(value)),
Err(e) => e.into_lanes().rejected().map(Err),
}
}
fn map_rejected<D2>(self, f: impl FnOnce(E::Rejected) -> D2) -> Result<T, Fail<D2, E::Lanes>>
where
E: IntoLanes,
E::Rejected: Rejection,
{
self.map_err(|e| e.into_lanes().map_rejected(f))
}
fn into_fault(self) -> Result<T, Fault<E::Lanes>>
where
E: FaultSource,
{
self.map_err(FaultSource::own_fault)
}
fn into_fail(self) -> Result<T, Fail<E::Rejected, E::Lanes>>
where
E: FailSource,
{
self.map_err(FailSource::own_fail)
}
fn classify<W: Classify + From<E>>(self) -> Result<T, W> {
self.map_err(W::from)
}
#[cfg(feature = "tracing")]
fn record(self) -> Self
where
E: Laned,
{
if let Err(e) = &self {
e.record(&tracing::Span::current());
}
self
}
}