// FIXME: Make it possible to convert to BError from // any other StdError type, instead of using the e() // extension method. // // This can only be done by _not_ implementing StdError, // but using a new trait like Fail. use std::error::Error as StdError; use std::result::Result as StdResult; use std::fmt::{self, Display, Debug, Formatter}; use std::process; pub type BResult = StdResult; pub struct BError(Box); // FIXME: Figure out how to use unsized types for unboxed kind // FIXME: Limit kind to all types that implement Display // _except_ for str / String // FIXME: Would like to make it possible to require // context be added to errors before returning. struct BErrorInner { kind: Box, source: Option>, } impl BError { pub fn new(kind: K) -> BError where K: Display + Send + Sync + 'static { BError(Box::new(BErrorInner { kind: Box::new(kind), source: None, })) } pub fn from_source(source: E, kind: K) -> BError where E: StdError + Send + Sync + 'static, K: Display + Send + Sync + 'static { BError(Box::new(BErrorInner { kind: Box::new(kind), source: Some(Box::new(source)), })) } } impl StdError for BError { fn source(&self) -> Option<&(dyn StdError + 'static)> { match self.0.source { Some(ref e) => Some(e.as_ref()), None => None, } } } impl Display for BError { fn fmt(&self, f: &mut Formatter) -> fmt::Result { self.0.kind.fmt(f) } } impl Debug for BError { fn fmt(&self, f: &mut Formatter) -> fmt::Result { f.debug_struct("BError") .field("kind", &format!("{}", &self.0.kind)) .field("source", &self.0.source) .finish() } } pub trait StdResultExt: Sized { fn ec(self, kind: K) -> StdResult where K: Display + Send + Sync + 'static; fn e(self) -> StdResult { self.ec("error") } } impl StdResultExt for StdResult where E: StdError + Send + Sync + 'static { fn ec(self, kind: K) -> StdResult where K: Display + Send + Sync + 'static { match self { Ok(v) => Ok(v), Err(e) => Err(BError::from_source(e, kind)) } } } pub fn main(run: impl FnOnce() -> BResult<()>) { if let Err(e) = run() { println!("error: {}", e); let mut e = e.source(); while let Some(cause) = e { println!(" caused by: {}", cause); e = cause.source(); } process::exit(1); } } #[test] fn test() { #[derive(Debug)] pub struct TestError; impl StdError for TestError { } impl Display for TestError { fn fmt(&self, _f: &mut Formatter) -> fmt::Result { panic!() } } fn ret_s_t() -> StdResult<(), TestError> { panic!() } fn ret_s_b() -> StdResult<(), BError> { panic!() } fn try_s_t() -> StdResult<(), TestError> { //ret_s_t().c("test")?; //ret_s_t().c("test")?; Ok(()) } fn try_s_b() -> StdResult<(), BError> { ret_s_t().c("test")?; ret_s_b().c("test")?; Ok(()) } }