use crate::encoding::Decoder;
use crate::escape::EscapeError;
use crate::events::attributes::AttrError;
use crate::name::QName;
use crate::utils::write_byte_string;
use std::fmt;
use std::io::Error as IoError;
use std::str::Utf8Error;
use std::string::FromUtf8Error;
use std::sync::Arc;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum SyntaxError {
InvalidBangMarkup,
UnclosedPIOrXmlDecl,
UnclosedComment,
UnclosedDoctype,
UnclosedCData,
UnclosedTag,
}
impl fmt::Display for SyntaxError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::InvalidBangMarkup => f.write_str("unknown or missed symbol in markup"),
Self::UnclosedPIOrXmlDecl => {
f.write_str("processing instruction or xml declaration not closed: `?>` not found before end of input")
}
Self::UnclosedComment => {
f.write_str("comment not closed: `-->` not found before end of input")
}
Self::UnclosedDoctype => {
f.write_str("DOCTYPE not closed: `>` not found before end of input")
}
Self::UnclosedCData => {
f.write_str("CDATA not closed: `]]>` not found before end of input")
}
Self::UnclosedTag => f.write_str("tag not closed: `>` not found before end of input"),
}
}
}
impl std::error::Error for SyntaxError {}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum IllFormedError {
MissingDeclVersion(Option<String>),
MissingDoctypeName,
MissingEndTag(String),
UnmatchedEndTag(String),
MismatchedEndTag {
expected: String,
found: String,
},
DoubleHyphenInComment,
}
impl fmt::Display for IllFormedError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::MissingDeclVersion(None) => {
write!(f, "an XML declaration does not contain `version` attribute")
}
Self::MissingDeclVersion(Some(attr)) => {
write!(f, "an XML declaration must start with `version` attribute, but in starts with `{}`", attr)
}
Self::MissingDoctypeName => write!(
f,
"`<!DOCTYPE>` declaration does not contain a name of a document type"
),
Self::MissingEndTag(tag) => write!(
f,
"start tag not closed: `</{}>` not found before end of input",
tag,
),
Self::UnmatchedEndTag(tag) => {
write!(f, "close tag `</{}>` does not match any open tag", tag)
}
Self::MismatchedEndTag { expected, found } => write!(
f,
"expected `</{}>`, but `</{}>` was found",
expected, found,
),
Self::DoubleHyphenInComment => {
write!(f, "forbidden string `--` was found in a comment")
}
}
}
}
impl std::error::Error for IllFormedError {}
#[derive(Clone, Debug)]
pub enum Error {
Io(Arc<IoError>),
Syntax(SyntaxError),
IllFormed(IllFormedError),
NonDecodable(Option<Utf8Error>),
InvalidAttr(AttrError),
EscapeError(EscapeError),
UnknownPrefix(Vec<u8>),
InvalidPrefixBind {
prefix: Vec<u8>,
namespace: Vec<u8>,
},
}
impl Error {
pub(crate) fn missed_end(name: QName, decoder: Decoder) -> Self {
match decoder.decode(name.as_ref()) {
Ok(name) => IllFormedError::MissingEndTag(name.into()).into(),
Err(err) => err.into(),
}
}
}
impl From<IoError> for Error {
#[inline]
fn from(error: IoError) -> Error {
Error::Io(Arc::new(error))
}
}
impl From<SyntaxError> for Error {
#[inline]
fn from(error: SyntaxError) -> Self {
Self::Syntax(error)
}
}
impl From<IllFormedError> for Error {
#[inline]
fn from(error: IllFormedError) -> Self {
Self::IllFormed(error)
}
}
impl From<Utf8Error> for Error {
#[inline]
fn from(error: Utf8Error) -> Error {
Error::NonDecodable(Some(error))
}
}
impl From<FromUtf8Error> for Error {
#[inline]
fn from(error: FromUtf8Error) -> Error {
error.utf8_error().into()
}
}
impl From<EscapeError> for Error {
#[inline]
fn from(error: EscapeError) -> Error {
Error::EscapeError(error)
}
}
impl From<AttrError> for Error {
#[inline]
fn from(error: AttrError) -> Self {
Error::InvalidAttr(error)
}
}
pub type Result<T> = std::result::Result<T, Error>;
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::Io(e) => write!(f, "I/O error: {}", e),
Error::Syntax(e) => write!(f, "syntax error: {}", e),
Error::IllFormed(e) => write!(f, "ill-formed document: {}", e),
Error::NonDecodable(None) => write!(f, "Malformed input, decoding impossible"),
Error::NonDecodable(Some(e)) => write!(f, "Malformed UTF-8 input: {}", e),
Error::InvalidAttr(e) => write!(f, "error while parsing attribute: {}", e),
Error::EscapeError(e) => write!(f, "{}", e),
Error::UnknownPrefix(prefix) => {
f.write_str("Unknown namespace prefix '")?;
write_byte_string(f, prefix)?;
f.write_str("'")
}
Error::InvalidPrefixBind { prefix, namespace } => {
f.write_str("The namespace prefix '")?;
write_byte_string(f, prefix)?;
f.write_str("' cannot be bound to '")?;
write_byte_string(f, namespace)?;
f.write_str("'")
}
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Error::Io(e) => Some(e),
Error::Syntax(e) => Some(e),
Error::IllFormed(e) => Some(e),
Error::NonDecodable(Some(e)) => Some(e),
Error::InvalidAttr(e) => Some(e),
Error::EscapeError(e) => Some(e),
_ => None,
}
}
}
#[cfg(feature = "serialize")]
pub mod serialize {
use super::*;
use std::borrow::Cow;
#[cfg(feature = "overlapped-lists")]
use std::num::NonZeroUsize;
use std::num::{ParseFloatError, ParseIntError};
#[derive(Clone, Debug)]
pub enum DeError {
Custom(String),
InvalidXml(Error),
InvalidInt(ParseIntError),
InvalidFloat(ParseFloatError),
InvalidBoolean(String),
KeyNotRead,
UnexpectedStart(Vec<u8>),
UnexpectedEof,
Unsupported(Cow<'static, str>),
#[cfg(feature = "overlapped-lists")]
TooManyEvents(NonZeroUsize),
}
impl fmt::Display for DeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
DeError::Custom(s) => write!(f, "{}", s),
DeError::InvalidXml(e) => write!(f, "{}", e),
DeError::InvalidInt(e) => write!(f, "{}", e),
DeError::InvalidFloat(e) => write!(f, "{}", e),
DeError::InvalidBoolean(v) => write!(f, "Invalid boolean value '{}'", v),
DeError::KeyNotRead => write!(f, "Invalid `Deserialize` implementation: `MapAccess::next_value[_seed]` was called before `MapAccess::next_key[_seed]`"),
DeError::UnexpectedStart(e) => {
f.write_str("Unexpected `Event::Start(")?;
write_byte_string(f, e)?;
f.write_str(")`")
}
DeError::UnexpectedEof => write!(f, "Unexpected `Event::Eof`"),
DeError::Unsupported(s) => write!(f, "Unsupported operation: {}", s),
#[cfg(feature = "overlapped-lists")]
DeError::TooManyEvents(s) => write!(f, "Deserializer buffers {} events, limit exceeded", s),
}
}
}
impl ::std::error::Error for DeError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
DeError::InvalidXml(e) => Some(e),
DeError::InvalidInt(e) => Some(e),
DeError::InvalidFloat(e) => Some(e),
_ => None,
}
}
}
impl serde::de::Error for DeError {
fn custom<T: fmt::Display>(msg: T) -> Self {
DeError::Custom(msg.to_string())
}
}
impl serde::ser::Error for DeError {
fn custom<T: fmt::Display>(msg: T) -> Self {
DeError::Custom(msg.to_string())
}
}
impl From<Error> for DeError {
#[inline]
fn from(e: Error) -> Self {
Self::InvalidXml(e)
}
}
impl From<EscapeError> for DeError {
#[inline]
fn from(e: EscapeError) -> Self {
Self::InvalidXml(e.into())
}
}
impl From<Utf8Error> for DeError {
#[inline]
fn from(e: Utf8Error) -> Self {
Self::InvalidXml(e.into())
}
}
impl From<FromUtf8Error> for DeError {
#[inline]
fn from(e: FromUtf8Error) -> Self {
Self::InvalidXml(e.into())
}
}
impl From<AttrError> for DeError {
#[inline]
fn from(e: AttrError) -> Self {
Self::InvalidXml(e.into())
}
}
impl From<ParseIntError> for DeError {
#[inline]
fn from(e: ParseIntError) -> Self {
Self::InvalidInt(e)
}
}
impl From<ParseFloatError> for DeError {
#[inline]
fn from(e: ParseFloatError) -> Self {
Self::InvalidFloat(e)
}
}
impl From<fmt::Error> for DeError {
#[inline]
fn from(e: fmt::Error) -> Self {
Self::Custom(e.to_string())
}
}
}