Skip to content

Commit

Permalink
Merge pull request #810 from RedPhoenixQ/io-errors
Browse files Browse the repository at this point in the history
Return `std::io::Error` from Writer methods
  • Loading branch information
Mingun authored Sep 29, 2024
2 parents ccb8b6f + 39b5905 commit e93181c
Show file tree
Hide file tree
Showing 12 changed files with 221 additions and 177 deletions.
7 changes: 7 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@

### Misc Changes

- [#227]: Split `SeError` from `DeError` in the `serialize` feature.
Serialize functions and methods now return `SeError`.
- [#810]: Return `std::io::Error` from `Writer` methods.

[#227]: https://github.com/tafia/quick-xml/issues/227
[#810]: https://github.com/tafia/quick-xml/pull/810


## 0.36.2 -- 2024-09-20

Expand Down
91 changes: 68 additions & 23 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ impl std::error::Error for IllFormedError {}
/// The error type used by this crate.
#[derive(Clone, Debug)]
pub enum Error {
/// XML document cannot be read from or written to underlying source.
/// XML document cannot be read from underlying source.
///
/// Contains the reference-counted I/O error to make the error type `Clone`able.
Io(Arc<IoError>),
Expand Down Expand Up @@ -345,19 +345,6 @@ pub mod serialize {
/// [`Event::Start`]: crate::events::Event::Start
/// [`Event::End`]: crate::events::Event::End
UnexpectedEof,
/// An attempt to deserialize to a type, that is not supported by the XML
/// store at current position, for example, attempt to deserialize `struct`
/// from attribute or attempt to deserialize binary data.
///
/// Serialized type cannot be represented in an XML due to violation of the
/// XML rules in the final XML document. For example, attempt to serialize
/// a `HashMap<{integer}, ...>` would cause this error because [XML name]
/// cannot start from a digit or a hyphen (minus sign). The same result
/// would occur if map key is a complex type that cannot be serialized as
/// a primitive type (i.e. string, char, bool, unit struct or unit variant).
///
/// [XML name]: https://www.w3.org/TR/xml11/#sec-common-syn
Unsupported(Cow<'static, str>),
/// Too many events were skipped while deserializing a sequence, event limit
/// exceeded. The limit was provided as an argument
#[cfg(feature = "overlapped-lists")]
Expand All @@ -379,7 +366,6 @@ pub mod serialize {
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),
}
Expand All @@ -403,12 +389,6 @@ pub mod serialize {
}
}

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 {
Expand Down Expand Up @@ -458,10 +438,75 @@ pub mod serialize {
}
}

impl From<fmt::Error> for DeError {
/// Serialization error
#[derive(Clone, Debug)]
pub enum SeError {
/// Serde custom error
Custom(String),
/// XML document cannot be written to underlying source.
///
/// Contains the reference-counted I/O error to make the error type `Clone`able.
Io(Arc<IoError>),
/// Some value could not be formatted
Fmt(std::fmt::Error),
/// Serialized type cannot be represented in an XML due to violation of the
/// XML rules in the final XML document. For example, attempt to serialize
/// a `HashMap<{integer}, ...>` would cause this error because [XML name]
/// cannot start from a digit or a hyphen (minus sign). The same result
/// would occur if map key is a complex type that cannot be serialized as
/// a primitive type (i.e. string, char, bool, unit struct or unit variant).
///
/// [XML name]: https://www.w3.org/TR/xml11/#sec-common-syn
Unsupported(Cow<'static, str>),
/// Some value could not be turned to UTF-8
NonEncodable(Utf8Error),
}

impl fmt::Display for SeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
SeError::Custom(s) => write!(f, "{}", s),
SeError::Io(e) => write!(f, "I/O error: {}", e),
SeError::Fmt(e) => write!(f, "formatting error: {}", e),
SeError::Unsupported(s) => write!(f, "unsupported value: {}", s),
SeError::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 {
SeError::Io(e) => Some(e),
_ => None,
}
}
}

impl serde::ser::Error for SeError {
fn custom<T: fmt::Display>(msg: T) -> Self {
SeError::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::Custom(e.to_string())
Self::Fmt(e)
}
}
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ pub mod writer;
// reexports
pub use crate::encoding::Decoder;
#[cfg(feature = "serialize")]
pub use crate::errors::serialize::DeError;
pub use crate::errors::serialize::{DeError, SeError};
pub use crate::errors::{Error, Result};
pub use crate::reader::{NsReader, Reader};
pub use crate::writer::{ElementWriter, Writer};
31 changes: 15 additions & 16 deletions src/se/content.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
//! Contains serializer for content of an XML element

use crate::de::TEXT_KEY;
use crate::errors::serialize::DeError;
use crate::se::element::{ElementSerializer, Struct, Tuple};
use crate::se::simple_type::{QuoteTarget, SimpleTypeSerializer};
use crate::se::{Indent, QuoteLevel, XmlName};
use crate::se::{Indent, QuoteLevel, SeError, XmlName};
use serde::ser::{
Impossible, Serialize, SerializeSeq, SerializeTuple, SerializeTupleStruct, Serializer,
};
Expand Down Expand Up @@ -36,7 +35,7 @@ macro_rules! write_primitive {
/// - units (`()`) and unit structs does not write anything;
/// - sequences, tuples and tuple structs are serialized without delimiters.
/// `[1, 2, 3]` would be serialized as `123` (if not using indent);
/// - structs and maps are not supported ([`DeError::Unsupported`] is returned);
/// - structs and maps are not supported ([`SeError::Unsupported`] is returned);
/// - enums:
/// - unit variants are serialized as self-closed `<variant/>`;
/// - newtype variants are serialized as inner value wrapped in `<variant>...</variant>`;
Expand Down Expand Up @@ -108,7 +107,7 @@ impl<'w, 'i, W: Write> ContentSerializer<'w, 'i, W> {

/// Writes `name` as self-closed tag
#[inline]
pub(super) fn write_empty(mut self, name: XmlName) -> Result<(), DeError> {
pub(super) fn write_empty(mut self, name: XmlName) -> Result<(), SeError> {
self.write_indent()?;
if self.expand_empty_elements {
self.writer.write_char('<')?;
Expand All @@ -125,9 +124,9 @@ impl<'w, 'i, W: Write> ContentSerializer<'w, 'i, W> {
}

/// Writes simple type content between `name` tags
pub(super) fn write_wrapped<S>(mut self, name: XmlName, serialize: S) -> Result<(), DeError>
pub(super) fn write_wrapped<S>(mut self, name: XmlName, serialize: S) -> Result<(), SeError>
where
S: for<'a> FnOnce(SimpleTypeSerializer<'i, &'a mut W>) -> Result<&'a mut W, DeError>,
S: for<'a> FnOnce(SimpleTypeSerializer<'i, &'a mut W>) -> Result<&'a mut W, SeError>,
{
self.write_indent()?;
self.writer.write_char('<')?;
Expand All @@ -142,7 +141,7 @@ impl<'w, 'i, W: Write> ContentSerializer<'w, 'i, W> {
Ok(())
}

pub(super) fn write_indent(&mut self) -> Result<(), DeError> {
pub(super) fn write_indent(&mut self) -> Result<(), SeError> {
if self.write_indent {
self.indent.write_indent(&mut self.writer)?;
self.write_indent = false;
Expand All @@ -153,7 +152,7 @@ impl<'w, 'i, W: Write> ContentSerializer<'w, 'i, W> {

impl<'w, 'i, W: Write> Serializer for ContentSerializer<'w, 'i, W> {
type Ok = ();
type Error = DeError;
type Error = SeError;

type SerializeSeq = Self;
type SerializeTuple = Self;
Expand Down Expand Up @@ -310,7 +309,7 @@ impl<'w, 'i, W: Write> Serializer for ContentSerializer<'w, 'i, W> {
}

fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
Err(DeError::Unsupported(
Err(SeError::Unsupported(
"serialization of map types is not supported in `$value` field".into(),
))
}
Expand All @@ -321,7 +320,7 @@ impl<'w, 'i, W: Write> Serializer for ContentSerializer<'w, 'i, W> {
name: &'static str,
_len: usize,
) -> Result<Self::SerializeStruct, Self::Error> {
Err(DeError::Unsupported(
Err(SeError::Unsupported(
format!("serialization of struct `{name}` is not supported in `$value` field").into(),
))
}
Expand All @@ -345,7 +344,7 @@ impl<'w, 'i, W: Write> Serializer for ContentSerializer<'w, 'i, W> {
len: usize,
) -> Result<Self::SerializeStructVariant, Self::Error> {
if variant == TEXT_KEY {
Err(DeError::Unsupported(
Err(SeError::Unsupported(
format!("cannot serialize `$text` struct variant of `{}` enum", name).into(),
))
} else {
Expand All @@ -360,7 +359,7 @@ impl<'w, 'i, W: Write> Serializer for ContentSerializer<'w, 'i, W> {

impl<'w, 'i, W: Write> SerializeSeq for ContentSerializer<'w, 'i, W> {
type Ok = ();
type Error = DeError;
type Error = SeError;

fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
where
Expand All @@ -380,7 +379,7 @@ impl<'w, 'i, W: Write> SerializeSeq for ContentSerializer<'w, 'i, W> {

impl<'w, 'i, W: Write> SerializeTuple for ContentSerializer<'w, 'i, W> {
type Ok = ();
type Error = DeError;
type Error = SeError;

#[inline]
fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
Expand All @@ -398,7 +397,7 @@ impl<'w, 'i, W: Write> SerializeTuple for ContentSerializer<'w, 'i, W> {

impl<'w, 'i, W: Write> SerializeTupleStruct for ContentSerializer<'w, 'i, W> {
type Ok = ();
type Error = DeError;
type Error = SeError;

#[inline]
fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
Expand Down Expand Up @@ -573,7 +572,7 @@ pub(super) mod tests {
};

match $data.serialize(ser).unwrap_err() {
DeError::$kind(e) => assert_eq!(e, $reason),
SeError::$kind(e) => assert_eq!(e, $reason),
e => panic!(
"Expected `Err({}({}))`, but got `{:?}`",
stringify!($kind),
Expand Down Expand Up @@ -1013,7 +1012,7 @@ pub(super) mod tests {
};

match $data.serialize(ser).unwrap_err() {
DeError::$kind(e) => assert_eq!(e, $reason),
SeError::$kind(e) => assert_eq!(e, $reason),
e => panic!(
"Expected `Err({}({}))`, but got `{:?}`",
stringify!($kind),
Expand Down
Loading

0 comments on commit e93181c

Please sign in to comment.