use std::{error::Error, fmt, io, path::PathBuf}; use crate::vfs::FsError; #[derive(Debug)] pub struct SnapshotError { detail: SnapshotErrorDetail, path: Option, } impl SnapshotError { pub fn new(detail: SnapshotErrorDetail, path: Option>) -> Self { SnapshotError { detail, path: path.map(Into::into), } } pub(crate) fn wrap(inner: impl Into, path: impl Into) -> Self { SnapshotError { detail: inner.into(), path: Some(path.into()), } } pub(crate) fn file_did_not_exist(path: impl Into) -> SnapshotError { SnapshotError { detail: SnapshotErrorDetail::FileDidNotExist, path: Some(path.into()), } } pub(crate) fn file_name_bad_unicode(path: impl Into) -> SnapshotError { SnapshotError { detail: SnapshotErrorDetail::FileNameBadUnicode, path: Some(path.into()), } } pub(crate) fn file_contents_bad_unicode( inner: std::str::Utf8Error, path: impl Into, ) -> SnapshotError { SnapshotError { detail: SnapshotErrorDetail::FileContentsBadUnicode { inner }, path: Some(path.into()), } } pub(crate) fn malformed_project( inner: serde_json::Error, path: impl Into, ) -> SnapshotError { SnapshotError { detail: SnapshotErrorDetail::MalformedProject { inner }, path: Some(path.into()), } } } impl Error for SnapshotError { fn source(&self) -> Option<&(dyn Error + 'static)> { self.detail.source() } } impl fmt::Display for SnapshotError { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { match &self.path { Some(path) => write!(formatter, "{} in path {}", self.detail, path.display()), None => write!(formatter, "{}", self.detail), } } } impl From for SnapshotError { fn from(error: FsError) -> Self { let (inner, path) = error.into_raw(); Self::new(inner.into(), Some(path)) } } impl From for SnapshotError { fn from(error: rlua::Error) -> Self { Self::new(error.into(), Option::::None) } } #[derive(Debug)] pub enum SnapshotErrorDetail { IoError { inner: io::Error }, Lua { inner: rlua::Error }, FileDidNotExist, FileNameBadUnicode, FileContentsBadUnicode { inner: std::str::Utf8Error }, MalformedProject { inner: serde_json::Error }, } impl From for SnapshotErrorDetail { fn from(inner: io::Error) -> Self { SnapshotErrorDetail::IoError { inner } } } impl From for SnapshotErrorDetail { fn from(inner: rlua::Error) -> Self { SnapshotErrorDetail::Lua { inner } } } impl SnapshotErrorDetail { fn source(&self) -> Option<&(dyn Error + 'static)> { use self::SnapshotErrorDetail::*; match self { IoError { inner } => Some(inner), Lua { inner } => Some(inner), FileContentsBadUnicode { inner } => Some(inner), MalformedProject { inner } => Some(inner), _ => None, } } } impl fmt::Display for SnapshotErrorDetail { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { use self::SnapshotErrorDetail::*; match self { IoError { inner } => write!(formatter, "I/O error: {}", inner), Lua { inner } => write!(formatter, "{}", inner), FileDidNotExist => write!(formatter, "file did not exist"), FileNameBadUnicode => write!(formatter, "file name had malformed Unicode"), FileContentsBadUnicode { inner } => { write!(formatter, "file had malformed unicode: {}", inner) } MalformedProject { inner } => write!(formatter, "{}", inner), } } }