identity_core/common/
single_struct_error.rsuse std::borrow::Cow;
use std::error::Error;
use std::fmt::Debug;
use std::fmt::Display;
#[derive(Debug)]
pub struct SingleStructError<T: Debug + Display> {
repr: Repr<T>,
}
impl<T: Display + Debug> Display for SingleStructError<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.repr {
Repr::Simple(ref kind) => write!(f, "{kind}"),
Repr::Extensive(ref extensive) => {
write!(f, "{}", &extensive.kind)?;
let Some(ref message) = extensive.message else {
return Ok(());
};
write!(f, " message: {}", message.as_ref())
}
}
}
}
impl<T: Debug + Display> Error for SingleStructError<T> {
fn source(&self) -> Option<&(dyn Error + 'static)> {
self.extensive().and_then(|err| {
err
.source
.as_ref()
.map(|source| source.as_ref() as &(dyn Error + 'static))
})
}
}
#[derive(Debug)]
struct Extensive<T: Debug + Display> {
kind: T,
source: Option<Box<dyn Error + Send + Sync + 'static>>,
message: Option<Cow<'static, str>>,
}
#[derive(Debug)]
enum Repr<T: Debug + Display> {
Simple(T),
Extensive(Box<Extensive<T>>),
}
impl<T: Debug + Display> From<T> for SingleStructError<T> {
fn from(kind: T) -> Self {
Self::new(kind)
}
}
impl<T: Debug + Display> From<Box<Extensive<T>>> for SingleStructError<T> {
fn from(extensive: Box<Extensive<T>>) -> Self {
Self {
repr: Repr::Extensive(extensive),
}
}
}
impl<T: Debug + Display> SingleStructError<T> {
pub fn new(kind: T) -> Self {
Self {
repr: Repr::Simple(kind),
}
}
pub fn kind(&self) -> &T {
match self.repr {
Repr::Simple(ref cause) => cause,
Repr::Extensive(ref extensive) => &extensive.kind,
}
}
pub fn into_kind(self) -> T {
match self.repr {
Repr::Simple(cause) => cause,
Repr::Extensive(extensive) => extensive.kind,
}
}
pub fn custom_message(&self) -> Option<&str> {
self
.extensive()
.into_iter()
.flat_map(|extensive| extensive.message.as_deref())
.next()
}
pub fn source_ref(&self) -> Option<&(dyn Error + Send + Sync + 'static)> {
self.extensive().and_then(|extensive| extensive.source.as_deref())
}
pub fn into_source(self) -> Option<Box<dyn Error + Send + Sync + 'static>> {
self.into_extensive().source
}
fn extensive(&self) -> Option<&Extensive<T>> {
match self.repr {
Repr::Extensive(ref extensive) => Some(extensive.as_ref()),
_ => None,
}
}
fn into_extensive(self) -> Box<Extensive<T>> {
match self.repr {
Repr::Extensive(extensive) => extensive,
Repr::Simple(kind) => Box::new(Extensive {
kind,
source: None,
message: None,
}),
}
}
pub fn with_source(self, source: impl Into<Box<dyn Error + Send + Sync + 'static>>) -> Self {
self._with_source(source.into())
}
fn _with_source(self, source: Box<dyn Error + Send + Sync + 'static>) -> Self {
let mut extensive = self.into_extensive();
extensive.as_mut().source = Some(source);
Self::from(extensive)
}
pub fn with_custom_message(self, message: impl Into<Cow<'static, str>>) -> Self {
self._with_custom_message(message.into())
}
fn _with_custom_message(self, message: Cow<'static, str>) -> Self {
let mut extensive = self.into_extensive();
extensive.as_mut().message = Some(message);
Self::from(extensive)
}
}