From 9538f4bc4655bfc81b9580b5a1592382a48b6fcd Mon Sep 17 00:00:00 2001 From: Avril Date: Thu, 27 Aug 2020 20:17:31 +0100 Subject: [PATCH] take two --- src/error.rs | 274 ++++++++++++++------------------------------------- src/main.rs | 22 +---- 2 files changed, 77 insertions(+), 219 deletions(-) diff --git a/src/error.rs b/src/error.rs index 979cddf..1612ab9 100644 --- a/src/error.rs +++ b/src/error.rs @@ -4,257 +4,133 @@ use std::{ fmt, }; -//TODO: -// this was a complete failure, look at eyre instead or something - -/// Context for an error -#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)] -pub struct Context -{ - line: Option, - column: Option, - file: &'static str, -} - -impl Context -{ - pub fn new(line: Option, column: Option, file: &'static str) -> Self - { - Self { - line,column,file - } - } -} - -impl fmt::Display for Context +pub trait Context { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result - { - write!(f, "{} ", self.file)?; - if let Some(line) = self.line { - write!(f, "{}:", line)?; - } else { - write!(f, "?:")?; - } - if let Some(column) = self.column { - write!(f, "{}", column)?; - } else { - write!(f, "?")?; - } - Ok(()) - } + fn line(&self) -> Option; + fn column(&self) -> Option; + fn file(&self) -> Option<&str>; } -/// A wrapper over an error with a nicer error message -/// -/// Like doushio's `Muggle`. -pub struct Wrap(E, D); - -pub trait WrappedError +pub trait Reporter { - fn long_msg(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result; - fn short_msg(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result; -} + type Error: error::Error + ?Sized; -impl WrappedError for Wrap -where D: fmt::Display, - E: error::Error + 'static -{ - fn long_msg(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + #[inline] fn context(&self) -> Option<&dyn Context> { - write!(f, "{}", self.long_message()) + None } - fn short_msg(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + fn source(&self) -> &Self::Error; + + fn short_message(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result; + #[inline] fn long_message(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self) + self.short_message(f) } } -impl Wrap -where D: fmt::Display, - E: error::Error + 'static -{ - /// Get all sources of the error - pub fn all_sources(&self) -> Vec<&(dyn error::Error + 'static)> - { - use std::error::Error; - std::iter::successors(self.source(), |x| x.source()).collect() - } - - /// Into the inner error - pub fn into_inner(self) -> E - { - self.0 - } +pub struct ShortMessage(R) +where R: Reporter; - /// Get the full and long error message - pub fn long_message(&self) -> impl fmt::Display + '_ +impl fmt::Display for ShortMessage +where R: Reporter +{ + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - struct LongOutput<'a, E,D>(&'a Wrap); - impl<'a, E,D> fmt::Display for LongOutput<'a, E,D> - where Wrap: error::Error - { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result - { - writeln!(f, "{}", self.0)?; - use std::error::Error; - for (i, spec) in (1..).zip(std::iter::successors(self.0.source(), |x| x.source())) - { - writeln!(f, " [{}] -> {}", i, spec)?; - } - - Ok(()) - } - } - - LongOutput(&self) + self.0.short_message(f) } } -pub trait WrapExt: Sized -{ - /// Wrap this error in another - fn wrap(self, msg: T) -> Wrap - where T: fmt::Display; -} +pub struct LongMessage(R) +where R: Reporter; -impl WrapExt for E where E: error::Error +impl fmt::Display for LongMessage +where R: Reporter { - fn wrap(self, msg: T) -> Wrap - where T: fmt::Display + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - Wrap(self, msg) + self.0.long_message(f) } } -pub trait WrapErrExt: Sized +impl Reporter for Box +where E: error::Error + ?Sized { - /// Wrap the error from this result with a nicer error message - fn wrap_err(self, msg: U) -> Result> - where U: fmt::Display; -} + type Error = E; -impl WrapErrExt for Result -{ - fn wrap_err(self, msg: U) -> Result> - where U: fmt::Display + fn source(&self) -> &Self::Error { - self.map_err(|e| Wrap(e, msg)) + &self } -} - - -impl fmt::Debug for Wrap -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + + fn short_message(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", std::any::type_name::()) + write!(f, "{}", &self) } } -impl fmt::Display for Wrap -where D: fmt::Display +impl<'a, R> Reporter for &'a R +where R: Reporter { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + type Error = ::Error; + + #[inline] fn context(&self) -> Option<&dyn Context> { - write!(f, "{}", self.1) + (*self).context() } -} - -impl error::Error for Wrap -where E: error::Error + 'static, - D: fmt::Display -{ - fn source(&self) -> Option<&(dyn error::Error + 'static)> + fn source(&self) -> &Self::Error { - Some(&self.0) + (*self).source() } -} - -/// An error with a context -#[derive(Debug)] -pub struct ContextError(pub E, pub Context) -where E: fmt::Debug; - -impl WrappedError for ContextError -where E: fmt::Debug + fmt::Display -{ - fn long_msg(&self,f: &mut fmt::Formatter<'_>) -> fmt::Result + + fn short_message(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self) + (*self).short_message(f) } - fn short_msg(&self,f: &mut fmt::Formatter<'_>) -> fmt::Result + #[inline] fn long_message(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0) + (*self).long_message(f) } } -impl fmt::Display for ContextError -where E: fmt::Display + fmt::Debug +pub struct Wrap(E, M); + +impl Reporter for Wrap +where E: Reporter, +M: fmt::Display { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + type Error = E::Error; + + #[inline] fn context(&self) -> Option<&dyn Context> { - write!(f, "{}: {}", self.1, self.0) + self.0.context() } -} - -impl error::Error for ContextError -where E: fmt::Display + fmt::Debug{} - -#[macro_export] - macro_rules! context { - () => ($crate::error::Context::new(Some(line!()), Some(column!()), file!())); -} - -/// Construct a new error with context -#[macro_export] macro_rules! error { - ($err:expr) => ($crate::error::ContextError($err, $crate::context!())); - ($fmt:literal $($tt:tt)*) => ($crate::error!(format!($fmt $($tt)*))); -} - -pub struct ErrorStack(Box); - -impl From for ErrorStack -{ - fn from(from: T) -> Self + fn source(&self) -> &Self::Error { - Self(Box::new(from)) + self.0.source() } -} - -impl fmt::Display for ErrorStack -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + + fn short_message(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.long_msg(f) + write!(f, "{}", self.1) } -} - -impl fmt::Debug for ErrorStack -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + #[inline] fn long_message(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f,"") + write!(f, "{}", self.1)?; + self.0.long_message(f) //ehh, also failed } } -impl error::Error for ErrorStack{} - -impl ErrorStack -{ - /// Get the short message from this stack - pub fn short_message(&self) -> impl fmt::Display + '_ +#[cfg(test)] +mod tests { + use super::*; + fn test() -> Box { - pub struct ShortMessage<'a>(&'a ErrorStack); - - impl<'a> fmt::Display for ShortMessage<'a> - { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result - { - self.0.0.short_msg(f) - } - } - - ShortMessage(self) + Box::new(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "uhhhhh")) + } + #[test] + fn atest() + { + let bx = test(); + assert_eq!(format!("{}", LongMessage(&bx)), format!("{}", bx)); } } diff --git a/src/main.rs b/src/main.rs index 64def7b..3b5e444 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,10 +7,6 @@ mod ext; use ext::*; mod error; -use error::{ - WrapErrExt as _, - WrapExt as _, -}; mod consts; mod util; mod hash; @@ -18,21 +14,8 @@ mod metadata; mod resolve; mod database; -fn inner() -> Result<(), error::ErrorStack> +async fn begin() -> Result> { - Err(error!("constructing an error"))?; - Ok(()) -} - -fn outer() -> Result<(), error::ErrorStack> -{ - inner().wrap_err("propagating an error")?; - Ok(()) -} - -async fn begin() -> Result -{ - outer().wrap_err("outer failed").wrap_err("outer failed twice!")?; Ok(0) } @@ -41,8 +24,7 @@ async fn main() { std::process::exit(match begin().await { Ok(0) => return, Err(err) => { - eprintln!("\nexited with error: {}", err.short_message()); - println!("\n{}", err); + eprintln!("\nexited with error: {}", err); 1 }, Ok(v) => v