use crate::{
carrier::{BuiltinFor, Carrier, IntoLanes, kind},
classify::Classify,
fail::{Fail, 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::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()
}
}
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::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;
#[allow(clippy::type_complexity)]
fn widen_via_builtin(self) -> Result<T, <E::Rejected as BuiltinFor<E::Lanes>>::Builtin>
where
E: IntoLanes,
E::Rejected: BuiltinFor<E::Lanes>;
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::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 widen_via_builtin(self) -> Result<T, <E::Rejected as BuiltinFor<E::Lanes>>::Builtin>
where
E: IntoLanes,
E::Rejected: BuiltinFor<E::Lanes>,
{
self.map_err(|e| BuiltinFor::builtin(e.into_lanes()))
}
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
}
}