-
Notifications
You must be signed in to change notification settings - Fork 236
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
Rewrite serializer #490
Rewrite serializer #490
Conversation
Codecov ReportAttention: Patch coverage is
❗ Your organization needs to install the Codecov GitHub app to enable full functionality. Additional details and impacted files@@ Coverage Diff @@
## master #490 +/- ##
==========================================
+ Coverage 54.16% 61.66% +7.50%
==========================================
Files 30 33 +3
Lines 12649 15343 +2694
==========================================
+ Hits 6851 9462 +2611
- Misses 5798 5881 +83
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
I might need a few days for this |
How does one achieve the previous behavior of enums where the enum value would be wrapped in the enum type tag? enum Wat {
Foo,
Bar,
Baz
}
struct Test {
wat: Wat,
} results in <Test>
<Foo/>
</Test> and if you add <Test>
Foo
</Test> Is the intention that we wrap the enum in a wrapper struct if we want type tags for the enum? <Test>
<Wat>Foo</Wat>
</Test> I guess this makes it consistent with the way lists are handled, and also consistent with the philosophical standpoint that enum is simply one of N possible values, and not a container. We should probably document this change, though. |
It appears that the mod try_enum {
use quick_xml::{de::from_str, se::to_string};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
enum WatEnum {
#[serde(rename="FOO")]
Foo,
#[serde(rename="BAR")]
Bar,
#[serde(rename="BAZ")]
Baz
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
struct Wat {
wat: WatEnum
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
struct Wat2 {
#[serde(rename="#any")]
wat: WatEnum
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
struct Wat3 {
#[serde(rename="#text")]
wat: WatEnum
}
#[test] // This fails
fn round_trip_enum_none() {
let tst = Wat { wat: WatEnum::Bar };
let data = to_string(&tst).unwrap();
println!("{:?}", &data);
let tst_again: Wat = from_str(data.as_str()).unwrap();
assert_eq!(&tst, &tst_again);
}
#[test] // This works
fn round_trip_enum_any() {
let tst = Wat2 { wat: WatEnum::Bar };
let data = to_string(&tst).unwrap();
println!("{:?}", &data);
let tst_again: Wat2 = from_str(data.as_str()).unwrap();
assert_eq!(&tst, &tst_again);
}
#[test] // this works
fn round_trip_enum_text() {
let tst = Wat3 { wat: WatEnum::Bar };
let data = to_string(&tst).unwrap();
println!("{:?}", &data);
let tst_again: Wat3 = from_str(data.as_str()).unwrap();
assert_eq!(&tst, &tst_again);
}
} |
Have you run benchmarks before and after? |
@dralley, no. The goal is to make a correct and consistent implementation first. There a no reason to worry about performance while the old implementation is just incorrect and inconsistent |
While in this PR this can be true, that is not desired behavior. This PR is just about serializer, I plan to continue work on deserializer part in next PRs. The final goal -- a consistent and composable implementation:
|
I'm not worried about performance, correctness is of course more important, it would just be good to know if it deserves some attention afterwards |
- `$text` serialized as a simple type - `$value` serialized as an element with name that depends from value instead of key - Text or CDATA elements deserialized as `$value` field, if that field is expected, and as `#text` field, if not expected - any not-listed in known fields elements deserialized as a `$value` field, if that field is expected doc-test failures (2): src\de\mod.rs - de (line 139) src\de\mod.rs - de (line 36) Co-authored-by: Daniel Alley <dalley@redhat.com>
…tafia#252 Still 2 doc-test failures
Still 2 doc-test failures
Serialization to attributes would be done only when field explicitly marked as an attribute failures (21): with_root::enum_::adjacently_tagged::flatten_struct with_root::enum_::adjacently_tagged::nested_struct with_root::enum_::adjacently_tagged::newtype with_root::enum_::adjacently_tagged::struct_ with_root::enum_::adjacently_tagged::text with_root::enum_::adjacently_tagged::tuple_struct with_root::enum_::adjacently_tagged::unit with_root::enum_::externally_tagged::nested_struct with_root::enum_::externally_tagged::struct_ with_root::enum_::externally_tagged::text with_root::enum_::internally_tagged::nested_struct with_root::enum_::internally_tagged::newtype with_root::enum_::internally_tagged::struct_ with_root::enum_::internally_tagged::text with_root::enum_::internally_tagged::unit with_root::enum_::untagged::nested_struct with_root::enum_::untagged::struct_ with_root::enum_::untagged::text with_root::nested_struct with_root::struct_ with_root::text
This commit changes expectations from serializing primitives - they should be wrapped in root tag failures (53): with_root::char_amp with_root::char_apos with_root::char_gt with_root::char_lt with_root::char_non_escaped with_root::char_quot with_root::char_space with_root::enum_::adjacently_tagged::flatten_struct with_root::enum_::adjacently_tagged::nested_struct with_root::enum_::adjacently_tagged::newtype with_root::enum_::adjacently_tagged::struct_ with_root::enum_::adjacently_tagged::text with_root::enum_::adjacently_tagged::tuple_struct with_root::enum_::adjacently_tagged::unit with_root::enum_::externally_tagged::nested_struct with_root::enum_::externally_tagged::primitive_unit with_root::enum_::externally_tagged::struct_ with_root::enum_::externally_tagged::text with_root::enum_::internally_tagged::nested_struct with_root::enum_::internally_tagged::newtype with_root::enum_::internally_tagged::struct_ with_root::enum_::internally_tagged::text with_root::enum_::internally_tagged::unit with_root::enum_::untagged::nested_struct with_root::enum_::untagged::newtype with_root::enum_::untagged::struct_ with_root::enum_::untagged::text with_root::enum_::untagged::unit with_root::f32_ with_root::f64_ with_root::false_ with_root::i128_ with_root::i16_ with_root::i32_ with_root::i64_ with_root::i8_ with_root::isize_ with_root::map with_root::nested_struct with_root::option_some with_root::seq with_root::str_escaped with_root::str_non_escaped with_root::struct_ with_root::text with_root::true_ with_root::u128_ with_root::u16_ with_root::u32_ with_root::u64_ with_root::u8_ with_root::unit with_root::usize_
… specified Now serializer tested in both modes: with and without root tag specified failures (114): with_root::char_amp with_root::char_apos with_root::char_gt with_root::char_lt with_root::char_non_escaped with_root::char_quot with_root::char_space with_root::enum_::adjacently_tagged::empty_struct with_root::enum_::adjacently_tagged::flatten_struct with_root::enum_::adjacently_tagged::nested_struct with_root::enum_::adjacently_tagged::newtype with_root::enum_::adjacently_tagged::struct_ with_root::enum_::adjacently_tagged::text with_root::enum_::adjacently_tagged::tuple_struct with_root::enum_::adjacently_tagged::unit with_root::enum_::externally_tagged::nested_struct with_root::enum_::externally_tagged::primitive_unit with_root::enum_::externally_tagged::struct_ with_root::enum_::externally_tagged::text with_root::enum_::internally_tagged::empty_struct with_root::enum_::internally_tagged::nested_struct with_root::enum_::internally_tagged::newtype with_root::enum_::internally_tagged::struct_ with_root::enum_::internally_tagged::text with_root::enum_::internally_tagged::unit with_root::enum_::untagged::nested_struct with_root::enum_::untagged::newtype with_root::enum_::untagged::struct_ with_root::enum_::untagged::text with_root::enum_::untagged::unit with_root::f32_ with_root::f64_ with_root::false_ with_root::i128_ with_root::i16_ with_root::i32_ with_root::i64_ with_root::i8_ with_root::isize_ with_root::map with_root::nested_struct with_root::option_some with_root::seq with_root::str_escaped with_root::str_non_escaped with_root::struct_ with_root::text with_root::true_ with_root::u128_ with_root::u16_ with_root::u32_ with_root::u64_ with_root::u8_ with_root::unit with_root::usize_ without_root::char_amp without_root::char_apos without_root::char_gt without_root::char_lt without_root::char_non_escaped without_root::char_quot without_root::char_space without_root::enum_::adjacently_tagged::empty_struct without_root::enum_::adjacently_tagged::flatten_struct without_root::enum_::adjacently_tagged::nested_struct without_root::enum_::adjacently_tagged::newtype without_root::enum_::adjacently_tagged::struct_ without_root::enum_::adjacently_tagged::text without_root::enum_::adjacently_tagged::tuple_struct without_root::enum_::adjacently_tagged::unit without_root::enum_::externally_tagged::nested_struct without_root::enum_::externally_tagged::primitive_unit without_root::enum_::externally_tagged::struct_ without_root::enum_::externally_tagged::text without_root::enum_::internally_tagged::empty_struct without_root::enum_::internally_tagged::flatten_struct without_root::enum_::internally_tagged::nested_struct without_root::enum_::internally_tagged::newtype without_root::enum_::internally_tagged::struct_ without_root::enum_::internally_tagged::text without_root::enum_::internally_tagged::unit without_root::enum_::untagged::flatten_struct without_root::enum_::untagged::nested_struct without_root::enum_::untagged::newtype without_root::enum_::untagged::struct_ without_root::enum_::untagged::text without_root::enum_::untagged::tuple_struct without_root::enum_::untagged::unit without_root::f32_ without_root::f64_ without_root::false_ without_root::flatten_struct without_root::i128_ without_root::i16_ without_root::i32_ without_root::i64_ without_root::i8_ without_root::isize_ without_root::map without_root::nested_struct without_root::seq without_root::str_escaped without_root::str_non_escaped without_root::struct_ without_root::text without_root::true_ without_root::tuple without_root::u128_ without_root::u16_ without_root::u32_ without_root::u64_ without_root::u8_ without_root::unit without_root::usize_
- serialize_bool - duplicate of `without_root::false_` and `without_root::true_` - serialize_struct - duplicate of `without_root::struct_` - serialize_struct_value_number - duplicate of `without_root::value` - serialize_struct_value_string - excess test, duplicate of previous - serialize_enum - duplicate of `without_root::enum_::externally_tagged::newtype` - serialize_a_list - non working test that replaced by `without_root::seq` - test_empty - duplicate of `without_root::empty_struct` - test_nested - duplicate of `without_root::nested_struct` Still 114 failures
failures (40): enum_::adjacently_tagged::flatten_struct::attributes enum_::adjacently_tagged::nested_struct::attributes enum_::adjacently_tagged::newtype::attributes enum_::adjacently_tagged::struct_::attributes enum_::adjacently_tagged::unit::attributes enum_::externally_tagged::flatten_struct::attributes enum_::externally_tagged::nested_struct::attributes enum_::externally_tagged::struct_::attributes enum_::internally_tagged::flatten_struct::attributes enum_::internally_tagged::nested_struct::attributes enum_::internally_tagged::struct_::attributes enum_::internally_tagged::unit::attributes enum_::untagged::flatten_struct::attributes enum_::untagged::nested_struct::attributes flatten_struct::attributes from_str_should_ignore_encoding nested_struct::attributes seq::fixed_name::fixed_size::list_of_struct seq::fixed_name::variable_size::list_of_struct seq::top_level::list_of_struct struct_::attribute_and_element struct_::attributes struct_::excess_attributes xml_schema_lists::attribute::bool_ xml_schema_lists::attribute::byte_buf xml_schema_lists::attribute::char_ xml_schema_lists::attribute::f32_ xml_schema_lists::attribute::f64_ xml_schema_lists::attribute::i128_ xml_schema_lists::attribute::i16_ xml_schema_lists::attribute::i32_ xml_schema_lists::attribute::i64_ xml_schema_lists::attribute::i8_ xml_schema_lists::attribute::string xml_schema_lists::attribute::u128_ xml_schema_lists::attribute::u16_ xml_schema_lists::attribute::u32_ xml_schema_lists::attribute::u64_ xml_schema_lists::attribute::u8_ xml_schema_lists::attribute::unit
What is |
I not exactly understand your question. Could you expand it?
Because this change is a part of future release (which I plan to make this year) you can find docs about it in the local copy after generating: $env:RUSTDOCFLAGS="--cfg docs_rs"; cargo +nightly doc --all-features --open and go to the documentation of the You also can read documentation source here: Line 3 in e877f4f
If anything is incomprehensible, feel free to ask so that we can address ambiguities before release. |
This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [quick-xml](https://github.com/tafia/quick-xml) | dependencies | minor | `0.26.0` -> `0.27.1` | --- ### Release Notes <details> <summary>tafia/quick-xml</summary> ### [`v0.27.1`](https://github.com/tafia/quick-xml/blob/HEAD/Changelog.md#​0271----2022-12-28) [Compare Source](tafia/quick-xml@v0.27.0...v0.27.1) ##### Bug Fixes - [#​530]: Fix an infinite loop leading to unbounded memory consumption that occurs when skipping events on malformed XML with the `overlapped-lists` feature active. - [#​530]: Fix an error in the `Deserializer::read_to_end` when `overlapped-lists` feature is active and malformed XML is parsed [#​530]: tafia/quick-xml#530 ### [`v0.27.0`](https://github.com/tafia/quick-xml/blob/HEAD/Changelog.md#​0270----2022-12-25) [Compare Source](tafia/quick-xml@v0.26.0...v0.27.0) ##### New Features - [#​521]: Implement `Clone` for all error types. This required changing `Error::Io` to contain `Arc<std::io::Error>` instead of `std::io::Error` since `std::io::Error` does not implement `Clone`. ##### Bug Fixes - [#​490]: Ensure that serialization of map keys always produces valid XML names. In particular, that means that maps with numeric and numeric-like keys (for example, `"42"`) no longer can be serialized because [XML name] cannot start from a digit - [#​500]: Fix deserialization of top-level sequences of enums, like ```xml <?xml version="1.0" encoding="UTF-8"?> <!-- list of enum Enum { A, B, С } --> <A/> <B/> <C/> ``` - [#​514]: Fix wrong reporting `Error::EndEventMismatch` after disabling and enabling `.check_end_names` - [#​517]: Fix swapped codes for `\r` and `\n` characters when escaping them - [#​523]: Fix incorrect skipping text and CDATA content before any map-like structures in serde deserializer, like ```xml unwanted text<struct>...</struct> ``` - [#​523]: Fix incorrect handling of `xs:list`s with encoded spaces: they still act as delimiters, which is confirmed also by mature XmlBeans Java library - [#​473]: Fix a hidden requirement to enable serde's `derive` feature to get quick-xml's `serialize` feature for `edition = 2021` or `resolver = 2` crates ##### Misc Changes - [#​490]: Removed `$unflatten=` special prefix for fields for serde (de)serializer, because: - it is useless for deserializer - serializer was rewritten and does not require it anymore This prefix allowed you to serialize struct field as an XML element and now replaced by a more thoughtful system explicitly indicating that a field should be serialized as an attribute by prepending `@` character to its name - [#​490]: Removed `$primitive=` prefix. That prefix allowed you to serialize struct field as an attribute instead of an element and now replaced by a more thoughtful system explicitly indicating that a field should be serialized as an attribute by prepending `@` character to its name - [#​490]: In addition to the `$value` special name for a field a new `$text` special name was added: - `$text` is used if you want to map field to text content only. No markup is expected (but text can represent a list as defined by `xs:list` type) - `$value` is used if you want to map elements with different names to one field, that should be represented either by an `enum`, or by sequence of `enum`s (`Vec`, tuple, etc.), or by string. Use it when you want to map field to any content of the field, text or markup Refer to [documentation] for details. - [#​521]: MSRV bumped to 1.52. - [#​473]: `serde` feature that used to make some types serializable, renamed to `serde-types` - [#​528]: Added documentation for XML to `serde` mapping [#​473]: tafia/quick-xml#473 [#​490]: tafia/quick-xml#490 [#​500]: tafia/quick-xml#500 [#​514]: tafia/quick-xml#514 [#​517]: tafia/quick-xml#517 [#​521]: tafia/quick-xml#521 [#​523]: tafia/quick-xml#523 [#​528]: tafia/quick-xml#528 [XML name]: https://www.w3.org/TR/xml11/#NT-Name [documentation]: https://docs.rs/quick-xml/0.27.0/quick_xml/de/index.html#difference-between-text-and-value-special-names </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNC43My4wIiwidXBkYXRlZEluVmVyIjoiMzQuNzQuMiJ9--> Co-authored-by: cabr2-bot <cabr2.help@gmail.com> Co-authored-by: crapStone <crapstone01@gmail.com> Reviewed-on: https://codeberg.org/Calciumdibromid/CaBr2/pulls/1692 Reviewed-by: crapStone <crapstone@noreply.codeberg.org> Co-authored-by: Calciumdibromid Bot <cabr2_bot@noreply.codeberg.org> Co-committed-by: Calciumdibromid Bot <cabr2_bot@noreply.codeberg.org>
This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [quick-xml](https://github.com/tafia/quick-xml) | dependencies | minor | `0.27.1` -> `0.28.0` | --- ### Release Notes <details> <summary>tafia/quick-xml</summary> ### [`v0.28.0`](https://github.com/tafia/quick-xml/blob/HEAD/Changelog.md#​0280----2023-03-13) [Compare Source](tafia/quick-xml@v0.27.1...v0.28.0) ##### New Features - [#​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` to trim leading and trailing spaces from text events - [#​565]: Allow deserialize special field names `$value` and `$text` into borrowed fields when use serde deserializer - [#​568]: Rename `Writter::inner` into `Writter::get_mut` - [#​568]: Add method `Writter::get_ref` - [#​569]: Rewrite the `Reader::read_event_into_async` as an async fn, making the future `Send` if possible. - [#​571]: Borrow element names (`<element>`) when deserialize with serde. This change allow to deserialize into `HashMap<&str, T>`, for example - [#​573]: Add basic support for async byte writers via tokio's `AsyncWrite`. ##### Bug Fixes - [#​537]: Restore ability to deserialize attributes that represents XML namespace mappings (`xmlns:xxx`) that was broken since [#​490] - [#​510]: Fix an error of deserialization of `Option<T>` fields where `T` is some sequence type (for example, `Vec` or tuple) - [#​540]: Fix a compilation error (probably a rustc bug) in some circumstances. `Serializer::new` and `Serializer::with_root` now accepts only references to `Write`r. - [#​520]: Merge consequent (delimited only by comments and processing instructions) texts and CDATA when deserialize using serde deserializer. `DeEvent::Text` and `DeEvent::CData` events was replaced by `DeEvent::Text` with merged content. The same behavior for the `Reader` does not implemented (yet?) and should be implemented manually - [#​562]: Correctly set minimum required version of memchr dependency to 2.1 - [#​565]: Correctly set minimum required version of tokio dependency to 1.10 - [#​565]: Fix compilation error when build with serde <1.0.139 [externally tagged]: https://serde.rs/enum-representations.html#externally-tagged [#​490]: tafia/quick-xml#490 [#​510]: tafia/quick-xml#510 [#​520]: tafia/quick-xml#520 [#​537]: tafia/quick-xml#537 [#​540]: tafia/quick-xml#540 [#​541]: tafia/quick-xml#541 [#​556]: tafia/quick-xml#556 [#​562]: tafia/quick-xml#562 [#​565]: tafia/quick-xml#565 [#​568]: tafia/quick-xml#568 [#​569]: tafia/quick-xml#569 [#​571]: tafia/quick-xml#571 [#​573]: tafia/quick-xml#573 </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNS42LjAiLCJ1cGRhdGVkSW5WZXIiOiIzNS42LjAifQ==--> Co-authored-by: cabr2-bot <cabr2.help@gmail.com> Co-authored-by: crapStone <crapstone01@gmail.com> Reviewed-on: https://codeberg.org/Calciumdibromid/CaBr2/pulls/1818 Reviewed-by: crapStone <crapstone@noreply.codeberg.org> Co-authored-by: Calciumdibromid Bot <cabr2_bot@noreply.codeberg.org> Co-committed-by: Calciumdibromid Bot <cabr2_bot@noreply.codeberg.org>
This PR rewrites serializer and fixes the following issues:
$primitive=
unit variants doesn't work correctly yet #354 (but it still should be checked that it works aligned with the serializer)Notable changes:
$unflatten=
prefix, as it not used anymore$primitive=
prefix, as it not used anymore$value
special name split into two special names#text
and#any
#content
. @dralley, please check especially, is the documentation clear about the differences?@
character. Without that fields serialized as elements and can be deserialized only from elements. Deserialization from element or from attribute into one field is not possible anymore. It's a weird wish anyway