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

Added '$struct' tag to identify structs in newtype enum variants. #359

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
23 changes: 21 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,8 @@ fn crates_io() -> Result<Html, DeError> {

### Credits

This has largely been inspired by [serde-xml-rs](https://github.com/RReverser/serde-xml-rs).
quick-xml follows its convention for deserialization, including the
This has largely been inspired by [serde-xml-rs](https://github.com/RReverser/serde-xml-rs).
quick-xml follows its convention for deserialization, including the
[`$value`](https://github.com/RReverser/serde-xml-rs#parsing-the-value-of-a-tag) special name.

### Parsing the "value" of a tag
Expand Down Expand Up @@ -260,6 +260,25 @@ struct Root {

Serializing `Root { foo: Foo::Bar }` will then yield `<Root foo="Bar"/>` instead of `<Root><Bar/></Root>`.

### Serializing newtype variants
The `$struct` tag is an experimental feature that allows serializing newtype variants where the newtype is a struct.
Please note that this feature will only work for serialization, therefore serde rename should be called only for serialize, unlike in the other features described before.
See here:

```rust, ignore
struct Foo {
a: String
}

enum Bar {
#[serde(rename(serialize = "$struct"))]
x(Foo)
}
```

This is only necessary for structs passed in newtype variants.
In the case of struct variants or when the newtype is a primitive adding this tag should be avoided.

### Performance

Note that despite not focusing on performance (there are several unecessary copies), it remains about 10x faster than serde-xml-rs.
Expand Down
2 changes: 2 additions & 0 deletions src/de/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,10 @@ use std::borrow::Cow;
use std::io::BufRead;

pub(crate) const INNER_VALUE: &str = "$value";
pub(crate) const STRUCT_TAG: &str = "$struct";
pub(crate) const UNFLATTEN_PREFIX: &str = "$unflatten=";
pub(crate) const PRIMITIVE_PREFIX: &str = "$primitive=";
pub(crate) const DOCUMENT_PREFIX: &str = "$root=";

/// Simplified event which contains only these variants that used by deserializer
#[derive(Debug, PartialEq)]
Expand Down
27 changes: 23 additions & 4 deletions src/se/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ mod var;

use self::var::{Map, Seq, Struct, Tuple};
use crate::{
de::PRIMITIVE_PREFIX,
de::{DOCUMENT_PREFIX, PRIMITIVE_PREFIX, STRUCT_TAG},
errors::serialize::DeError,
events::{BytesEnd, BytesStart, BytesText, Event},
events::{BytesDecl, BytesEnd, BytesStart, BytesText, Event},
writer::Writer,
};
use serde::ser::{self, Serialize};
Expand Down Expand Up @@ -129,6 +129,15 @@ impl<'r, W: Write> Serializer<'r, W> {
.write_event(Event::End(BytesEnd::borrowed(tag_name.as_bytes())))?;
Ok(())
}

fn write_declaration(&mut self) -> Result<(), DeError> {
self.writer.write_event(Event::Decl(BytesDecl::new(
"1.0".as_bytes(),
Some("UTF-8".as_bytes()),
None,
)))?;
Ok(())
}
}

impl<'r, 'w, W: Write> ser::Serializer for &'w mut Serializer<'r, W> {
Expand Down Expand Up @@ -262,7 +271,12 @@ impl<'r, 'w, W: Write> ser::Serializer for &'w mut Serializer<'r, W> {
// (`variant`), we need to clear root tag before writing content and restore
// it after
let root = self.root_tag.take();
let result = self.write_paired(variant, value);
let result;
if variant == STRUCT_TAG {
result = value.serialize(&mut *self);
} else {
result = self.write_paired(variant, value)
}
self.root_tag = root;
result
}
Expand Down Expand Up @@ -315,7 +329,12 @@ impl<'r, 'w, W: Write> ser::Serializer for &'w mut Serializer<'r, W> {
name: &'static str,
_len: usize,
) -> Result<Self::SerializeStruct, DeError> {
Ok(Struct::new(self, self.root_tag.unwrap_or(name)))
let mut element_name = self.root_tag.unwrap_or(name);
if element_name.starts_with(DOCUMENT_PREFIX) {
self.write_declaration()?;
element_name = name.split_at(DOCUMENT_PREFIX.len()).1;
}
Ok(Struct::new(self, element_name))
}

fn serialize_struct_variant(
Expand Down