use crate::{
classify::Classify,
fail::{Fail, Failure, Fault, Laned, Rejection, WidenResult},
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::{
fail::{Fail, Rejection},
profile::LaneProfile,
};
pub trait Sealed {}
impl<D: Rejection, L: LaneProfile> Sealed for Fail<D, L> {}
impl<R: Rejection> Sealed for R {}
}
impl<D: Rejection, L: LaneProfile<Fatal = Fatal>> NarrowRejectedLane for Fail<D, L> {
type Narrowed = Fault<L>;
fn narrow_rejected(self) -> Fault<L> {
Fail::narrow_rejected(self)
}
}
impl<R: Rejection> NarrowRejectedLane for R {
type Narrowed = Fatal;
fn narrow_rejected(self) -> Fatal {
crate::fail::invariant_from_rejection(self)
}
}
#[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)
}
}
pub trait ResultExt<T, E>: Sized {
fn widen<E2>(self) -> Result<T, E2>
where
Self: WidenResult<T, E2>;
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::Rejection>, Fault<E::Lanes>>
where
E: Failure;
fn map_rejected<D2>(self, f: impl FnOnce(E::Rejection) -> D2) -> Result<T, Fail<D2, E::Lanes>>
where
E: Failure;
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 widen<E2>(self) -> Result<T, E2>
where
Self: WidenResult<T, E2>,
{
WidenResult::widen(self)
}
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::Rejection>, Fault<E::Lanes>>
where
E: Failure,
{
match self {
Ok(value) => Ok(Ok(value)),
Err(e) => e.into_fail().rejected().map(Err),
}
}
fn map_rejected<D2>(self, f: impl FnOnce(E::Rejection) -> D2) -> Result<T, Fail<D2, E::Lanes>>
where
E: Failure,
{
self.map_err(|e| e.into_fail().map_rejected(f))
}
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
}
}