Skip to content

Commit e93181c

Browse files
authored
Merge pull request #810 from RedPhoenixQ/io-errors
Return `std::io::Error` from Writer methods
2 parents ccb8b6f + 39b5905 commit e93181c

File tree

12 files changed

+221
-177
lines changed

12 files changed

+221
-177
lines changed

Changelog.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@
1919

2020
### Misc Changes
2121

22+
- [#227]: Split `SeError` from `DeError` in the `serialize` feature.
23+
Serialize functions and methods now return `SeError`.
24+
- [#810]: Return `std::io::Error` from `Writer` methods.
25+
26+
[#227]: https://github.com/tafia/quick-xml/issues/227
27+
[#810]: https://github.com/tafia/quick-xml/pull/810
28+
2229

2330
## 0.36.2 -- 2024-09-20
2431

src/errors.rs

Lines changed: 68 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ impl std::error::Error for IllFormedError {}
159159
/// The error type used by this crate.
160160
#[derive(Clone, Debug)]
161161
pub enum Error {
162-
/// XML document cannot be read from or written to underlying source.
162+
/// XML document cannot be read from underlying source.
163163
///
164164
/// Contains the reference-counted I/O error to make the error type `Clone`able.
165165
Io(Arc<IoError>),
@@ -345,19 +345,6 @@ pub mod serialize {
345345
/// [`Event::Start`]: crate::events::Event::Start
346346
/// [`Event::End`]: crate::events::Event::End
347347
UnexpectedEof,
348-
/// An attempt to deserialize to a type, that is not supported by the XML
349-
/// store at current position, for example, attempt to deserialize `struct`
350-
/// from attribute or attempt to deserialize binary data.
351-
///
352-
/// Serialized type cannot be represented in an XML due to violation of the
353-
/// XML rules in the final XML document. For example, attempt to serialize
354-
/// a `HashMap<{integer}, ...>` would cause this error because [XML name]
355-
/// cannot start from a digit or a hyphen (minus sign). The same result
356-
/// would occur if map key is a complex type that cannot be serialized as
357-
/// a primitive type (i.e. string, char, bool, unit struct or unit variant).
358-
///
359-
/// [XML name]: https://www.w3.org/TR/xml11/#sec-common-syn
360-
Unsupported(Cow<'static, str>),
361348
/// Too many events were skipped while deserializing a sequence, event limit
362349
/// exceeded. The limit was provided as an argument
363350
#[cfg(feature = "overlapped-lists")]
@@ -379,7 +366,6 @@ pub mod serialize {
379366
f.write_str(")`")
380367
}
381368
DeError::UnexpectedEof => write!(f, "Unexpected `Event::Eof`"),
382-
DeError::Unsupported(s) => write!(f, "Unsupported operation: {}", s),
383369
#[cfg(feature = "overlapped-lists")]
384370
DeError::TooManyEvents(s) => write!(f, "Deserializer buffers {} events, limit exceeded", s),
385371
}
@@ -403,12 +389,6 @@ pub mod serialize {
403389
}
404390
}
405391

406-
impl serde::ser::Error for DeError {
407-
fn custom<T: fmt::Display>(msg: T) -> Self {
408-
DeError::Custom(msg.to_string())
409-
}
410-
}
411-
412392
impl From<Error> for DeError {
413393
#[inline]
414394
fn from(e: Error) -> Self {
@@ -458,10 +438,75 @@ pub mod serialize {
458438
}
459439
}
460440

461-
impl From<fmt::Error> for DeError {
441+
/// Serialization error
442+
#[derive(Clone, Debug)]
443+
pub enum SeError {
444+
/// Serde custom error
445+
Custom(String),
446+
/// XML document cannot be written to underlying source.
447+
///
448+
/// Contains the reference-counted I/O error to make the error type `Clone`able.
449+
Io(Arc<IoError>),
450+
/// Some value could not be formatted
451+
Fmt(std::fmt::Error),
452+
/// Serialized type cannot be represented in an XML due to violation of the
453+
/// XML rules in the final XML document. For example, attempt to serialize
454+
/// a `HashMap<{integer}, ...>` would cause this error because [XML name]
455+
/// cannot start from a digit or a hyphen (minus sign). The same result
456+
/// would occur if map key is a complex type that cannot be serialized as
457+
/// a primitive type (i.e. string, char, bool, unit struct or unit variant).
458+
///
459+
/// [XML name]: https://www.w3.org/TR/xml11/#sec-common-syn
460+
Unsupported(Cow<'static, str>),
461+
/// Some value could not be turned to UTF-8
462+
NonEncodable(Utf8Error),
463+
}
464+
465+
impl fmt::Display for SeError {
466+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
467+
match self {
468+
SeError::Custom(s) => write!(f, "{}", s),
469+
SeError::Io(e) => write!(f, "I/O error: {}", e),
470+
SeError::Fmt(e) => write!(f, "formatting error: {}", e),
471+
SeError::Unsupported(s) => write!(f, "unsupported value: {}", s),
472+
SeError::NonEncodable(e) => write!(f, "malformed UTF-8: {}", e),
473+
}
474+
}
475+
}
476+
477+
impl ::std::error::Error for SeError {
478+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
479+
match self {
480+
SeError::Io(e) => Some(e),
481+
_ => None,
482+
}
483+
}
484+
}
485+
486+
impl serde::ser::Error for SeError {
487+
fn custom<T: fmt::Display>(msg: T) -> Self {
488+
SeError::Custom(msg.to_string())
489+
}
490+
}
491+
492+
impl From<IoError> for SeError {
493+
#[inline]
494+
fn from(e: IoError) -> Self {
495+
Self::Io(Arc::new(e))
496+
}
497+
}
498+
499+
impl From<Utf8Error> for SeError {
500+
#[inline]
501+
fn from(e: Utf8Error) -> Self {
502+
Self::NonEncodable(e)
503+
}
504+
}
505+
506+
impl From<fmt::Error> for SeError {
462507
#[inline]
463508
fn from(e: fmt::Error) -> Self {
464-
Self::Custom(e.to_string())
509+
Self::Fmt(e)
465510
}
466511
}
467512
}

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ pub mod writer;
7373
// reexports
7474
pub use crate::encoding::Decoder;
7575
#[cfg(feature = "serialize")]
76-
pub use crate::errors::serialize::DeError;
76+
pub use crate::errors::serialize::{DeError, SeError};
7777
pub use crate::errors::{Error, Result};
7878
pub use crate::reader::{NsReader, Reader};
7979
pub use crate::writer::{ElementWriter, Writer};

src/se/content.rs

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
//! Contains serializer for content of an XML element
22
33
use crate::de::TEXT_KEY;
4-
use crate::errors::serialize::DeError;
54
use crate::se::element::{ElementSerializer, Struct, Tuple};
65
use crate::se::simple_type::{QuoteTarget, SimpleTypeSerializer};
7-
use crate::se::{Indent, QuoteLevel, XmlName};
6+
use crate::se::{Indent, QuoteLevel, SeError, XmlName};
87
use serde::ser::{
98
Impossible, Serialize, SerializeSeq, SerializeTuple, SerializeTupleStruct, Serializer,
109
};
@@ -36,7 +35,7 @@ macro_rules! write_primitive {
3635
/// - units (`()`) and unit structs does not write anything;
3736
/// - sequences, tuples and tuple structs are serialized without delimiters.
3837
/// `[1, 2, 3]` would be serialized as `123` (if not using indent);
39-
/// - structs and maps are not supported ([`DeError::Unsupported`] is returned);
38+
/// - structs and maps are not supported ([`SeError::Unsupported`] is returned);
4039
/// - enums:
4140
/// - unit variants are serialized as self-closed `<variant/>`;
4241
/// - newtype variants are serialized as inner value wrapped in `<variant>...</variant>`;
@@ -108,7 +107,7 @@ impl<'w, 'i, W: Write> ContentSerializer<'w, 'i, W> {
108107

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

127126
/// Writes simple type content between `name` tags
128-
pub(super) fn write_wrapped<S>(mut self, name: XmlName, serialize: S) -> Result<(), DeError>
127+
pub(super) fn write_wrapped<S>(mut self, name: XmlName, serialize: S) -> Result<(), SeError>
129128
where
130-
S: for<'a> FnOnce(SimpleTypeSerializer<'i, &'a mut W>) -> Result<&'a mut W, DeError>,
129+
S: for<'a> FnOnce(SimpleTypeSerializer<'i, &'a mut W>) -> Result<&'a mut W, SeError>,
131130
{
132131
self.write_indent()?;
133132
self.writer.write_char('<')?;
@@ -142,7 +141,7 @@ impl<'w, 'i, W: Write> ContentSerializer<'w, 'i, W> {
142141
Ok(())
143142
}
144143

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

154153
impl<'w, 'i, W: Write> Serializer for ContentSerializer<'w, 'i, W> {
155154
type Ok = ();
156-
type Error = DeError;
155+
type Error = SeError;
157156

158157
type SerializeSeq = Self;
159158
type SerializeTuple = Self;
@@ -310,7 +309,7 @@ impl<'w, 'i, W: Write> Serializer for ContentSerializer<'w, 'i, W> {
310309
}
311310

312311
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
313-
Err(DeError::Unsupported(
312+
Err(SeError::Unsupported(
314313
"serialization of map types is not supported in `$value` field".into(),
315314
))
316315
}
@@ -321,7 +320,7 @@ impl<'w, 'i, W: Write> Serializer for ContentSerializer<'w, 'i, W> {
321320
name: &'static str,
322321
_len: usize,
323322
) -> Result<Self::SerializeStruct, Self::Error> {
324-
Err(DeError::Unsupported(
323+
Err(SeError::Unsupported(
325324
format!("serialization of struct `{name}` is not supported in `$value` field").into(),
326325
))
327326
}
@@ -345,7 +344,7 @@ impl<'w, 'i, W: Write> Serializer for ContentSerializer<'w, 'i, W> {
345344
len: usize,
346345
) -> Result<Self::SerializeStructVariant, Self::Error> {
347346
if variant == TEXT_KEY {
348-
Err(DeError::Unsupported(
347+
Err(SeError::Unsupported(
349348
format!("cannot serialize `$text` struct variant of `{}` enum", name).into(),
350349
))
351350
} else {
@@ -360,7 +359,7 @@ impl<'w, 'i, W: Write> Serializer for ContentSerializer<'w, 'i, W> {
360359

361360
impl<'w, 'i, W: Write> SerializeSeq for ContentSerializer<'w, 'i, W> {
362361
type Ok = ();
363-
type Error = DeError;
362+
type Error = SeError;
364363

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

381380
impl<'w, 'i, W: Write> SerializeTuple for ContentSerializer<'w, 'i, W> {
382381
type Ok = ();
383-
type Error = DeError;
382+
type Error = SeError;
384383

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

399398
impl<'w, 'i, W: Write> SerializeTupleStruct for ContentSerializer<'w, 'i, W> {
400399
type Ok = ();
401-
type Error = DeError;
400+
type Error = SeError;
402401

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

575574
match $data.serialize(ser).unwrap_err() {
576-
DeError::$kind(e) => assert_eq!(e, $reason),
575+
SeError::$kind(e) => assert_eq!(e, $reason),
577576
e => panic!(
578577
"Expected `Err({}({}))`, but got `{:?}`",
579578
stringify!($kind),
@@ -1013,7 +1012,7 @@ pub(super) mod tests {
10131012
};
10141013

10151014
match $data.serialize(ser).unwrap_err() {
1016-
DeError::$kind(e) => assert_eq!(e, $reason),
1015+
SeError::$kind(e) => assert_eq!(e, $reason),
10171016
e => panic!(
10181017
"Expected `Err({}({}))`, but got `{:?}`",
10191018
stringify!($kind),

0 commit comments

Comments
 (0)