kanit

Toy init system
Log | Files | Refs | README | LICENSE

error.rs (4092B)


      1 use std::fmt::{self, Debug, Display, Formatter};
      2 
      3 pub type Result<T, E = Error> = std::result::Result<T, E>;
      4 
      5 #[derive(Debug)]
      6 pub enum ErrorKind {
      7     Recoverable,
      8     Unrecoverable,
      9 }
     10 
     11 type LazyContext = dyn Send + Fn() -> String;
     12 
     13 pub struct Error {
     14     kind: ErrorKind,
     15     context: Option<Box<LazyContext>>,
     16     original: Box<dyn std::error::Error + Send>,
     17 }
     18 
     19 impl Error {
     20     fn new<S: Display + Send + 'static>(
     21         kind: ErrorKind,
     22         context: Option<S>,
     23         original: Box<dyn std::error::Error + Send>,
     24     ) -> Self {
     25         Self {
     26             context: context.map(|n| Box::new(move || n.to_string()) as Box<LazyContext>),
     27             kind,
     28             original,
     29         }
     30     }
     31 
     32     pub fn is_recoverable(&self) -> bool {
     33         matches!(self.kind, ErrorKind::Recoverable)
     34     }
     35 }
     36 
     37 impl Display for Error {
     38     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
     39         if let Some(ref context) = self.context {
     40             write!(f, "{}: {}", context(), self.original)
     41         } else {
     42             write!(f, "{}", self.original)
     43         }
     44     }
     45 }
     46 
     47 impl Debug for Error {
     48     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
     49         f.debug_struct("Error")
     50             .field("kind", &self.kind)
     51             .field("original", &self.original)
     52             .finish()
     53     }
     54 }
     55 
     56 impl<E: std::error::Error + Send + 'static> From<E> for Error {
     57     fn from(error: E) -> Self {
     58         Self::new::<&str>(ErrorKind::Unrecoverable, None, Box::new(error))
     59     }
     60 }
     61 
     62 #[derive(Debug)]
     63 pub struct StaticError(pub &'static str);
     64 
     65 impl Display for StaticError {
     66     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
     67         write!(f, "{}", self.0)
     68     }
     69 }
     70 
     71 impl std::error::Error for StaticError {}
     72 
     73 pub struct WithError(Box<LazyContext>);
     74 
     75 impl WithError {
     76     pub fn with<F: Send + Fn() -> String + 'static>(e: F) -> Self {
     77         Self(Box::new(e) as Box<LazyContext>)
     78     }
     79 }
     80 
     81 impl Display for WithError {
     82     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
     83         write!(f, "{}", self.0())
     84     }
     85 }
     86 
     87 impl Debug for WithError {
     88     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
     89         f.debug_struct("Error").finish()
     90     }
     91 }
     92 
     93 impl std::error::Error for WithError {}
     94 
     95 pub trait Context<T>: Sized {
     96     fn context_kind<C: Display + Send + 'static>(self, context: C, kind: ErrorKind) -> Result<T>;
     97     fn with_context_kind<C: Send + Fn() -> String + 'static>(
     98         self,
     99         context: C,
    100         kind: ErrorKind,
    101     ) -> Result<T> {
    102         self.context_kind(WithError::with(context), kind)
    103     }
    104     fn context<C: Display + Send + 'static>(self, context: C) -> Result<T> {
    105         self.context_kind(context, ErrorKind::Unrecoverable)
    106     }
    107     fn with_context<C: Send + Fn() -> String + 'static>(self, context: C) -> Result<T> {
    108         self.with_context_kind(context, ErrorKind::Unrecoverable)
    109     }
    110     fn kind(self, kind: ErrorKind) -> Result<T>;
    111 }
    112 
    113 impl<T> Context<T> for Option<T> {
    114     fn context_kind<C: Display + Send + 'static>(self, context: C, kind: ErrorKind) -> Result<T> {
    115         match self {
    116             Some(ok) => Ok(ok),
    117             None => Err(Error::new(
    118                 kind,
    119                 Some(context),
    120                 Box::new(StaticError("attempted to unwrap 'None' value")),
    121             )),
    122         }
    123     }
    124 
    125     fn kind(self, kind: ErrorKind) -> Result<T> {
    126         match self {
    127             Some(ok) => Ok(ok),
    128             None => Err(Error::new::<&str>(
    129                 kind,
    130                 None,
    131                 Box::new(StaticError("attempted to unwrap 'None' value")),
    132             )),
    133         }
    134     }
    135 }
    136 
    137 impl<T, E: std::error::Error + Send + 'static> Context<T> for Result<T, E> {
    138     fn context_kind<C: Display + Send + 'static>(self, context: C, kind: ErrorKind) -> Result<T> {
    139         match self {
    140             Ok(ok) => Ok(ok),
    141             Err(e) => Err(Error::new(kind, Some(context), Box::new(e))),
    142         }
    143     }
    144 
    145     fn kind(self, kind: ErrorKind) -> Result<T> {
    146         match self {
    147             Ok(ok) => Ok(ok),
    148             Err(e) => Err(Error::new::<&str>(kind, None, Box::new(e))),
    149         }
    150     }
    151 }