diff --git a/src/morethantext/error.rs b/src/morethantext/error.rs index 5da4967..497f915 100644 --- a/src/morethantext/error.rs +++ b/src/morethantext/error.rs @@ -1,39 +1,112 @@ -use std::{error::Error, fmt}; +use std::{error::Error, fmt, sync::Arc}; #[derive(Debug)] -pub struct MTTError { - detail: String, +pub enum MTTError { + Generic(Generic), } -impl MTTError { - fn new(detail: &str) -> Self { - Self { - detail: detail.to_string(), +impl Error for MTTError { + fn source(&self) -> Option<&(dyn Error + 'static)> { + match self { + MTTError::Generic(err) => err.source(), } } } impl fmt::Display for MTTError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + MTTError::Generic(err) => write!(f, "{}", err), + } + } +} + +impl From for MTTError { + fn from(err: Generic) -> Self { + MTTError::Generic(err) + } +} + +#[derive(Debug)] +pub struct Generic { + detail: String, + source: Option>, +} + +impl Generic { + fn new(detail: &str) -> Self { + Self { + detail: detail.to_string(), + source: None, + } + } + + fn add_source(&mut self, source: MTTError) { + self.source = Some(Arc::new(source)); + } +} + +impl Error for Generic { + fn source(&self) -> Option<&(dyn Error + 'static)> { + match &self.source { + Some(err) => Some(err.as_ref()), + None => None, + } + } +} + +impl fmt::Display for Generic { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.detail) } } -impl Error for MTTError {} - #[cfg(test)] -mod errors { +mod generics { use super::*; #[test] fn new_error() { let detail = "new error"; - let err = MTTError::new(detail); + let err = Generic::new(detail); assert!( err.to_string() == detail, "\n\nGot: {}\nWant: {}\n\n", err.to_string(), detail ); + assert!( + err.source().is_none(), + "Error source should initialoze to None." + ); + let error: MTTError = err.into(); + assert!( + error.to_string() == detail, + "\n\nGot: {}\nWant: {}\n\n", + error.to_string(), + detail + ); + } + + #[test] + fn error_with_source() { + let par_detail = "parent error"; + let cld_detail = "child error"; + let par_err = Generic::new(par_detail); + let mut cld_err = Generic::new(cld_detail); + cld_err.add_source(par_err.into()); + assert!( + cld_err.source().unwrap().to_string() == par_detail, + "/n/nGot: {}\nWant: {}\n\n", + cld_err.source().unwrap().to_string(), + par_detail + ); + let error: MTTError = cld_err.into(); + assert!( + error.source().unwrap().to_string() == par_detail, + "/n/nGot: {}\nWant: {}\n\n", + error.source().unwrap().to_string(), + par_detail + ); } }