failed again. just fucking use eyre or color-eyre ffs

work
Avril 4 years ago
parent 9538f4bc46
commit 3d254efc4b
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -4,133 +4,320 @@ use std::{
fmt, fmt,
}; };
pub trait Context #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, Default)]
pub struct Context
{ {
fn line(&self) -> Option<u32>; file: Option<&'static str>,
fn column(&self) -> Option<u32>; line: Option<u32>,
fn file(&self) -> Option<&str>; column: Option<u32>,
} }
pub trait Reporter impl Context
{ {
type Error: error::Error + ?Sized; pub fn with_all(file: &'static str, line: u32, column: u32) -> Self
{
Self {
file: Some(file),
line: Some(line),
column: Some(column)
}
}
}
#[inline] fn context(&self) -> Option<&dyn Context> impl fmt::Display for Context
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{ {
None if let Some(file) = self.file {
write!(f, "{} ", file)
} else {
write!(f, "? ")
}?;
if let Some(line) = self.line {
write!(f, "{}:", line)
} else {
write!(f, "?:")
}?;
if let Some(column) = self.column {
write!(f, "{}", column)
} else {
write!(f, "?")
}
} }
fn source(&self) -> &Self::Error; }
fn short_message(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result; #[macro_export] macro_rules! context {
#[inline] fn long_message(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result () => ($crate::error::Context::with_all(file!(), line!(), column!()));
}
#[derive(Debug)]
pub struct ContextError<E>(E, Context)
where E: error::Error;
impl<E> ContextError<E>
where E: error::Error
{
pub fn with_context(from: E, ctx: Context) -> Self
{ {
self.short_message(f) Self(from, ctx)
} }
} }
pub struct ShortMessage<R>(R) impl<E> error::Error for ContextError<E>
where R: Reporter; where E: error::Error + 'static
{
fn source(&self) -> Option<&(dyn error::Error + 'static)>
{
Some(&self.0)
}
}
impl<R> fmt::Display for ShortMessage<R> impl<E> fmt::Display for ContextError<E>
where R: Reporter where E: error::Error
{ {
#[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{ {
self.0.short_message(f) write!(f, "{}: {}", self.1, self.0)
} }
} }
pub struct LongMessage<R>(R) #[macro_export] macro_rules! error {
where R: Reporter; ($msg:expr) => {
{
pub struct DisplayError<D>(D) where D: fmt::Display;
impl<D> fmt::Debug for DisplayError<D>
where D: fmt::Display
{
#[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
write!(f, "{}", std::any::type_name::<Self>())
}
}
impl<D> fmt::Display for DisplayError<D>
where D: fmt::Display
{
#[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
self.0.fmt(f)
}
}
impl<D> error::Error for DisplayError<D>
where D: fmt::Display{}
impl<R> fmt::Display for LongMessage<R> $crate::error::ContextError::with_context(DisplayError($msg), context!())
where R: Reporter }
};
(&fmt:literal $($tt:tt)*) => ($crate::error!(format!($literal $($tt)*)));
}
pub struct Wrap<E,D>(E,D);
impl<E,D> Wrap<E,D>
where E: error::Error + 'static,
D: fmt::Display
{ {
#[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result pub fn long_message(&self) -> impl fmt::Display + '_
{ {
self.0.long_message(f)
pub struct LongMessage<'a, E,D>(&'a Wrap<E,D>);
impl<'a, E,D> fmt::Display for LongMessage<'a,E,D>
where E: error::Error + 'static,
D: fmt::Display
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
use error::Error;
for (num, next) in (1..).zip(std::iter::successors(self.0.source(), |e| e.source()))
{
writeln!(f, " [{}] -> {}", num, next)?;
}
Ok(())
}
}
LongMessage(self)
} }
} }
impl<E> Reporter for Box<E> impl<E,D> fmt::Display for Wrap<E,D>
where E: error::Error + ?Sized where D: fmt::Display
{ {
type Error = E; fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
write!(f, "{}", self.1)
}
}
fn source(&self) -> &Self::Error impl<E,D> fmt::Debug for Wrap<E,D>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{ {
&self write!(f, "{}", std::any::type_name::<Self>())
} }
}
fn short_message(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
impl<E,D> error::Error for Wrap<E,D>
where E: error::Error + 'static,
D: fmt::Display
{
fn source(&self) -> Option<&(dyn error::Error + 'static)>
{ {
write!(f, "{}", &self) Some(&self.0)
} }
} }
impl<'a, R> Reporter for &'a R pub trait WrapErrExt<T,E>: Sized
where R: Reporter
{ {
type Error = <R as Reporter>::Error; #[inline] fn wrap_err<F,D>(self, val: D) -> Result<T, Wrap<E, D>>
where D: fmt::Display
#[inline] fn context(&self) -> Option<&dyn Context>
{ {
(*self).context() self.wrap_err_with(|| val)
} }
fn source(&self) -> &Self::Error fn wrap_err_with<F,D>(self, func: F) -> Result<T, Wrap<E, D>>
where D: fmt::Display,
F: FnOnce() -> D;
}
impl<T,E> WrapErrExt<T,E> for Result<T,E>
{
fn wrap_err_with<F,D>(self, func: F) -> Result<T, Wrap<E, D>>
where D: fmt::Display,
F: FnOnce() -> D
{ {
(*self).source() self.map_err(|e| Wrap(e, func()))
} }
}
// We can now define the reporter trait, like last time, and then out own reporter type for `Wrap<E,D>` that prints its long message properly
pub trait Reporter
{
type Error: error::Error + ?Sized;
#[inline] fn long_message(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result
{
Ok(())
}
fn short_message(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
fn source(&self) -> &Self::Error;
}
impl<E> Reporter for Box<E>
where E: error::Error + ?Sized
{
type Error = E;
fn short_message(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result fn short_message(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{ {
(*self).short_message(f) write!(f, "{}", self)
} }
#[inline] fn long_message(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
fn source(&self) -> &Self::Error
{ {
(*self).long_message(f) self
} }
} }
pub struct Wrap<E,M>(E, M); pub struct WrapReporter<E,D>(Wrap<E,D>);
impl<E,M> Reporter for Wrap<E,M> impl<E,D> Reporter for WrapReporter<E,D>
where E: Reporter, where E: error::Error + 'static,
M: fmt::Display D: fmt::Display
{ {
type Error = E::Error; type Error = E;
fn short_message(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
write!(f, "{}", self.0)
}
#[inline] fn context(&self) -> Option<&dyn Context> fn long_message(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{ {
self.0.context() write!(f, "{}", self.0.long_message())
} }
fn source(&self) -> &Self::Error fn source(&self) -> &Self::Error
{ {
self.0.source() &self.0.0
} }
}
impl<E,D> From<Wrap<E,D>> for WrapReporter<E,D>
{
fn from(from: Wrap<E,D>) -> Self
{
Self(from)
}
}
pub struct Report<E>(Box<E>) where E: ?Sized;
impl<E> From<E> for Report<E>
where E: error::Error
{
fn from(from: E) -> Self
{
Self(Box::new(from))
}
}
impl<E> From<Box<E>> for Report<E>
where E: error::Error + 'static + ?Sized
{
fn from(from: Box<E>) -> Self
{
Self(from)
}
}
impl<E> Reporter for Report<E>
where E: error::Error + ?Sized
{
type Error = E;
fn short_message(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result fn short_message(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{ {
write!(f, "{}", self.1) write!(f, "{}", self.0)
} }
#[inline] fn long_message(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
fn source(&self) -> &Self::Error
{ {
write!(f, "{}", self.1)?; &self.0
self.0.long_message(f) //ehh, also failed
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod test
{
use super::*; use super::*;
fn test() -> Box<dyn error::Error>
#[test]
fn test()
{ {
Box::new(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "uhhhhh")) let err: Result<(), _> = Err(error!("hello world"))
.wrap_err_with(|| error!("thing failed"))
.wrap_err_with(|| error!("top level failed again"));
if let Err(err) = err
{
panic!("{}\n\n{}", err, err.long_message());
}
} }
#[test] #[test]
fn atest() fn report()
{ {
let bx = test(); fn one() -> Result<(), Report<dyn error::Error>>
assert_eq!(format!("{}", LongMessage(&bx)), format!("{}", bx)); {
let err: Result<(), _> = Err(error!("hello world"))
.wrap_err_with(|| error!("thing failed"))
.wrap_err_with(|| error!("top level failed again"));
Ok(err?) //failed again. just fucking use eyre
}
} }
} }

Loading…
Cancel
Save