use alloc::boxed::Box;
use alloc::string::String;
use alloc::string::ToString;
use alloc::vec;
use alloc::vec::Vec;
use core::error::Error;
use core::fmt;
use core::marker::PhantomData;
use core::ops::Deref;
use core::panic::Location;
pub struct Exn<E: Error + Send + Sync + 'static> {
frame: Box<Frame>,
phantom: PhantomData<E>,
}
impl<E: Error + Send + Sync + 'static> From<E> for Exn<E> {
#[track_caller]
fn from(error: E) -> Self {
Exn::new(error)
}
}
impl<E: Error + Send + Sync + 'static> Exn<E> {
#[track_caller]
pub fn new(error: E) -> Self {
struct SourceError(String);
impl fmt::Debug for SourceError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.0, f)
}
}
impl fmt::Display for SourceError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
impl Error for SourceError {}
fn walk(error: &dyn Error, location: &'static Location<'static>) -> Vec<Frame> {
if let Some(source) = error.source() {
let children = vec![Frame {
error: Box::new(SourceError(source.to_string())),
location,
children: walk(source, location),
}];
children
} else {
vec![]
}
}
let location = Location::caller();
let children = walk(&error, location);
let frame = Frame {
error: Box::new(error),
location,
children,
};
Self {
frame: Box::new(frame),
phantom: PhantomData,
}
}
#[track_caller]
pub fn raise_all<T, I>(error: E, children: I) -> Self
where
T: Error + Send + Sync + 'static,
I: IntoIterator,
I::Item: Into<Exn<T>>,
{
let mut new_exn = Exn::new(error);
for exn in children {
let exn = exn.into();
new_exn.frame.children.push(*exn.frame);
}
new_exn
}
#[track_caller]
pub fn raise<T: Error + Send + Sync + 'static>(self, err: T) -> Exn<T> {
let mut new_exn = Exn::new(err);
new_exn.frame.children.push(*self.frame);
new_exn
}
pub fn frame(&self) -> &Frame {
&self.frame
}
}
impl<E> Deref for Exn<E>
where
E: Error + Send + Sync + 'static,
{
type Target = E;
fn deref(&self) -> &Self::Target {
self.frame
.error()
.downcast_ref()
.expect("error type must match")
}
}
pub struct Frame {
error: Box<dyn Error + Send + Sync + 'static>,
location: &'static Location<'static>,
children: Vec<Frame>,
}
impl Frame {
pub fn error(&self) -> &(dyn Error + Send + Sync + 'static) {
&*self.error
}
pub fn location(&self) -> &'static Location<'static> {
self.location
}
pub fn children(&self) -> &[Frame] {
&self.children
}
}
impl Error for Frame {
fn source(&self) -> Option<&(dyn Error + 'static)> {
self.children
.first()
.map(|child| child as &(dyn Error + 'static))
}
}
impl<E: Error + Send + Sync + 'static> From<Exn<E>> for Box<dyn Error + 'static> {
fn from(exn: Exn<E>) -> Self {
exn.frame
}
}
impl<E: Error + Send + Sync + 'static> From<Exn<E>> for Box<dyn Error + Send + 'static> {
fn from(exn: Exn<E>) -> Self {
exn.frame
}
}
impl<E: Error + Send + Sync + 'static> From<Exn<E>> for Box<dyn Error + Send + Sync + 'static> {
fn from(exn: Exn<E>) -> Self {
exn.frame
}
}