use crate::encoding::{Decoder, EncodingError};
use crate::escape::EscapeError;
use crate::events::attributes::AttrError;
use crate::name::{NamespaceError, QName};
use std::fmt;
use std::io::Error as IoError;
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) => {
f.write_str("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 => {
f.write_str("`<!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 => {
f.write_str("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),
InvalidAttr(AttrError),
Encoding(EncodingError),
Escape(EscapeError),
Namespace(NamespaceError),
}
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 {
Self::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<EncodingError> for Error {
#[inline]
fn from(error: EncodingError) -> Error {
Self::Encoding(error)
}
}
impl From<EscapeError> for Error {
#[inline]
fn from(error: EscapeError) -> Error {
Self::Escape(error)
}
}
impl From<AttrError> for Error {
#[inline]
fn from(error: AttrError) -> Self {
Self::InvalidAttr(error)
}
}
impl From<NamespaceError> for Error {
#[inline]
fn from(error: NamespaceError) -> Self {
Self::Namespace(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 {
Self::Io(e) => write!(f, "I/O error: {}", e),
Self::Syntax(e) => write!(f, "syntax error: {}", e),
Self::IllFormed(e) => write!(f, "ill-formed document: {}", e),
Self::InvalidAttr(e) => write!(f, "error while parsing attribute: {}", e),
Self::Encoding(e) => e.fmt(f),
Self::Escape(e) => e.fmt(f),
Self::Namespace(e) => e.fmt(f),
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Io(e) => Some(e),
Self::Syntax(e) => Some(e),
Self::IllFormed(e) => Some(e),
Self::InvalidAttr(e) => Some(e),
Self::Encoding(e) => Some(e),
Self::Escape(e) => Some(e),
Self::Namespace(e) => Some(e),
}
}
}
#[cfg(feature = "serialize")]
pub mod serialize {
use super::*;
use crate::utils::write_byte_string;
use std::borrow::Cow;
#[cfg(feature = "overlapped-lists")]
use std::num::NonZeroUsize;
use std::str::Utf8Error;
#[derive(Clone, Debug)]
pub enum DeError {
Custom(String),
InvalidXml(Error),
KeyNotRead,
UnexpectedStart(Vec<u8>),
UnexpectedEof,
#[cfg(feature = "overlapped-lists")]
TooManyEvents(NonZeroUsize),
}
impl fmt::Display for DeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Custom(s) => f.write_str(s),
Self::InvalidXml(e) => e.fmt(f),
Self::KeyNotRead => f.write_str("invalid `Deserialize` implementation: `MapAccess::next_value[_seed]` was called before `MapAccess::next_key[_seed]`"),
Self::UnexpectedStart(e) => {
f.write_str("unexpected `Event::Start(")?;
write_byte_string(f, e)?;
f.write_str(")`")
}
Self::UnexpectedEof => f.write_str("unexpected `Event::Eof`"),
#[cfg(feature = "overlapped-lists")]
Self::TooManyEvents(s) => write!(f, "deserializer buffered {} events, limit exceeded", s),
}
}
}
impl std::error::Error for DeError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::InvalidXml(e) => Some(e),
_ => None,
}
}
}
impl serde::de::Error for DeError {
fn custom<T: fmt::Display>(msg: T) -> Self {
Self::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<EncodingError> for DeError {
#[inline]
fn from(e: EncodingError) -> Self {
Self::InvalidXml(e.into())
}
}
impl From<AttrError> for DeError {
#[inline]
fn from(e: AttrError) -> Self {
Self::InvalidXml(e.into())
}
}
#[derive(Clone, Debug)]
pub enum SeError {
Custom(String),
Io(Arc<IoError>),
Fmt(std::fmt::Error),
Unsupported(Cow<'static, str>),
NonEncodable(Utf8Error),
}
impl fmt::Display for SeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Custom(s) => f.write_str(s),
Self::Io(e) => write!(f, "I/O error: {}", e),
Self::Fmt(e) => write!(f, "formatting error: {}", e),
Self::Unsupported(s) => write!(f, "unsupported value: {}", s),
Self::NonEncodable(e) => write!(f, "malformed UTF-8: {}", e),
}
}
}
impl ::std::error::Error for SeError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Io(e) => Some(e),
_ => None,
}
}
}
impl serde::ser::Error for SeError {
fn custom<T: fmt::Display>(msg: T) -> Self {
Self::Custom(msg.to_string())
}
}
impl From<IoError> for SeError {
#[inline]
fn from(e: IoError) -> Self {
Self::Io(Arc::new(e))
}
}
impl From<Utf8Error> for SeError {
#[inline]
fn from(e: Utf8Error) -> Self {
Self::NonEncodable(e)
}
}
impl From<fmt::Error> for SeError {
#[inline]
fn from(e: fmt::Error) -> Self {
Self::Fmt(e)
}
}
}