1 use crate::utils::Context; 2 3 use std::{error::Error as StdError, fmt, io}; 4 5 /// Wrap `std::io::Error` with additional message 6 /// 7 /// Keeps the original error kind and stores the original I/O error as `source`. 8 impl<T> Context for Result<T, std::io::Error> { context(self, message: impl Fn() -> String) -> Self9 fn context(self, message: impl Fn() -> String) -> Self { 10 self.map_err(|e| VerboseError::wrap(e, message())) 11 } 12 } 13 14 #[derive(Debug)] 15 pub(crate) struct VerboseError { 16 source: io::Error, 17 message: String, 18 } 19 20 impl VerboseError { wrap(source: io::Error, message: impl Into<String>) -> io::Error21 pub(crate) fn wrap(source: io::Error, message: impl Into<String>) -> io::Error { 22 io::Error::new( 23 source.kind(), 24 VerboseError { 25 source, 26 message: message.into(), 27 }, 28 ) 29 } 30 } 31 32 impl fmt::Display for VerboseError { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result33 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 34 write!(f, "{}", self.message) 35 } 36 } 37 38 impl StdError for VerboseError { source(&self) -> Option<&(dyn StdError + 'static)>39 fn source(&self) -> Option<&(dyn StdError + 'static)> { 40 Some(&self.source) 41 } 42 } 43