#![allow(clippy::type_complexity)]
mod ptr;
mod raw;
mod rtti;
#[doc(hidden)]
pub mod macros;
pub mod context;
pub mod nae;
pub mod payload;
pub mod state;
use std::{
self, error,
fmt::{self, Debug, Display},
marker::PhantomData,
mem, result,
};
use crate::{
context::{Context, Literal},
nae::Nae,
payload::{Immediate, PayloadFn},
raw::RawError,
state::{State, Stateless},
};
pub type Result<T> = result::Result<T, Error>;
#[repr(transparent)]
pub struct Error<S = Stateless>(RawError<S::Repr>)
where
S: State + ?Sized;
impl Error {
pub fn with_error<E>(
err: E,
) -> Builder<E, Stateless, Immediate<payload::Empty>, context::Blank> {
Builder {
err,
context: PhantomData,
state: (),
payload_fn: Immediate(payload::Empty::new()),
}
}
pub fn with_state<S>(state: S) -> Builder<Nae, S, Immediate<payload::Empty>, context::Blank>
where
S: State,
{
Builder {
err: Nae::new(),
context: PhantomData,
state: state.into_repr(),
payload_fn: Immediate(payload::Empty::new()),
}
}
pub fn with_payload<P>(payload: P) -> Builder<Nae, Stateless, Immediate<P>, context::Blank>
where
P: Display + Send + Sync + 'static,
{
Builder {
err: Nae::new(),
context: PhantomData,
state: (),
payload_fn: Immediate(payload),
}
}
pub fn with_payload_fn<F>(payload_fn: F) -> Builder<Nae, Stateless, F, context::Blank>
where
F: PayloadFn,
{
Builder {
err: Nae::new(),
context: PhantomData,
state: (),
payload_fn,
}
}
pub fn with_context<L>(_ty: L) -> Builder<Nae, Stateless, Immediate<payload::Empty>, L>
where
L: Context,
{
Self::with_context_ty::<L>()
}
pub fn with_context_ty<L>() -> Builder<Nae, Stateless, Immediate<payload::Empty>, L> {
Builder {
err: Nae::new(),
context: PhantomData,
state: (),
payload_fn: Immediate(payload::Empty::new()),
}
}
pub fn into_parts<E, P>(self) -> (Option<E>, Option<P>)
where
E: 'static,
P: 'static,
{
let (source, payload, _) = self.0.into_parts::<E, P>();
(source, payload)
}
pub fn stateless(self) -> Self {
self
}
}
impl<S> Error<S>
where
S: State + ?Sized,
{
pub fn erase(self) -> impl error::Error + Send + Sync + 'static {
ImplError::<S>(self.0)
}
pub fn erase_ref(&self) -> &(impl error::Error + Send + Sync + 'static) {
unsafe { mem::transmute::<&RawError<S::Repr>, &ImplError<S>>(&self.0) }
}
}
impl<S> Error<S>
where
S: State + ?Sized,
S::Repr: Default,
{
pub fn from_error<E>(err: E) -> Self
where
E: error::Error + Send + Sync + 'static,
{
err.into()
}
pub fn from_context<L>(_ty: L) -> Self
where
L: Literal,
{
Self::from_context_ty::<L>()
}
pub fn from_context_ty<L>() -> Self
where
L: Literal,
{
if let Ok(err) =
rtti::concretize::<Error<Stateless>, Error<S>>(Error(RawError::new_const::<L>()))
{
return err;
}
Self(RawError::new_boxed::<_, _, context::Blank>(
S::Repr::default(),
Nae::new(),
payload::Empty::new(),
))
}
pub fn from_payload<P>(payload: P) -> Self
where
P: Display + Send + Sync + 'static,
{
Self(RawError::new_boxed::<_, P, context::Blank>(
S::Repr::default(),
Nae::new(),
payload,
))
}
}
impl<S> Error<S>
where
S: State + ?Sized,
{
pub fn context(&self) -> Option<&(dyn Display + Send + Sync + 'static)> {
self.0.context()
}
pub fn payload(&self) -> Option<&(dyn Display + Send + Sync + 'static)> {
self.0.payload()
}
pub fn has_source_of<E>(&self) -> bool
where
E: 'static,
{
self.0.downcast_source_ref::<E>().is_some()
}
pub fn downcast_source_ref<E>(&self) -> Option<&E>
where
E: 'static,
{
self.0.downcast_source_ref::<E>()
}
pub fn downcast_source_mut<E>(&mut self) -> Option<&mut E>
where
E: 'static,
{
self.0.downcast_source_mut::<E>()
}
pub fn has_payload_of<P>(&self) -> bool
where
P: 'static,
{
self.0.downcast_payload_ref::<P>().is_some()
}
pub fn downcast_payload_ref<P>(&self) -> Option<&P>
where
P: 'static,
{
self.0.downcast_payload_ref::<P>()
}
pub fn downcast_payload_mut<P>(&mut self) -> Option<&mut P>
where
P: 'static,
{
self.0.downcast_payload_mut::<P>()
}
pub fn into_source(self) -> Option<Box<dyn error::Error + Send + Sync + 'static>> {
self.0.into_source()
}
pub fn chain(&self) -> impl Iterator<Item = &(dyn error::Error + 'static)> {
self.0.chain()
}
}
impl<S> Error<S>
where
S: State,
{
pub fn from_state(state: S) -> Self {
Error(RawError::new_inline_or_boxed(S::into_repr(state)))
}
pub fn state(&self) -> &S {
S::from_repr_ref(self.0.state())
}
pub fn into_parts<E, P>(self) -> (Option<E>, Option<P>, S)
where
E: 'static,
P: 'static,
{
let (source, payload, state) = self.0.into_parts::<E, P>();
(source, payload, S::from_repr(state))
}
pub fn into_state(self) -> S {
S::from_repr(self.0.into_state())
}
}
impl<S> From<Error<S>> for Box<dyn error::Error + Send + Sync + 'static>
where
S: State + ?Sized,
{
fn from(value: Error<S>) -> Self {
value.0.into_boxed_error()
}
}
impl<S> Debug for Error<S>
where
S: State + ?Sized,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Debug::fmt(&self.0, f)
}
}
impl<S> Display for Error<S>
where
S: State + ?Sized,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Display::fmt(&self.0, f)
}
}
#[repr(transparent)]
struct ImplError<S = Stateless>(RawError<S::Repr>)
where
S: State + ?Sized;
impl<S> Debug for ImplError<S>
where
S: State + ?Sized,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Debug::fmt(&self.0, f)
}
}
impl<S> Display for ImplError<S>
where
S: State + ?Sized,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Display::fmt(&self.0, f)
}
}
impl<S> error::Error for ImplError<S>
where
S: State + ?Sized,
{
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
self.0
.source()
.map(|src| src as &(dyn error::Error + 'static))
}
}
impl<E, S> From<E> for Error<S>
where
E: error::Error + Send + Sync + 'static,
S: State + ?Sized,
S::Repr: Default,
{
fn from(err: E) -> Self {
let Err(err) = match_else!(rtti::concretize::<E, ImplError<S>>(err),
Ok(err_unit) => return Error(err_unit.0),
);
Error(RawError::new_boxed::<_, _, context::Blank>(
S::Repr::default(),
err,
payload::Empty::new(),
))
}
}
impl<S> From<Error<S>> for Error
where
S: State,
{
fn from(err: Error<S>) -> Self {
let Err(err) = match_else!(rtti::concretize::<Error<S>, Error<()>>(err),
Ok(err_unit) => return Error(err_unit.0),
);
Error(RawError::new_boxed::<_, _, context::Blank>(
(),
err.erase(),
payload::Empty::new(),
))
}
}
impl<S> From<Error> for Error<S>
where
S: State,
S::Repr: Default,
{
fn from(value: Error) -> Self {
Error::<S>(RawError::new_boxed::<_, _, context::Blank>(
S::Repr::default(),
value.erase(),
payload::Empty::new(),
))
}
}
#[derive(Debug)]
pub struct Builder<E, S, F, L>
where
F: PayloadFn,
S: State + ?Sized,
L: ?Sized,
{
err: E,
state: S::Repr,
payload_fn: F,
context: PhantomData<L>,
}
impl<E, S, F, L> Builder<E, S, F, L>
where
F: PayloadFn,
E: error::Error + Send + Sync + 'static,
S: State + ?Sized,
L: Context + ?Sized,
{
pub fn build(self) -> Error<S> {
self.into()
}
}
impl<E, S, F, L> From<Builder<E, S, F, L>> for Error<S>
where
F: PayloadFn,
E: error::Error + Send + Sync + 'static,
S: State + ?Sized,
L: Context + ?Sized,
{
fn from(value: Builder<E, S, F, L>) -> Self {
let has_state = !rtti::is_same_ty::<S::Repr, ()>();
let has_context = !rtti::is_same_ty::<L, context::Blank>();
let has_error = !rtti::is_same_ty::<E, Nae>();
let has_payload = !rtti::is_same_ty::<F::Output, payload::Empty>();
match (has_state, has_context, has_error, has_payload) {
(_, false, false, false) => Error::<S>(RawError::new_inline_or_boxed(value.state)),
(false, true, false, false) => {
let Ok(body) = match_else!(rtti::concretize::<_, RawError<S::Repr>>(RawError::new_const::<L>()),
Err(_) => unreachable!(),
);
Error(body)
}
_ => Error::<S>(RawError::new_boxed::<_, _, L>(
value.state,
value.err,
value.payload_fn.call(),
)),
}
}
}
impl<E, S, F, L> From<Builder<E, S, F, L>> for Error
where
F: PayloadFn,
E: error::Error + Send + Sync + 'static,
S: State,
L: Context + ?Sized,
{
fn from(value: Builder<E, S, F, L>) -> Self {
let has_state = rtti::is_same_ty::<S::Repr, ()>();
let has_context = rtti::is_same_ty::<L, context::Blank>();
let has_error = rtti::is_same_ty::<E, Nae>();
let has_payload = rtti::is_same_ty::<F::Output, payload::Empty>();
match (has_state, has_context, has_error, has_payload) {
(true, false, false, false) => Error(RawError::new_boxed::<_, _, L>(
(),
ImplError::<S>(RawError::new_inline_or_boxed(value.state)),
payload::Empty::new(),
)),
(false, true, false, false) => Error(RawError::new_const::<L>()),
(false, _, _, _) => Error(RawError::new_boxed::<_, _, L>(
(),
value.err,
value.payload_fn.call(),
)),
_ => Error(RawError::new_boxed::<_, _, context::Blank>(
(),
ImplError::<S>(RawError::new_boxed::<_, _, L>(
value.state,
value.err,
value.payload_fn.call(),
)),
payload::Empty::new(),
)),
}
}
}
impl<E, S, F, L> From<Builder<E, Stateless, F, L>> for Error<S>
where
F: PayloadFn,
E: error::Error + Send + Sync + 'static,
S: State,
S::Repr: Default,
L: Context + ?Sized,
{
fn from(value: Builder<E, Stateless, F, L>) -> Self {
let has_state = rtti::is_same_ty::<S::Repr, ()>();
let has_context = rtti::is_same_ty::<L, context::Blank>();
let has_error = rtti::is_same_ty::<E, Nae>();
let has_payload = rtti::is_same_ty::<F::Output, payload::Empty>();
match (has_state, has_context, has_error, has_payload) {
(true, false, false, false) => {
Error(RawError::<S::Repr>::new_boxed::<_, _, context::Blank>(
S::Repr::default(),
Nae::new(),
payload::Empty::new(),
))
}
(false, true, false, false) => {
let Ok(body) = match_else!(rtti::concretize::<_, RawError<S::Repr>>(RawError::new_const::<L>()),
Err(_) => unreachable!(),
);
Error(body)
}
_ => Error(RawError::new_boxed::<_, _, L>(
S::Repr::default(),
value.err,
value.payload_fn.call(),
)),
}
}
}
impl<S1, S, F, L> From<Builder<Error<S1>, S, F, L>> for Error<S>
where
S1: State + ?Sized,
F: PayloadFn,
S: State + ?Sized,
S::Repr: Default,
L: Context + ?Sized,
{
fn from(value: Builder<Error<S1>, S, F, L>) -> Self {
Error(RawError::new_boxed::<_, _, L>(
value.state,
value.err.erase(),
value.payload_fn.call(),
))
}
}
pub trait StateExt {
type Result<E>;
fn or_state<S>(self, state: S) -> Self::Result<Error<S>>
where
S: State;
}
pub trait ContextExt {
type Result<E>;
fn or_context<L>(self, _ty: L) -> Self::Result<Error>
where
L: Literal;
}
pub trait BuilderExt: Sized {
type Result<E>;
type E;
type S: State + ?Sized;
type F: PayloadFn;
type L: Literal + ?Sized;
fn with_context_ty<L>(self) -> Self::Result<Builder<Self::E, Self::S, Self::F, L>>
where
L: Context;
fn with_context<L>(self, _ty: L) -> Self::Result<Builder<Self::E, Self::S, Self::F, L>>
where
L: Context,
{
self.with_context_ty::<L>()
}
fn with_state<S>(self, state: S) -> Self::Result<Builder<Self::E, S, Self::F, Self::L>>
where
S: State + Sized;
fn with_payload_fn<F>(
self,
payload_fn: F,
) -> Self::Result<Builder<Self::E, Self::S, F, Self::L>>
where
F: PayloadFn;
fn with_payload<P>(
self,
payload: P,
) -> Self::Result<Builder<Self::E, Self::S, Immediate<P>, Self::L>>
where
P: Display + Send + Sync + 'static,
{
self.with_payload_fn(Immediate(payload))
}
}
pub trait ErrorExt {
type Result<E>;
type S: State + ?Sized;
fn build_error(self) -> Self::Result<Error<Self::S>>;
fn erase_error(self) -> Self::Result<impl error::Error + Send + Sync + 'static>;
}
impl<T, E1> StateExt for result::Result<T, E1> {
type Result<E> = result::Result<T, E>;
fn or_state<S>(self, state: S) -> Self::Result<Error<S>>
where
S: State,
{
self.map_err(|_| Error::<S>(RawError::new_inline_or_boxed(state.into_repr())))
}
}
impl<T, E1> ContextExt for result::Result<T, E1> {
type Result<E> = result::Result<T, E>;
fn or_context<L>(self, _ty: L) -> Self::Result<Error>
where
L: Context,
{
self.map_err(|_| Error(RawError::new_const::<L>()))
}
}
impl<T, E1> BuilderExt for result::Result<T, E1>
where
E1: error::Error + Send + Sync + 'static,
{
type Result<E> = result::Result<T, E>;
type E = E1;
type S = Stateless;
type F = Immediate<payload::Empty>;
type L = context::Blank;
fn with_context_ty<L>(self) -> Self::Result<Builder<Self::E, Self::S, Self::F, L>>
where
L: Context,
{
self.map_err(|err| Builder {
err,
context: PhantomData,
state: (),
payload_fn: Immediate(payload::Empty::new()),
})
}
fn with_state<S>(self, state: S) -> Self::Result<Builder<Self::E, S, Self::F, Self::L>>
where
S: State + Sized,
{
self.map_err(|err| Builder {
err,
context: PhantomData,
state: state.into_repr(),
payload_fn: Immediate(payload::Empty::new()),
})
}
fn with_payload_fn<F>(
self,
payload_fn: F,
) -> Self::Result<Builder<Self::E, Self::S, F, Self::L>>
where
F: PayloadFn,
{
self.map_err(|err| Builder {
err,
context: PhantomData,
state: (),
payload_fn,
})
}
}
impl<T, S1> BuilderExt for result::Result<T, Error<S1>>
where
S1: State + ?Sized,
{
type Result<E> = result::Result<T, E>;
type E = Error<S1>;
type S = Stateless;
type F = Immediate<payload::Empty>;
type L = context::Blank;
fn with_context_ty<L>(self) -> Self::Result<Builder<Self::E, Self::S, Self::F, L>>
where
L: Context,
{
self.map_err(|err| Builder {
err,
context: PhantomData,
state: (),
payload_fn: Immediate(payload::Empty::new()),
})
}
fn with_state<S>(self, state: S) -> Self::Result<Builder<Self::E, S, Self::F, Self::L>>
where
S: State,
{
self.map_err(|err| Builder {
err,
context: PhantomData,
state: state.into_repr(),
payload_fn: Immediate(payload::Empty::new()),
})
}
fn with_payload_fn<F>(
self,
payload_fn: F,
) -> Self::Result<Builder<Self::E, Self::S, F, Self::L>>
where
F: PayloadFn,
{
self.map_err(|err| Builder {
err,
context: PhantomData,
state: (),
payload_fn,
})
}
}
impl<E1, S1, F1, L1> BuilderExt for Builder<E1, S1, F1, L1>
where
F1: PayloadFn,
S1: State + ?Sized,
L1: Literal + ?Sized,
{
type Result<E> = E;
type E = E1;
type S = S1;
type F = F1;
type L = L1;
fn with_context_ty<L>(self) -> Self::Result<Builder<Self::E, Self::S, Self::F, L>>
where
L: Context,
{
Builder {
err: self.err,
context: PhantomData,
state: self.state,
payload_fn: self.payload_fn,
}
}
fn with_state<S>(self, state: S) -> Self::Result<Builder<Self::E, S, Self::F, Self::L>>
where
S: State,
{
Builder {
state: state.into_repr(),
err: self.err,
context: self.context,
payload_fn: self.payload_fn,
}
}
fn with_payload_fn<F>(
self,
payload_fn: F,
) -> Self::Result<Builder<Self::E, Self::S, F, Self::L>>
where
F: PayloadFn,
{
Builder {
err: self.err,
context: self.context,
state: self.state,
payload_fn,
}
}
}
impl<T, E1, S1, F1, L1> BuilderExt for result::Result<T, Builder<E1, S1, F1, L1>>
where
F1: PayloadFn,
S1: State + ?Sized,
L1: Literal + ?Sized,
{
type Result<E> = result::Result<T, E>;
type E = E1;
type S = S1;
type F = F1;
type L = L1;
fn with_context_ty<L>(self) -> Self::Result<Builder<Self::E, Self::S, Self::F, L>>
where
L: Context,
{
self.map_err(|err| Builder {
err: err.err,
context: PhantomData,
state: err.state,
payload_fn: err.payload_fn,
})
}
fn with_state<S>(self, state: S) -> Self::Result<Builder<Self::E, S, Self::F, Self::L>>
where
S: State,
{
self.map_err(|err| Builder {
state: state.into_repr(),
err: err.err,
context: err.context,
payload_fn: err.payload_fn,
})
}
fn with_payload_fn<F>(
self,
payload_fn: F,
) -> Self::Result<Builder<Self::E, Self::S, F, Self::L>>
where
F: PayloadFn,
{
self.map_err(|err| Builder {
err: err.err,
context: err.context,
state: err.state,
payload_fn,
})
}
}
impl<S> ErrorExt for Error<S>
where
S: State + ?Sized,
{
type Result<E> = E;
type S = S;
fn build_error(self) -> Self::Result<Error<Self::S>> {
self
}
fn erase_error(self) -> Self::Result<impl error::Error + Send + Sync + 'static> {
self.erase()
}
}
impl<E1, S, F, L> ErrorExt for Builder<E1, S, F, L>
where
E1: error::Error + Send + Sync + 'static,
F: PayloadFn,
S: State + ?Sized,
L: Context + ?Sized,
{
type Result<E> = E;
type S = S;
fn build_error(self) -> Self::Result<Error<Self::S>> {
self.into()
}
fn erase_error(self) -> Self::Result<impl error::Error + Send + Sync + 'static> {
self.build_error().erase()
}
}
impl<S1, S, F, L> ErrorExt for Builder<Error<S1>, S, F, L>
where
S1: State + ?Sized,
F: PayloadFn,
S: State + ?Sized,
L: Context + ?Sized,
{
type Result<E> = E;
type S = S;
fn build_error(self) -> Self::Result<Error<Self::S>> {
Builder {
err: self.err.erase(),
state: self.state,
payload_fn: self.payload_fn,
context: self.context,
}
.build_error()
}
fn erase_error(self) -> Self::Result<impl error::Error + Send + Sync + 'static> {
self.build_error().erase()
}
}
impl<T, E1, S, F, L> ErrorExt for result::Result<T, Builder<E1, S, F, L>>
where
E1: error::Error + Send + Sync + 'static,
F: PayloadFn,
S: State + ?Sized,
L: Context + ?Sized,
{
type Result<E> = result::Result<T, E>;
type S = S;
fn build_error(self) -> Self::Result<Error<Self::S>> {
self.map_err(Error::from)
}
fn erase_error(self) -> Self::Result<impl error::Error + Send + Sync + 'static> {
self.build_error().map_err(|err| err.erase())
}
}
impl<T, S1, S, F, L> ErrorExt for result::Result<T, Builder<Error<S1>, S, F, L>>
where
S1: State + ?Sized,
F: PayloadFn,
S: State + ?Sized,
L: Context + ?Sized,
{
type Result<E> = result::Result<T, E>;
type S = S;
fn build_error(self) -> Self::Result<Error<Self::S>> {
self.map_err(|err| {
Builder {
err: err.err.erase(),
state: err.state,
payload_fn: err.payload_fn,
context: err.context,
}
.build_error()
})
}
fn erase_error(self) -> Self::Result<impl error::Error + Send + Sync + 'static> {
self.build_error().map_err(|err| err.erase())
}
}
impl<T, E1> ErrorExt for result::Result<T, E1>
where
E1: error::Error + Send + Sync + 'static,
{
type Result<E> = result::Result<T, E>;
type S = Stateless;
fn build_error(self) -> Self::Result<Error<Self::S>> {
self.map_err(Error::from)
}
fn erase_error(self) -> Self::Result<impl error::Error + Send + Sync + 'static> {
self.build_error().map_err(|err| err.erase())
}
}
impl<T, S> ErrorExt for result::Result<T, Error<S>>
where
S: State,
{
type Result<E> = result::Result<T, E>;
type S = S;
fn build_error(self) -> Self::Result<Error<Self::S>> {
self
}
fn erase_error(self) -> Self::Result<impl error::Error + Send + Sync + 'static> {
self.map_err(|err| err.erase())
}
}
impl<T> StateExt for Option<T> {
type Result<E> = result::Result<T, E>;
fn or_state<S>(self, state: S) -> Self::Result<Error<S>>
where
S: State,
{
self.ok_or(Error::<S>(RawError::new_inline_or_boxed(state.into_repr())))
}
}
impl<T> ContextExt for Option<T> {
type Result<E> = result::Result<T, E>;
fn or_context<L>(self, _ty: L) -> Self::Result<Error>
where
L: Context,
{
self.ok_or(Error(RawError::new_const::<L>()))
}
}
impl<T> BuilderExt for Option<T> {
type Result<E> = result::Result<T, E>;
type E = Nae;
type S = Stateless;
type F = Immediate<payload::Empty>;
type L = context::Blank;
fn with_context_ty<L>(self) -> Self::Result<Builder<Self::E, Self::S, Self::F, L>>
where
L: Context,
{
self.ok_or(Builder {
err: Nae::new(),
context: PhantomData,
state: (),
payload_fn: Immediate(payload::Empty::new()),
})
}
fn with_state<S>(self, state: S) -> Self::Result<Builder<Self::E, S, Self::F, Self::L>>
where
S: State,
{
self.ok_or(Builder {
state: state.into_repr(),
err: Nae::new(),
context: PhantomData,
payload_fn: Immediate(payload::Empty::new()),
})
}
fn with_payload_fn<F>(
self,
payload_fn: F,
) -> Self::Result<Builder<Self::E, Self::S, F, Self::L>>
where
F: PayloadFn,
{
self.ok_or(Builder {
err: Nae::new(),
context: PhantomData,
state: (),
payload_fn,
})
}
}