1 use crate::{ErrReport, Result}; 2 use std::fmt::{self, Display}; 3 4 /// A helper trait for attaching help text to errors to be displayed after the chain of errors 5 pub trait Help<T>: private::Sealed { 6 /// Add a note to an error, to be displayed after the chain of errors. 7 /// 8 /// # Examples 9 /// 10 /// ```rust 11 /// # use std::{error::Error, fmt::{self, Display}}; 12 /// # use jane_eyre::Result; 13 /// # #[derive(Debug)] 14 /// # struct FakeErr; 15 /// # impl Display for FakeErr { 16 /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 17 /// # write!(f, "FakeErr") 18 /// # } 19 /// # } 20 /// # impl std::error::Error for FakeErr {} 21 /// # fn main() -> Result<()> { 22 /// # fn fallible_fn() -> Result<(), FakeErr> { 23 /// # Ok(()) 24 /// # } 25 /// use jane_eyre::Help as _; 26 /// 27 /// fallible_fn().note("This might have failed due to ...")?; 28 /// # Ok(()) 29 /// # } 30 /// ``` note<C>(self, context: C) -> Result<T> where C: Display + Send + Sync + 'static31 fn note<C>(self, context: C) -> Result<T> 32 where 33 C: Display + Send + Sync + 'static; 34 35 /// Add a Note to an error, to be displayed after the chain of errors, which is lazily 36 /// evaluated only in the case of an error. 37 /// 38 /// # Examples 39 /// 40 /// ```rust 41 /// # use std::{error::Error, fmt::{self, Display}}; 42 /// # use jane_eyre::Result; 43 /// # #[derive(Debug)] 44 /// # struct FakeErr; 45 /// # impl Display for FakeErr { 46 /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 47 /// # write!(f, "FakeErr") 48 /// # } 49 /// # } 50 /// # impl std::error::Error for FakeErr {} 51 /// # fn main() -> Result<()> { 52 /// # fn fallible_fn() -> Result<(), FakeErr> { 53 /// # Ok(()) 54 /// # } 55 /// use jane_eyre::Help as _; 56 /// 57 /// fallible_fn().with_note(|| { 58 /// format!("This might have failed due to ... It has failed {} times", 100) 59 /// })?; 60 /// # Ok(()) 61 /// # } 62 /// ``` with_note<C, F>(self, f: F) -> Result<T> where C: Display + Send + Sync + 'static, F: FnOnce() -> C63 fn with_note<C, F>(self, f: F) -> Result<T> 64 where 65 C: Display + Send + Sync + 'static, 66 F: FnOnce() -> C; 67 68 /// Add a Warning to an error, to be displayed after the chain of errors. warning<C>(self, context: C) -> Result<T> where C: Display + Send + Sync + 'static69 fn warning<C>(self, context: C) -> Result<T> 70 where 71 C: Display + Send + Sync + 'static; 72 73 /// Add a Warning to an error, to be displayed after the chain of errors, which is lazily 74 /// evaluated only in the case of an error. with_warning<C, F>(self, f: F) -> Result<T> where C: Display + Send + Sync + 'static, F: FnOnce() -> C75 fn with_warning<C, F>(self, f: F) -> Result<T> 76 where 77 C: Display + Send + Sync + 'static, 78 F: FnOnce() -> C; 79 80 /// Add a Suggestion to an error, to be displayed after the chain of errors. suggestion<C>(self, context: C) -> Result<T> where C: Display + Send + Sync + 'static81 fn suggestion<C>(self, context: C) -> Result<T> 82 where 83 C: Display + Send + Sync + 'static; 84 85 /// Add a Suggestion to an error, to be displayed after the chain of errors, which is lazily 86 /// evaluated only in the case of an error. with_suggestion<C, F>(self, f: F) -> Result<T> where C: Display + Send + Sync + 'static, F: FnOnce() -> C87 fn with_suggestion<C, F>(self, f: F) -> Result<T> 88 where 89 C: Display + Send + Sync + 'static, 90 F: FnOnce() -> C; 91 } 92 93 impl<T, E> Help<T> for std::result::Result<T, E> 94 where 95 E: Into<ErrReport>, 96 { note<C>(self, context: C) -> Result<T> where C: Display + Send + Sync + 'static,97 fn note<C>(self, context: C) -> Result<T> 98 where 99 C: Display + Send + Sync + 'static, 100 { 101 self.map_err(|e| { 102 let mut e = e.into(); 103 e.context_mut().help.push(HelpInfo::Note(Box::new(context))); 104 e 105 }) 106 } 107 with_note<C, F>(self, context: F) -> Result<T> where C: Display + Send + Sync + 'static, F: FnOnce() -> C,108 fn with_note<C, F>(self, context: F) -> Result<T> 109 where 110 C: Display + Send + Sync + 'static, 111 F: FnOnce() -> C, 112 { 113 self.map_err(|e| { 114 let mut e = e.into(); 115 e.context_mut() 116 .help 117 .push(HelpInfo::Note(Box::new(context()))); 118 e 119 }) 120 } 121 warning<C>(self, context: C) -> Result<T> where C: Display + Send + Sync + 'static,122 fn warning<C>(self, context: C) -> Result<T> 123 where 124 C: Display + Send + Sync + 'static, 125 { 126 self.map_err(|e| { 127 let mut e = e.into(); 128 e.context_mut() 129 .help 130 .push(HelpInfo::Warning(Box::new(context))); 131 e 132 }) 133 } 134 with_warning<C, F>(self, context: F) -> Result<T> where C: Display + Send + Sync + 'static, F: FnOnce() -> C,135 fn with_warning<C, F>(self, context: F) -> Result<T> 136 where 137 C: Display + Send + Sync + 'static, 138 F: FnOnce() -> C, 139 { 140 self.map_err(|e| { 141 let mut e = e.into(); 142 e.context_mut() 143 .help 144 .push(HelpInfo::Warning(Box::new(context()))); 145 e 146 }) 147 } 148 suggestion<C>(self, context: C) -> Result<T> where C: Display + Send + Sync + 'static,149 fn suggestion<C>(self, context: C) -> Result<T> 150 where 151 C: Display + Send + Sync + 'static, 152 { 153 self.map_err(|e| { 154 let mut e = e.into(); 155 e.context_mut() 156 .help 157 .push(HelpInfo::Suggestion(Box::new(context))); 158 e 159 }) 160 } 161 with_suggestion<C, F>(self, context: F) -> Result<T> where C: Display + Send + Sync + 'static, F: FnOnce() -> C,162 fn with_suggestion<C, F>(self, context: F) -> Result<T> 163 where 164 C: Display + Send + Sync + 'static, 165 F: FnOnce() -> C, 166 { 167 self.map_err(|e| { 168 let mut e = e.into(); 169 e.context_mut() 170 .help 171 .push(HelpInfo::Suggestion(Box::new(context()))); 172 e 173 }) 174 } 175 } 176 177 pub enum HelpInfo { 178 Note(Box<dyn Display + Send + Sync + 'static>), 179 Warning(Box<dyn Display + Send + Sync + 'static>), 180 Suggestion(Box<dyn Display + Send + Sync + 'static>), 181 } 182 183 impl Display for HelpInfo { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result184 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 185 match self { 186 Self::Note(context) => write!(f, "Note: {}", context), 187 Self::Warning(context) => write!(f, "Warning: {}", context), 188 Self::Suggestion(context) => write!(f, "Suggestion: {}", context), 189 } 190 } 191 } 192 193 pub(crate) mod private { 194 use crate::ErrReport; 195 pub trait Sealed {} 196 197 impl<T, E> Sealed for std::result::Result<T, E> where E: Into<ErrReport> {} 198 } 199