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 }