use std::{error::Error as StdError, fmt, io, str::Utf8Error, string::FromUtf8Error}; use serde::{de, ser}; use crate::parse::{is_ident_first_char, is_ident_other_char, is_ident_raw_char, BASE64_ENGINE}; /// This type represents all possible errors that can occur when /// serializing or deserializing RON data. #[derive(Clone, Debug, PartialEq, Eq)] pub struct SpannedError { pub code: Error, pub position: Position, } pub type Result = std::result::Result; pub type SpannedResult = std::result::Result; #[derive(Clone, Debug, PartialEq, Eq)] #[non_exhaustive] pub enum Error { Io(String), Message(String), Base64Error(base64::DecodeError), Eof, ExpectedArray, ExpectedArrayEnd, ExpectedAttribute, ExpectedAttributeEnd, ExpectedBoolean, ExpectedComma, ExpectedChar, ExpectedFloat, FloatUnderscore, ExpectedInteger, ExpectedOption, ExpectedOptionEnd, ExpectedMap, ExpectedMapColon, ExpectedMapEnd, ExpectedDifferentStructName { expected: &'static str, found: String, }, ExpectedStructLike, ExpectedNamedStructLike(&'static str), ExpectedStructLikeEnd, ExpectedUnit, ExpectedString, ExpectedStringEnd, ExpectedIdentifier, InvalidEscape(&'static str), IntegerOutOfBounds, NoSuchExtension(String), UnclosedBlockComment, UnderscoreAtBeginning, UnexpectedByte(char), Utf8Error(Utf8Error), TrailingCharacters, InvalidValueForType { expected: String, found: String, }, ExpectedDifferentLength { expected: String, found: usize, }, NoSuchEnumVariant { expected: &'static [&'static str], found: String, outer: Option, }, NoSuchStructField { expected: &'static [&'static str], found: String, outer: Option, }, MissingStructField { field: &'static str, outer: Option, }, DuplicateStructField { field: &'static str, outer: Option, }, InvalidIdentifier(String), SuggestRawIdentifier(String), ExceededRecursionLimit, } impl fmt::Display for SpannedError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if (self.position == Position { line: 0, col: 0 }) { write!(f, "{}", self.code) } else { write!(f, "{}: {}", self.position, self.code) } } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { Error::Io(ref s) => f.write_str(s), Error::Message(ref s) => f.write_str(s), Error::Base64Error(ref e) => fmt::Display::fmt(e, f), Error::Eof => f.write_str("Unexpected end of RON"), Error::ExpectedArray => f.write_str("Expected opening `[`"), Error::ExpectedArrayEnd => f.write_str("Expected closing `]`"), Error::ExpectedAttribute => f.write_str("Expected an `#![enable(...)]` attribute"), Error::ExpectedAttributeEnd => { f.write_str("Expected closing `)]` after the enable attribute") } Error::ExpectedBoolean => f.write_str("Expected boolean"), Error::ExpectedComma => f.write_str("Expected comma"), Error::ExpectedChar => f.write_str("Expected char"), Error::ExpectedFloat => f.write_str("Expected float"), Error::FloatUnderscore => f.write_str("Unexpected underscore in float"), Error::ExpectedInteger => f.write_str("Expected integer"), Error::ExpectedOption => f.write_str("Expected option"), Error::ExpectedOptionEnd => f.write_str("Expected closing `)`"), Error::ExpectedMap => f.write_str("Expected opening `{`"), Error::ExpectedMapColon => f.write_str("Expected colon"), Error::ExpectedMapEnd => f.write_str("Expected closing `}`"), Error::ExpectedDifferentStructName { expected, ref found, } => write!( f, "Expected struct {} but found {}", Identifier(expected), Identifier(found) ), Error::ExpectedStructLike => f.write_str("Expected opening `(`"), Error::ExpectedNamedStructLike(name) => { if name.is_empty() { f.write_str("Expected only opening `(`, no name, for un-nameable struct") } else { write!(f, "Expected opening `(` for struct {}", Identifier(name)) } } Error::ExpectedStructLikeEnd => f.write_str("Expected closing `)`"), Error::ExpectedUnit => f.write_str("Expected unit"), Error::ExpectedString => f.write_str("Expected string"), Error::ExpectedStringEnd => f.write_str("Expected end of string"), Error::ExpectedIdentifier => f.write_str("Expected identifier"), Error::InvalidEscape(s) => f.write_str(s), Error::IntegerOutOfBounds => f.write_str("Integer is out of bounds"), Error::NoSuchExtension(ref name) => { write!(f, "No RON extension named {}", Identifier(name)) } Error::Utf8Error(ref e) => fmt::Display::fmt(e, f), Error::UnclosedBlockComment => f.write_str("Unclosed block comment"), Error::UnderscoreAtBeginning => { f.write_str("Unexpected leading underscore in an integer") } Error::UnexpectedByte(ref byte) => write!(f, "Unexpected byte {:?}", byte), Error::TrailingCharacters => f.write_str("Non-whitespace trailing characters"), Error::InvalidValueForType { ref expected, ref found, } => { write!(f, "Expected {} but found {} instead", expected, found) } Error::ExpectedDifferentLength { ref expected, found, } => { write!(f, "Expected {} but found ", expected)?; match found { 0 => f.write_str("zero elements")?, 1 => f.write_str("one element")?, n => write!(f, "{} elements", n)?, } f.write_str(" instead") } Error::NoSuchEnumVariant { expected, ref found, ref outer, } => { f.write_str("Unexpected ")?; if outer.is_none() { f.write_str("enum ")?; } write!(f, "variant named {}", Identifier(found))?; if let Some(outer) = outer { write!(f, "in enum {}", Identifier(outer))?; } write!( f, ", {}", OneOf { alts: expected, none: "variants" } ) } Error::NoSuchStructField { expected, ref found, ref outer, } => { write!(f, "Unexpected field named {}", Identifier(found))?; if let Some(outer) = outer { write!(f, "in {}", Identifier(outer))?; } write!( f, ", {}", OneOf { alts: expected, none: "fields" } ) } Error::MissingStructField { field, ref outer } => { write!(f, "Unexpected missing field {}", Identifier(field))?; match outer { Some(outer) => write!(f, " in {}", Identifier(outer)), None => Ok(()), } } Error::DuplicateStructField { field, ref outer } => { write!(f, "Unexpected duplicate field {}", Identifier(field))?; match outer { Some(outer) => write!(f, " in {}", Identifier(outer)), None => Ok(()), } } Error::InvalidIdentifier(ref invalid) => write!(f, "Invalid identifier {:?}", invalid), Error::SuggestRawIdentifier(ref identifier) => write!( f, "Found invalid std identifier `{}`, try the raw identifier `r#{}` instead", identifier, identifier ), Error::ExceededRecursionLimit => f.write_str("Exceeded recursion limit, try increasing the limit and using `serde_stacker` to protect against a stack overflow"), } } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Position { pub line: usize, pub col: usize, } impl fmt::Display for Position { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}:{}", self.line, self.col) } } impl ser::Error for Error { #[cold] fn custom(msg: T) -> Self { Error::Message(msg.to_string()) } } impl de::Error for Error { #[cold] fn custom(msg: T) -> Self { Error::Message(msg.to_string()) } #[cold] fn invalid_type(unexp: de::Unexpected, exp: &dyn de::Expected) -> Self { // Invalid type and invalid value are merged given their similarity in ron Self::invalid_value(unexp, exp) } #[cold] fn invalid_value(unexp: de::Unexpected, exp: &dyn de::Expected) -> Self { struct UnexpectedSerdeTypeValue<'a>(de::Unexpected<'a>); impl<'a> fmt::Display for UnexpectedSerdeTypeValue<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use de::Unexpected::*; match self.0 { Bool(b) => write!(f, "the boolean `{}`", b), Unsigned(i) => write!(f, "the unsigned integer `{}`", i), Signed(i) => write!(f, "the signed integer `{}`", i), Float(n) => write!(f, "the floating point number `{}`", n), Char(c) => write!(f, "the UTF-8 character `{}`", c), Str(s) => write!(f, "the string {:?}", s), Bytes(b) => write!(f, "the bytes \"{}\"", { base64::display::Base64Display::new(b, &BASE64_ENGINE) }), Unit => write!(f, "a unit value"), Option => write!(f, "an optional value"), NewtypeStruct => write!(f, "a newtype struct"), Seq => write!(f, "a sequence"), Map => write!(f, "a map"), Enum => write!(f, "an enum"), UnitVariant => write!(f, "a unit variant"), NewtypeVariant => write!(f, "a newtype variant"), TupleVariant => write!(f, "a tuple variant"), StructVariant => write!(f, "a struct variant"), Other(other) => f.write_str(other), } } } Error::InvalidValueForType { expected: exp.to_string(), found: UnexpectedSerdeTypeValue(unexp).to_string(), } } #[cold] fn invalid_length(len: usize, exp: &dyn de::Expected) -> Self { Error::ExpectedDifferentLength { expected: exp.to_string(), found: len, } } #[cold] fn unknown_variant(variant: &str, expected: &'static [&'static str]) -> Self { Error::NoSuchEnumVariant { expected, found: variant.to_string(), outer: None, } } #[cold] fn unknown_field(field: &str, expected: &'static [&'static str]) -> Self { Error::NoSuchStructField { expected, found: field.to_string(), outer: None, } } #[cold] fn missing_field(field: &'static str) -> Self { Error::MissingStructField { field, outer: None } } #[cold] fn duplicate_field(field: &'static str) -> Self { Error::DuplicateStructField { field, outer: None } } } impl StdError for SpannedError {} impl StdError for Error {} impl From for Error { fn from(e: Utf8Error) -> Self { Error::Utf8Error(e) } } impl From for Error { fn from(e: FromUtf8Error) -> Self { Error::Utf8Error(e.utf8_error()) } } impl From for Error { fn from(e: io::Error) -> Self { Error::Io(e.to_string()) } } impl From for SpannedError { fn from(e: io::Error) -> Self { SpannedError { code: e.into(), position: Position { line: 0, col: 0 }, } } } impl From for Error { fn from(e: SpannedError) -> Self { e.code } } struct OneOf { alts: &'static [&'static str], none: &'static str, } impl fmt::Display for OneOf { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.alts { [] => write!(f, "there are no {}", self.none), [a1] => write!(f, "expected {} instead", Identifier(a1)), [a1, a2] => write!( f, "expected either {} or {} instead", Identifier(a1), Identifier(a2) ), [a1, ref alts @ ..] => { write!(f, "expected one of {}", Identifier(a1))?; for alt in alts { write!(f, ", {}", Identifier(alt))?; } f.write_str(" instead") } } } } struct Identifier<'a>(&'a str); impl<'a> fmt::Display for Identifier<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if self.0.is_empty() || !self.0.as_bytes().iter().copied().all(is_ident_raw_char) { return write!(f, "{:?}_[invalid identifier]", self.0); } let mut bytes = self.0.as_bytes().iter().copied(); if !bytes.next().map_or(false, is_ident_first_char) || !bytes.all(is_ident_other_char) { write!(f, "`r#{}`", self.0) } else { write!(f, "`{}`", self.0) } } }