use alloc::{borrow::Cow, boxed::Box, string::String};
use core::{
any::type_name,
error::Error,
fmt::{Debug, Display},
ops::Deref,
};
#[cfg(all(feature = "backtrace", feature = "std"))]
use std::backtrace::Backtrace;
use crate::cause::{Cause, CauseInner, Chain};
use crate::inner::UniErrorInner;
use crate::kind::{UniKind, UniKindCode, UniKindCodes};
#[derive(Debug)]
pub struct UniError<K: ?Sized> {
inner: UniErrorInner<K>,
}
impl<K> UniError<K> {
pub(crate) fn new(
kind: K,
context: Option<Cow<'static, str>>,
cause: Option<CauseInner>,
) -> Self {
Self {
inner: UniErrorInner::new(kind, context, cause),
}
}
pub fn from_kind_boxed(kind: K, error: Box<dyn Error + Send + Sync>) -> Self {
Self::new(kind, None, Some(CauseInner::from_boxed_error(error)))
}
pub fn from_kind_context_boxed(
kind: K,
context: impl Into<Cow<'static, str>>,
error: Box<dyn Error + Send + Sync>,
) -> Self {
Self::new(
kind,
Some(context.into()),
Some(CauseInner::from_boxed_error(error)),
)
}
pub fn from_kind(kind: K) -> Self {
Self::new(kind, None, None)
}
pub fn from_kind_context(kind: K, context: impl Into<Cow<'static, str>>) -> Self {
Self::new(kind, Some(context.into()), None)
}
pub fn type_name(&self) -> &'static str {
type_name::<Self>()
}
}
impl<K: Default> UniError<K> {
pub fn from_kind_default_context(context: impl Into<Cow<'static, str>>) -> Self {
Self::new(Default::default(), Some(context.into()), None)
}
pub fn from_boxed(error: Box<dyn Error + Send + Sync>) -> Self {
Self::new(
Default::default(),
None,
Some(CauseInner::from_boxed_error(error)),
)
}
pub fn from_context_boxed(
context: impl Into<Cow<'static, str>>,
error: Box<dyn Error + Send + Sync>,
) -> Self {
Self::new(
Default::default(),
Some(context.into()),
Some(CauseInner::from_boxed_error(error)),
)
}
}
impl<K: ?Sized + 'static> UniError<K> {
#[cfg(all(feature = "backtrace", feature = "std"))]
pub fn backtrace(&self) -> &Backtrace {
&self.inner.backtrace()
}
pub fn kind_ref(&self) -> &K {
self.inner.kind_ref()
}
pub fn is_simple(&self) -> bool {
self.inner.is_simple()
}
pub fn prev_cause<'e>(&'e self) -> Option<Cause<'e>> {
self.inner.prev_cause()
}
pub fn chain(&self) -> Chain<'_> {
Chain::new(self.prev_cause())
}
pub fn root_cause(&self) -> Option<Cause<'_>> {
let mut chain = self.chain();
let mut root = chain.next();
for next in chain {
root = Some(next);
}
root
}
pub fn add_context(self, context: impl Into<Cow<'static, str>>) -> Self {
UniError {
inner: self.inner.add_context(context),
}
}
}
impl<K: Clone> UniError<K> {
pub fn kind_clone(&self) -> K {
self.inner.kind_clone()
}
pub fn kind_map<F, K2>(self, f: F) -> UniError<K2>
where
F: FnOnce(Self, K) -> UniError<K2>,
{
let kind = self.kind_clone();
f(self, kind)
}
}
impl<K: UniKind> UniError<K> {
pub fn into_dyn_kind(self) -> UniError<dyn UniKind> {
UniError {
inner: self.inner.into_dyn_kind(),
}
}
pub fn kind<K2>(self, kind: K2) -> UniError<K2> {
UniError::new(kind, None, Some(CauseInner::from_uni_error(self)))
}
pub fn kind_default_context<K2>(self, context: impl Into<Cow<'static, str>>) -> UniError<K2>
where
K2: Default,
{
UniError::new(
Default::default(),
Some(context.into()),
Some(CauseInner::from_uni_error(self)),
)
}
pub fn kind_context<K2>(self, kind: K2, context: impl Into<Cow<'static, str>>) -> UniError<K2> {
UniError::new(
kind,
Some(context.into()),
Some(CauseInner::from_uni_error(self)),
)
}
pub fn kind_default<K2>(self) -> UniError<K2>
where
K2: Default,
{
UniError::new(
Default::default(),
None,
Some(CauseInner::from_uni_error(self)),
)
}
pub fn kind_into<K2>(self) -> UniError<K2>
where
K: Clone + Into<K2>,
{
UniError::new(
self.kind_clone().into(),
None,
Some(CauseInner::from_uni_error(self)),
)
}
pub fn kind_into_context<K2>(self, context: impl Into<Cow<'static, str>>) -> UniError<K2>
where
K: Clone + Into<K2>,
{
UniError::new(
self.kind_clone().into(),
Some(context.into()),
Some(CauseInner::from_uni_error(self)),
)
}
}
impl<K: UniKind + ?Sized> UniError<K> {
pub fn kind_code(&self) -> i32 {
self.kind_ref().code(self.prev_cause())
}
pub fn kind_code2(&self) -> i32 {
self.kind_ref().code2(self.prev_cause())
}
pub fn kind_value(&self) -> Cow<'static, str> {
self.kind_ref().value(self.prev_cause())
}
pub fn kind_context_str(&self) -> Option<Cow<'static, str>> {
self.kind_ref().context(self.prev_cause())
}
}
impl<K: UniKindCode> UniError<K> {
pub fn into_dyn_kind_code(self) -> UniError<dyn UniKindCode<Code = K::Code>> {
UniError {
inner: self.inner.into_dyn_kind_code(),
}
}
}
impl<K: UniKindCode + ?Sized> UniError<K> {
pub fn typed_code(&self) -> K::Code {
self.kind_ref().typed_code(self.prev_cause())
}
}
impl<K: UniKindCodes> UniError<K> {
pub fn into_dyn_kind_codes(
self,
) -> UniError<dyn UniKindCodes<Code = K::Code, Code2 = K::Code2>> {
UniError {
inner: self.inner.into_dyn_kind_codes(),
}
}
}
impl<K: UniKindCodes + ?Sized> UniError<K> {
pub fn typed_code2(&self) -> K::Code2 {
self.kind_ref().typed_code2(self.prev_cause())
}
}
impl UniError<dyn UniKind> {
pub fn kind_dyn_ref(&self) -> &dyn UniKind {
self.kind_ref()
}
pub fn into_typed_kind<K: UniKind>(self) -> Option<UniError<K>> {
self.inner
.into_typed_kind::<K>()
.map(|inner| UniError { inner })
}
pub fn to_typed_kind<K: UniKind>(&self) -> Option<UniError<K>> {
self.inner
.to_typed_kind::<K>()
.map(|inner| UniError { inner })
}
pub fn type_name(&self) -> String {
let start = "uni_error::error::UniError<";
let end = ">";
let kind_type = self.kind_ref().type_name();
alloc::format!("{start}{kind_type}{end}")
}
pub fn kind<K2>(self, kind: K2) -> UniError<K2> {
UniError::new(kind, None, Some(CauseInner::from_dyn_error(self)))
}
pub fn kind_default_context<K2>(self, context: impl Into<Cow<'static, str>>) -> UniError<K2>
where
K2: Default,
{
UniError::new(
Default::default(),
Some(context.into()),
Some(CauseInner::from_dyn_error(self)),
)
}
pub fn kind_context<K2>(self, kind: K2, context: impl Into<Cow<'static, str>>) -> UniError<K2> {
UniError::new(
kind,
Some(context.into()),
Some(CauseInner::from_dyn_error(self)),
)
}
pub fn kind_default<K2>(self) -> UniError<K2>
where
K2: Default,
{
UniError::new(
Default::default(),
None,
Some(CauseInner::from_dyn_error(self)),
)
}
}
impl<C: 'static> UniError<dyn UniKindCode<Code = C>> {
pub fn kind_dyn_ref(&self) -> &dyn UniKindCode<Code = C> {
self.kind_ref()
}
pub fn into_typed_kind<K: UniKindCode<Code = C>>(self) -> Option<UniError<K>> {
self.inner
.into_typed_kind::<K>()
.map(|inner| UniError { inner })
}
pub fn to_typed_kind<K: UniKindCode<Code = C>>(&self) -> Option<UniError<K>> {
self.inner
.to_typed_kind::<K>()
.map(|inner| UniError { inner })
}
pub fn type_name(&self) -> String {
let start = "uni_error::error::UniError<";
let end = ">";
let kind_type = self.kind_ref().type_name();
alloc::format!("{start}{kind_type}{end}")
}
pub fn into_dyn_kind(self) -> UniError<dyn UniKind> {
UniError {
inner: self.inner.into_dyn_kind(),
}
}
pub fn kind<K2>(self, kind: K2) -> UniError<K2> {
UniError::new(kind, None, Some(CauseInner::from_dyn_code_error(self)))
}
pub fn kind_default_context<K2>(self, context: impl Into<Cow<'static, str>>) -> UniError<K2>
where
K2: Default,
{
UniError::new(
Default::default(),
Some(context.into()),
Some(CauseInner::from_dyn_code_error(self)),
)
}
pub fn kind_context<K2>(self, kind: K2, context: impl Into<Cow<'static, str>>) -> UniError<K2> {
UniError::new(
kind,
Some(context.into()),
Some(CauseInner::from_dyn_code_error(self)),
)
}
pub fn kind_default<K2>(self) -> UniError<K2>
where
K2: Default,
{
UniError::new(
Default::default(),
None,
Some(CauseInner::from_dyn_code_error(self)),
)
}
}
impl<C: 'static, C2: 'static> UniError<dyn UniKindCodes<Code = C, Code2 = C2>> {
pub fn kind_dyn_ref(&self) -> &dyn UniKindCodes<Code = C, Code2 = C2> {
self.kind_ref()
}
pub fn into_typed<K: UniKindCodes<Code = C, Code2 = C2>>(self) -> Option<UniError<K>> {
self.inner
.into_typed_kind::<K>()
.map(|inner| UniError { inner })
}
pub fn to_typed_kind<K: UniKindCodes<Code = C, Code2 = C2>>(&self) -> Option<UniError<K>> {
self.inner
.to_typed_kind::<K>()
.map(|inner| UniError { inner })
}
pub fn type_name(&self) -> String {
let start = "uni_error::error::UniError<";
let end = ">";
let kind_type = self.kind_ref().type_name();
alloc::format!("{start}{kind_type}{end}")
}
pub fn into_dyn_kind(self) -> UniError<dyn UniKind> {
UniError {
inner: self.inner.into_dyn_kind(),
}
}
pub fn kind<K2>(self, kind: K2) -> UniError<K2> {
UniError::new(kind, None, Some(CauseInner::from_dyn_codes_error(self)))
}
pub fn kind_default_context<K2>(self, context: impl Into<Cow<'static, str>>) -> UniError<K2>
where
K2: Default,
{
UniError::new(
Default::default(),
Some(context.into()),
Some(CauseInner::from_dyn_codes_error(self)),
)
}
pub fn kind_context<K2>(self, kind: K2, context: impl Into<Cow<'static, str>>) -> UniError<K2> {
UniError::new(
kind,
Some(context.into()),
Some(CauseInner::from_dyn_codes_error(self)),
)
}
pub fn kind_default<K2>(self) -> UniError<K2>
where
K2: Default,
{
UniError::new(
Default::default(),
None,
Some(CauseInner::from_dyn_codes_error(self)),
)
}
}
impl<K: UniKind + ?Sized> Display for UniError<K> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
<UniErrorInner<K> as Display>::fmt(&self.inner, f)
}
}
impl<K: ?Sized> Clone for UniError<K> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
}
}
}
impl<K: PartialEq + ?Sized + 'static> PartialEq for UniError<K> {
fn eq(&self, other: &Self) -> bool {
self.inner.eq(&other.inner)
}
}
impl<K: UniKind + ?Sized> Deref for UniError<K> {
type Target = dyn Error + Sync + Send + 'static;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<K: UniKind + ?Sized> AsRef<dyn Error + Sync + Send> for UniError<K> {
fn as_ref(&self) -> &(dyn Error + Sync + Send + 'static) {
&**self
}
}