#![doc = include_str!("../README.md")]
use std::any::TypeId;
use std::fmt::{Debug, Display, Formatter};
use std::mem::ManuallyDrop;
use std::ptr;
pub use conerror_macro::conerror;
pub type Result<T> = std::result::Result<T, Error>;
pub struct Error(Box<Inner>);
impl Error {
pub fn new<T>(
error: T,
file: &'static str,
line: u32,
func: &'static str,
module: &'static str,
) -> Self
where
T: Into<Box<dyn std::error::Error + Send + Sync>>,
{
Self(Box::new(Inner {
source: error.into(),
location: Some(vec![Location {
file,
line,
func,
module,
}]),
}))
}
pub fn plain<T>(error: T) -> Self
where
T: Into<Box<dyn std::error::Error + Send + Sync>>,
{
Self(Box::new(Inner {
source: error.into(),
location: None,
}))
}
pub fn chain<T>(
error: T,
file: &'static str,
line: u32,
func: &'static str,
module: &'static str,
) -> Self
where
T: std::error::Error + Send + Sync + 'static,
{
if TypeId::of::<T>() == TypeId::of::<Self>() {
let error = ManuallyDrop::new(error);
let mut error = unsafe { ptr::read(&error as *const _ as *const Self) };
if let Some(ref mut location) = error.0.location {
location.push(Location {
file,
line,
func,
module,
});
}
return error;
}
Self::new(error, file, line, func, module)
}
pub fn location(&self) -> Option<&[Location]> {
self.0.location.as_ref().map(|v| v.as_slice())
}
}
impl Debug for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Error")
.field("source", &self.0.source)
.field("location", &self.0.location)
.finish()
}
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Display::fmt(&self.0.source, f)?;
if let Some(ref location) = self.0.location {
for (i, v) in location.iter().enumerate() {
write!(f, "\n#{} {}", i, v)?;
}
}
Ok(())
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Some(&*self.0.source)
}
}
struct Inner {
source: Box<dyn std::error::Error + Send + Sync>,
location: Option<Vec<Location>>,
}
#[derive(Debug)]
pub struct Location {
pub file: &'static str,
pub line: u32,
pub func: &'static str,
pub module: &'static str,
}
impl Display for Location {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}:{} {}::{}()",
self.file, self.line, self.module, self.func
)
}
}