#![deny(clippy::all)]
#![warn(clippy::nursery)]
#![warn(clippy::pedantic)]
#![allow(clippy::use_self)]
use std::{error::Error as StdError, fmt, result::Result as StdResult};
mod macros;
pub type Result<T> = StdResult<T, Error>;
#[derive(Debug)]
pub struct Error
{
pub ctx: String,
pub cause: Option<Box<dyn StdError + 'static>>,
}
impl Error
{
pub fn new<S, E>(ctx: S, cause: E) -> Error
where
S: Into<String>,
E: StdError + 'static,
{
let ctx = ctx.into();
let cause: Option<Box<dyn StdError + 'static>> = Some(Box::new(cause));
Error { ctx, cause }
}
pub fn iter_causes(&self) -> Causes { Causes { cause: self.cause.as_ref().map(Box::as_ref) } }
}
impl fmt::Display for Error
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.ctx) }
}
impl StdError for Error
{
fn description(&self) -> &str { &self.ctx }
fn source(&self) -> Option<&(dyn StdError + 'static)> { self.cause.as_ref().map(Box::as_ref) }
}
pub struct Causes<'a>
{
cause: Option<&'a (dyn StdError + 'static)>,
}
impl<'a> Iterator for Causes<'a>
{
type Item = &'a (dyn StdError + 'static);
fn next(&mut self) -> Option<Self::Item>
{
let cause = self.cause.take();
self.cause = cause.and_then(StdError::source);
cause
}
}
pub trait ResultExt<T>
{
fn context<S: Into<String>>(self, ctx: S) -> Result<T>;
}
impl<T, E: StdError + 'static> ResultExt<T> for StdResult<T, E>
{
fn context<S: Into<String>>(self, ctx: S) -> Result<T>
{
self.map_err(|e| Error { ctx: ctx.into(), cause: Some(Box::new(e)) })
}
}
#[inline]
pub fn err_msg<S: Into<String>>(ctx: S) -> Error { Error { ctx: ctx.into(), cause: None } }
#[inline]
pub fn iter_causes<E: StdError>(e: &E) -> Causes { Causes { cause: e.source() } }