From 6c19f369fe522430ed6f999f73d1889ebd1191bc Mon Sep 17 00:00:00 2001 From: Wren Turkal Date: Sun, 27 Aug 2023 01:59:34 -0700 Subject: [PATCH] Use thiserror crate to make error definition more ergonomic. The thiserror crate takes care of a bunch of details of implementing errors for a library in rust. This will simplify the code around our errors by making it follow conventions that are widely used in the rust community. It also is much shorter in terms of lines of code. Closes #638 --- Cargo.toml | 1 + src/errors.rs | 64 ++++++++++++--------------------------------------- 2 files changed, 16 insertions(+), 49 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0be6faa8..be234d76 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ serde = { version = ">=1.0.100,<1.0.181", optional = true } tokio = { version = "1.10", optional = true, default-features = false, features = ["io-util"] } memchr = "2.1" arbitrary = { version = "1.2.3", features = ["derive"], optional = true } +thiserror = "1.0.47" [dev-dependencies] criterion = "0.4" diff --git a/src/errors.rs b/src/errors.rs index 14cd7a5c..09c3e98a 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -2,26 +2,28 @@ use crate::escape::EscapeError; use crate::events::attributes::AttrError; -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; /// The error type used by this crate. -#[derive(Clone, Debug)] +#[derive(thiserror::Error, Clone, Debug)] pub enum Error { /// IO error. /// /// `Arc` instead of `IoError` since `IoError` is not `Clone`. + #[error("I/O error: {0}")] Io(Arc), /// Input decoding error. If `encoding` feature is disabled, contains `None`, /// otherwise contains the UTF-8 decoding error + #[error("Malformed input, decoding impossible")] NonDecodable(Option), /// Unexpected End of File + #[error("Unexpected EOF during reading {0}")] UnexpectedEof(String), /// End event mismatch + #[error("Expecting found ")] EndEventMismatch { /// Expected end event expected: String, @@ -29,23 +31,33 @@ pub enum Error { found: String, }, /// Unexpected token + #[error("Unexpected token '{0}'")] UnexpectedToken(String), /// Unexpected + #[error( + "Only Comment (`--`), CDATA (`[CDATA[`) and DOCTYPE (`DOCTYPE`) nodes can start with a '!', but symbol `{}` found", + *(.0) as char)] UnexpectedBang(u8), /// Text not found, expected `Event::Text` + #[error("Cannot read text, expecting Event::Text")] TextNotFound, /// `Event::BytesDecl` must start with *version* attribute. Contains the attribute /// that was found or `None` if an xml declaration doesn't contain attributes. + #[error("XmlDecl must start with 'version' attribute, found {0:?}")] XmlDeclWithoutVersion(Option), /// Empty `Event::DocType`. `` is correct but ` is not. /// /// See + #[error("DOCTYPE declaration must not be empty")] EmptyDocType, /// Attribute parsing error + #[error("error while parsing attribute: {0}")] InvalidAttr(AttrError), /// Escape error + #[error("{0}")] EscapeError(EscapeError), /// Specified namespace prefix is unknown, cannot resolve namespace for it + #[error("Uknonwn namespace prefix '{:?}'", crate::utils::Bytes(.0))] UnknownPrefix(Vec), } @@ -91,52 +103,6 @@ impl From for Error { /// A specialized `Result` type where the error is hard-wired to [`Error`]. pub type Result = std::result::Result; -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::NonDecodable(None) => write!(f, "Malformed input, decoding impossible"), - Error::NonDecodable(Some(e)) => write!(f, "Malformed UTF-8 input: {}", e), - Error::UnexpectedEof(e) => write!(f, "Unexpected EOF during reading {}", e), - Error::EndEventMismatch { expected, found } => { - write!(f, "Expecting found ", expected, found) - } - Error::UnexpectedToken(e) => write!(f, "Unexpected token '{}'", e), - Error::UnexpectedBang(b) => write!( - f, - "Only Comment (`--`), CDATA (`[CDATA[`) and DOCTYPE (`DOCTYPE`) nodes can start with a '!', but symbol `{}` found", - *b as char - ), - Error::TextNotFound => write!(f, "Cannot read text, expecting Event::Text"), - Error::XmlDeclWithoutVersion(e) => write!( - f, - "XmlDecl must start with 'version' attribute, found {:?}", - e - ), - Error::EmptyDocType => write!(f, "DOCTYPE declaration must not be empty"), - 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("'") - } - } - } -} - -impl std::error::Error for Error { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match self { - Error::Io(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 { //! A module to handle serde (de)serialization errors