diff options
Diffstat (limited to 'third_party/rust/serde_yaml/src/error.rs')
-rw-r--r-- | third_party/rust/serde_yaml/src/error.rs | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/third_party/rust/serde_yaml/src/error.rs b/third_party/rust/serde_yaml/src/error.rs new file mode 100644 index 0000000000..dc8321435f --- /dev/null +++ b/third_party/rust/serde_yaml/src/error.rs @@ -0,0 +1,244 @@ +use crate::path::Path; +use serde::{de, ser}; +use std::error; +use std::fmt::{self, Debug, Display}; +use std::io; +use std::result; +use std::str; +use std::string; +use std::sync::Arc; +use yaml_rust::emitter; +use yaml_rust::scanner::{self, Marker, ScanError}; + +/// An error that happened serializing or deserializing YAML data. +pub struct Error(Box<ErrorImpl>); + +/// Alias for a `Result` with the error type `serde_yaml::Error`. +pub type Result<T> = result::Result<T, Error>; + +#[derive(Debug)] +pub enum ErrorImpl { + Message(String, Option<Pos>), + + Emit(emitter::EmitError), + Scan(scanner::ScanError), + Io(io::Error), + Utf8(str::Utf8Error), + FromUtf8(string::FromUtf8Error), + + EndOfStream, + MoreThanOneDocument, + RecursionLimitExceeded, + + Shared(Arc<ErrorImpl>), +} + +#[derive(Debug)] +pub struct Pos { + marker: Marker, + path: String, +} + +/// The input location that an error occured. +#[derive(Debug)] +pub struct Location { + index: usize, + line: usize, + column: usize, +} + +impl Location { + /// The byte index of the error + pub fn index(&self) -> usize { + self.index + } + + /// The line of the error + pub fn line(&self) -> usize { + self.line + } + + /// The column of the error + pub fn column(&self) -> usize { + self.column + } + + // This is to keep decoupled with the yaml crate + #[doc(hidden)] + fn from_marker(marker: &Marker) -> Self { + Location { + // `col` returned from the `yaml` crate is 0-indexed but all error messages add + 1 to this value + column: marker.col() + 1, + index: marker.index(), + line: marker.line(), + } + } +} + +impl Error { + /// Returns the Location from the error if one exists. + /// + /// Not all types of errors have a location so this can return `None`. + /// + /// # Examples + /// + /// ``` + /// # use serde_yaml::{Value, Error}; + /// # + /// // The `@` character as the first character makes this invalid yaml + /// let invalid_yaml: Result<Value, Error> = serde_yaml::from_str("@invalid_yaml"); + /// + /// let location = invalid_yaml.unwrap_err().location().unwrap(); + /// + /// assert_eq!(location.line(), 1); + /// assert_eq!(location.column(), 1); + /// ``` + pub fn location(&self) -> Option<Location> { + match self.0.as_ref() { + ErrorImpl::Message(_, Some(pos)) => Some(Location::from_marker(&pos.marker)), + ErrorImpl::Scan(scan) => Some(Location::from_marker(scan.marker())), + _ => None, + } + } +} + +pub(crate) fn end_of_stream() -> Error { + Error(Box::new(ErrorImpl::EndOfStream)) +} + +pub(crate) fn more_than_one_document() -> Error { + Error(Box::new(ErrorImpl::MoreThanOneDocument)) +} + +pub(crate) fn io(err: io::Error) -> Error { + Error(Box::new(ErrorImpl::Io(err))) +} + +pub(crate) fn emitter(err: emitter::EmitError) -> Error { + Error(Box::new(ErrorImpl::Emit(err))) +} + +pub(crate) fn scanner(err: scanner::ScanError) -> Error { + Error(Box::new(ErrorImpl::Scan(err))) +} + +pub(crate) fn str_utf8(err: str::Utf8Error) -> Error { + Error(Box::new(ErrorImpl::Utf8(err))) +} + +pub(crate) fn string_utf8(err: string::FromUtf8Error) -> Error { + Error(Box::new(ErrorImpl::FromUtf8(err))) +} + +pub(crate) fn recursion_limit_exceeded() -> Error { + Error(Box::new(ErrorImpl::RecursionLimitExceeded)) +} + +pub(crate) fn shared(shared: Arc<ErrorImpl>) -> Error { + Error(Box::new(ErrorImpl::Shared(shared))) +} + +pub(crate) fn fix_marker(mut error: Error, marker: Marker, path: Path) -> Error { + if let ErrorImpl::Message(_, none @ None) = error.0.as_mut() { + *none = Some(Pos { + marker, + path: path.to_string(), + }); + } + error +} + +impl Error { + pub(crate) fn shared(self) -> Arc<ErrorImpl> { + if let ErrorImpl::Shared(err) = *self.0 { + err + } else { + Arc::from(self.0) + } + } +} + +impl error::Error for Error { + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + self.0.source() + } +} + +impl Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.display(f) + } +} + +// Remove two layers of verbosity from the debug representation. Humans often +// end up seeing this representation because it is what unwrap() shows. +impl Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.debug(f) + } +} + +impl ser::Error for Error { + fn custom<T: Display>(msg: T) -> Self { + Error(Box::new(ErrorImpl::Message(msg.to_string(), None))) + } +} + +impl de::Error for Error { + fn custom<T: Display>(msg: T) -> Self { + Error(Box::new(ErrorImpl::Message(msg.to_string(), None))) + } +} + +impl ErrorImpl { + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + match self { + ErrorImpl::Scan(err) => Some(err), + ErrorImpl::Io(err) => Some(err), + ErrorImpl::Utf8(err) => Some(err), + ErrorImpl::FromUtf8(err) => Some(err), + ErrorImpl::Shared(err) => err.source(), + _ => None, + } + } + + fn display(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + ErrorImpl::Message(msg, None) => Display::fmt(msg, f), + ErrorImpl::Message(msg, Some(Pos { marker, path })) => { + if path == "." { + write!(f, "{}", ScanError::new(*marker, msg)) + } else { + write!(f, "{}: {}", path, ScanError::new(*marker, msg)) + } + } + ErrorImpl::Emit(emitter::EmitError::FmtError(_)) => f.write_str("yaml-rust fmt error"), + ErrorImpl::Emit(emitter::EmitError::BadHashmapKey) => f.write_str("bad hash map key"), + ErrorImpl::Scan(err) => Display::fmt(err, f), + ErrorImpl::Io(err) => Display::fmt(err, f), + ErrorImpl::Utf8(err) => Display::fmt(err, f), + ErrorImpl::FromUtf8(err) => Display::fmt(err, f), + ErrorImpl::EndOfStream => f.write_str("EOF while parsing a value"), + ErrorImpl::MoreThanOneDocument => f.write_str( + "deserializing from YAML containing more than one document is not supported", + ), + ErrorImpl::RecursionLimitExceeded => f.write_str("recursion limit exceeded"), + ErrorImpl::Shared(err) => err.display(f), + } + } + + fn debug(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + ErrorImpl::Message(msg, pos) => f.debug_tuple("Message").field(msg).field(pos).finish(), + ErrorImpl::Emit(emit) => f.debug_tuple("Emit").field(emit).finish(), + ErrorImpl::Scan(scan) => f.debug_tuple("Scan").field(scan).finish(), + ErrorImpl::Io(io) => f.debug_tuple("Io").field(io).finish(), + ErrorImpl::Utf8(utf8) => f.debug_tuple("Utf8").field(utf8).finish(), + ErrorImpl::FromUtf8(from_utf8) => f.debug_tuple("FromUtf8").field(from_utf8).finish(), + ErrorImpl::EndOfStream => f.debug_tuple("EndOfStream").finish(), + ErrorImpl::MoreThanOneDocument => f.debug_tuple("MoreThanOneDocument").finish(), + ErrorImpl::RecursionLimitExceeded => f.debug_tuple("RecursionLimitExceeded").finish(), + ErrorImpl::Shared(err) => err.debug(f), + } + } +} |