Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Return std::io::Error from Writer methods #810

Merged
merged 6 commits into from
Sep 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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