Skip to content

Commit

Permalink
Merge pull request #574 from Mingun/ser-text-enum
Browse files Browse the repository at this point in the history
Implement correct handling of `$text` fields in enums and add roundtrip tests
  • Loading branch information
Mingun committed Mar 7, 2023
2 parents 4b298fd + c2482c5 commit 7792983
Show file tree
Hide file tree
Showing 4 changed files with 444 additions and 108 deletions.
4 changes: 2 additions & 2 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@

### New Features

- [#541]: Deserialize specially named `$text` enum variant in [externally tagged]
enums from textual content
- [#541]: (De)serialize specially named `$text` enum variant in [externally tagged]
enums to / from textual content
- [#556]: `to_writer` and `to_string` now accept `?Sized` types
- [#556]: Add new `to_writer_with_root` and `to_string_with_root` helper functions
- [#520]: Add methods `BytesText::inplace_trim_start` and `BytesText::inplace_trim_end`
Expand Down
6 changes: 3 additions & 3 deletions src/se/content.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Contains serializer for content of an XML element

use crate::errors::serialize::DeError;
use crate::se::element::{ElementSerializer, Struct};
use crate::se::element::{ElementSerializer, Struct, Tuple};
use crate::se::simple_type::{QuoteTarget, SimpleTypeSerializer};
use crate::se::{Indent, QuoteLevel, XmlName};
use serde::ser::{
Expand Down Expand Up @@ -132,7 +132,7 @@ impl<'w, 'i, W: Write> Serializer for ContentSerializer<'w, 'i, W> {
type SerializeSeq = Self;
type SerializeTuple = Self;
type SerializeTupleStruct = Self;
type SerializeTupleVariant = ElementSerializer<'w, 'i, W>;
type SerializeTupleVariant = Tuple<'w, 'i, W>;
type SerializeMap = Impossible<Self::Ok, Self::Error>;
type SerializeStruct = Impossible<Self::Ok, Self::Error>;
type SerializeStructVariant = Struct<'w, 'i, W>;
Expand Down Expand Up @@ -258,7 +258,7 @@ impl<'w, 'i, W: Write> Serializer for ContentSerializer<'w, 'i, W> {
// `ElementSerializer::serialize_tuple_variant` is the same as
// `ElementSerializer::serialize_tuple_struct`, except that it replaces `.key`
// to `variant` which is not required here
ser.serialize_tuple_struct(name, len)
ser.serialize_tuple_struct(name, len).map(Tuple::Element)
}

fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
Expand Down
71 changes: 57 additions & 14 deletions src/se/element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::de::{TEXT_KEY, VALUE_KEY};
use crate::errors::serialize::DeError;
use crate::se::content::ContentSerializer;
use crate::se::key::QNameSerializer;
use crate::se::simple_type::{QuoteTarget, SimpleTypeSerializer};
use crate::se::simple_type::{QuoteTarget, SimpleSeq, SimpleTypeSerializer};
use crate::se::{Indent, XmlName};
use serde::ser::{
Serialize, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple,
Expand Down Expand Up @@ -37,7 +37,7 @@ impl<'w, 'k, W: Write> Serializer for ElementSerializer<'w, 'k, W> {
type SerializeSeq = Self;
type SerializeTuple = Self;
type SerializeTupleStruct = Self;
type SerializeTupleVariant = Self;
type SerializeTupleVariant = Tuple<'w, 'k, W>;
type SerializeMap = Map<'w, 'k, W>;
type SerializeStruct = Struct<'w, 'k, W>;
type SerializeStructVariant = Struct<'w, 'k, W>;
Expand Down Expand Up @@ -105,12 +105,19 @@ impl<'w, 'k, W: Write> Serializer for ElementSerializer<'w, 'k, W> {

fn serialize_unit_variant(
self,
_name: &'static str,
name: &'static str,
_variant_index: u32,
variant: &'static str,
) -> Result<Self::Ok, Self::Error> {
let name = XmlName::try_from(variant)?;
self.ser.write_empty(name)
if variant == TEXT_KEY {
// We should write some text but we don't known what text to write
Err(DeError::Unsupported(
format!("`{}::$text` unit variant cannot be serialized", name).into(),
))
} else {
let name = XmlName::try_from(variant)?;
self.ser.write_empty(name)
}
}

fn serialize_newtype_struct<T: ?Sized + Serialize>(
Expand All @@ -128,8 +135,13 @@ impl<'w, 'k, W: Write> Serializer for ElementSerializer<'w, 'k, W> {
variant: &'static str,
value: &T,
) -> Result<Self::Ok, Self::Error> {
self.key = XmlName::try_from(variant)?;
value.serialize(self)
if variant == TEXT_KEY {
value.serialize(self.ser.into_simple_type_serializer())?;
Ok(())
} else {
self.key = XmlName::try_from(variant)?;
value.serialize(self)
}
}

#[inline]
Expand Down Expand Up @@ -159,8 +171,15 @@ impl<'w, 'k, W: Write> Serializer for ElementSerializer<'w, 'k, W> {
variant: &'static str,
len: usize,
) -> Result<Self::SerializeTupleVariant, Self::Error> {
self.key = XmlName::try_from(variant)?;
self.serialize_tuple_struct(name, len)
if variant == TEXT_KEY {
self.ser
.into_simple_type_serializer()
.serialize_tuple_struct(name, len)
.map(Tuple::Text)
} else {
self.key = XmlName::try_from(variant)?;
self.serialize_tuple_struct(name, len).map(Tuple::Element)
}
}

fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
Expand Down Expand Up @@ -195,8 +214,14 @@ impl<'w, 'k, W: Write> Serializer for ElementSerializer<'w, 'k, W> {
variant: &'static str,
len: usize,
) -> Result<Self::SerializeStructVariant, Self::Error> {
self.key = XmlName::try_from(variant)?;
self.serialize_struct(name, len)
if variant == TEXT_KEY {
Err(DeError::Unsupported(
format!("`{}::$text` struct variant cannot be serialized", name).into(),
))
} else {
self.key = XmlName::try_from(variant)?;
self.serialize_struct(name, len)
}
}
}

Expand Down Expand Up @@ -259,7 +284,19 @@ impl<'w, 'k, W: Write> SerializeTupleStruct for ElementSerializer<'w, 'k, W> {
}
}

impl<'w, 'k, W: Write> SerializeTupleVariant for ElementSerializer<'w, 'k, W> {
////////////////////////////////////////////////////////////////////////////////////////////////////

/// A serializer for tuple variants. Tuples can be serialized in two modes:
/// - wrapping each tuple field into a tag
/// - without wrapping, fields are delimited by a space
pub enum Tuple<'w, 'k, W: Write> {
/// Serialize each tuple field as an element
Element(ElementSerializer<'w, 'k, W>),
/// Serialize tuple as an `xs:list`: space-delimited content of fields
Text(SimpleSeq<'k, &'w mut W>),
}

impl<'w, 'k, W: Write> SerializeTupleVariant for Tuple<'w, 'k, W> {
type Ok = ();
type Error = DeError;

Expand All @@ -268,12 +305,18 @@ impl<'w, 'k, W: Write> SerializeTupleVariant for ElementSerializer<'w, 'k, W> {
where
T: ?Sized + Serialize,
{
<Self as SerializeTuple>::serialize_element(self, value)
match self {
Tuple::Element(ser) => SerializeTuple::serialize_element(ser, value),
Tuple::Text(ser) => SerializeTuple::serialize_element(ser, value),
}
}

#[inline]
fn end(self) -> Result<Self::Ok, Self::Error> {
<Self as SerializeTuple>::end(self)
match self {
Tuple::Element(ser) => SerializeTuple::end(ser),
Tuple::Text(ser) => SerializeTuple::end(ser).map(|_| ()),
}
}
}

Expand Down

0 comments on commit 7792983

Please sign in to comment.