Skip to content
This repository was archived by the owner on May 30, 2022. It is now read-only.

Commit ee2633b

Browse files
committed
Add map-context dependent deserializer for map values, which fixes negative trivial tests
1 parent cffbdde commit ee2633b

File tree

3 files changed

+355
-112
lines changed

3 files changed

+355
-112
lines changed

Changelog.md

+5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010

1111
## Unreleased
1212

13+
### Bug Fixes
14+
15+
- [#9]: Deserialization erroneously was successful in some cases where error is expected.
16+
This broke deserialization of untagged enums which rely on error if variant cannot be parsed
17+
1318
### Misc Changes
1419

1520
- [#8]: Changes in the error type `DeError`:

src/de/map.rs

+209-9
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22
33
use crate::{
44
de::escape::EscapedDeserializer,
5-
de::{DeEvent, Deserializer, XmlRead, INNER_VALUE, UNFLATTEN_PREFIX},
5+
de::{deserialize_bool, DeEvent, Deserializer, XmlRead, INNER_VALUE, UNFLATTEN_PREFIX},
66
errors::serialize::DeError,
77
events::attributes::IterState,
8-
events::BytesStart,
8+
events::{BytesCData, BytesStart},
9+
reader::Decoder,
910
};
10-
use serde::de::{self, DeserializeSeed, IntoDeserializer};
11+
use serde::de::{self, DeserializeSeed, IntoDeserializer, Visitor};
12+
use serde::serde_if_integer128;
1113
use std::borrow::Cow;
1214
use std::ops::Range;
1315

@@ -25,11 +27,9 @@ enum ValueSource {
2527
/// [`next_key_seed()`]: de::MapAccess::next_key_seed
2628
/// [`next_value_seed()`]: de::MapAccess::next_value_seed
2729
Unknown,
28-
/// `next_key_seed` checked the attributes list and find it is not exhausted yet.
29-
/// Next call to the `next_value_seed` will deserialize type from the attribute value
30+
/// Next value should be deserialized from an attribute value; value is located
31+
/// at specified span.
3032
Attribute(Range<usize>),
31-
/// The same as `Text`
32-
Nested,
3333
/// Value should be deserialized from the text content of the XML node, which
3434
/// represented or by an ordinary text node, or by a CDATA node:
3535
///
@@ -43,6 +43,96 @@ enum ValueSource {
4343
/// </any-tag>
4444
/// ```
4545
Text,
46+
/// Next value should be deserialized from an element with an any name.
47+
/// Corresponding tag name will always be associated with a field with name
48+
/// [`INNER_VALUE`].
49+
///
50+
/// That state is set when call to [`peek()`] returns a [`Start`] event
51+
/// _and_ struct has a field with a special name [`INNER_VALUE`].
52+
///
53+
/// When in this state, next event, returned by [`next()`], will be a [`Start`],
54+
/// which represents both a key, and a value. Value would be deserialized from
55+
/// the whole element and how is will be done determined by the value deserializer.
56+
/// The [`MapAccess`] do not consume any events in that state.
57+
///
58+
/// Because in that state any encountered `<tag>` is mapped to the [`INNER_VALUE`]
59+
/// field, it is possible to use tag name as an enum discriminator, so `enum`s
60+
/// can be deserialized from that XMLs:
61+
///
62+
/// ```xml
63+
/// <any-tag>
64+
/// <variant1>...</variant1>
65+
/// <!-- ~~~~~~~~ - this data will determine that this is Enum::variant1 -->
66+
/// <!--^^^^^^^^^^^^^^^^^^^^^^^ - this data will be used to deserialize a map value -->
67+
/// </any-tag>
68+
/// ```
69+
/// ```xml
70+
/// <any-tag>
71+
/// <variant2>...</variant2>
72+
/// <!-- ~~~~~~~~ - this data will determine that this is Enum::variant2 -->
73+
/// <!--^^^^^^^^^^^^^^^^^^^^^^^ - this data will be used to deserialize a map value -->
74+
/// </any-tag>
75+
/// ```
76+
///
77+
/// both can be deserialized into
78+
///
79+
/// ```ignore
80+
/// enum Enum {
81+
/// variant1,
82+
/// variant2,
83+
/// }
84+
/// struct AnyName {
85+
/// #[serde(rename = "$value")]
86+
/// field: Enum,
87+
/// }
88+
/// ```
89+
///
90+
/// That is possible, because value deserializer have access to the full content
91+
/// of a `<variant1>...</variant1>` or `<variant2>...</variant2>` node, including
92+
/// the tag name.
93+
///
94+
/// Currently, processing of that enum variant is fully equivalent to the
95+
/// processing of a [`Text`] variant. Split of variants made for clarity.
96+
///
97+
/// [`Start`]: DeEvent::Start
98+
/// [`peek()`]: Deserializer::peek()
99+
/// [`next()`]: Deserializer::next()
100+
/// [`Text`]: Self::Text
101+
Content,
102+
/// Next value should be deserialized from an element with a dedicated name.
103+
///
104+
/// That state is set when call to [`peek()`] returns a [`Start`] event, which
105+
/// [`name()`] represents a field name. That name will be deserialized as a key.
106+
///
107+
/// When in this state, next event, returned by [`next()`], will be a [`Start`],
108+
/// which represents both a key, and a value. Value would be deserialized from
109+
/// the whole element and how is will be done determined by the value deserializer.
110+
/// The [`MapAccess`] do not consume any events in that state.
111+
///
112+
/// An illustration below shows, what data is used to deserialize key and value:
113+
/// ```xml
114+
/// <any-tag>
115+
/// <key>...</key>
116+
/// <!-- ~~~ - this data will be used to deserialize a map key -->
117+
/// <!--^^^^^^^^^^^^^^ - this data will be used to deserialize a map value -->
118+
/// </any-tag>
119+
/// ```
120+
///
121+
/// Although value deserializer will have access to the full content of a `<key>`
122+
/// node (including the tag name), it will not get much benefits from that,
123+
/// because tag name will always be fixed for a given map field (equal to a
124+
/// field name). So, if the field type is an `enum`, it cannot select its
125+
/// variant based on the tag name. If that is needed, then [`Content`] variant
126+
/// of this enum should be used. Such usage is enabled by annotating a struct
127+
/// field as "content" field, which implemented as given the field a special
128+
/// [`INNER_VALUE`] name.
129+
///
130+
/// [`Start`]: DeEvent::Start
131+
/// [`peek()`]: Deserializer::peek()
132+
/// [`next()`]: Deserializer::next()
133+
/// [`name()`]: BytesStart::name()
134+
/// [`Content`]: Self::Content
135+
Nested,
46136
}
47137

48138
/// A deserializer for `Attributes`
@@ -141,7 +231,7 @@ where
141231
// TODO: This should be handled by #[serde(flatten)]
142232
// See https://github.com/serde-rs/serde/issues/1905
143233
DeEvent::Start(_) if has_value_field => {
144-
self.source = ValueSource::Text;
234+
self.source = ValueSource::Content;
145235
seed.deserialize(INNER_VALUE.into_deserializer()).map(Some)
146236
}
147237
DeEvent::Start(e) => {
@@ -189,8 +279,118 @@ where
189279
true,
190280
))
191281
}
192-
ValueSource::Nested | ValueSource::Text => seed.deserialize(&mut *self.de),
282+
// This arm processes the following XML shape:
283+
// <any-tag>
284+
// text value
285+
// </any-tag>
286+
// The whole map represented by an `<any-tag>` element, the map key
287+
// is implicit and equals to the `INNER_VALUE` constant, and the value
288+
// is a `Text` or a `CData` event (the value deserializer will see one
289+
// of that events)
290+
ValueSource::Text => seed.deserialize(MapValueDeserializer { map: self }),
291+
// This arm processes the following XML shape:
292+
// <any-tag>
293+
// <any>...</any>
294+
// </any-tag>
295+
// The whole map represented by an `<any-tag>` element, the map key
296+
// is implicit and equals to the `INNER_VALUE` constant, and the value
297+
// is a `Start` event (the value deserializer will see that event)
298+
ValueSource::Content => seed.deserialize(MapValueDeserializer { map: self }),
299+
// This arm processes the following XML shape:
300+
// <any-tag>
301+
// <tag>...</tag>
302+
// </any-tag>
303+
// The whole map represented by an `<any-tag>` element, the map key
304+
// is a `tag`, and the value is a `Start` event (the value deserializer
305+
// will see that event)
306+
ValueSource::Nested => seed.deserialize(&mut *self.de),
193307
ValueSource::Unknown => Err(DeError::KeyNotRead),
194308
}
195309
}
196310
}
311+
312+
////////////////////////////////////////////////////////////////////////////////////////////////////
313+
314+
macro_rules! forward {
315+
(
316+
$deserialize:ident
317+
$(
318+
($($name:ident : $type:ty),*)
319+
)?
320+
) => {
321+
#[inline]
322+
fn $deserialize<V: Visitor<'de>>(
323+
self,
324+
$($($name: $type,)*)?
325+
visitor: V
326+
) -> Result<V::Value, Self::Error> {
327+
self.map.de.$deserialize($($($name,)*)? visitor)
328+
}
329+
};
330+
}
331+
332+
/// A deserializer for a value of map or struct. That deserializer slightly
333+
/// differently processes events for a primitive types and sequences than
334+
/// a [`Deserializer`].
335+
struct MapValueDeserializer<'de, 'a, 'm, R>
336+
where
337+
R: XmlRead<'de>,
338+
{
339+
/// Access to the map that created this deserializer. Gives access to the
340+
/// context, such as list of fields, that current map known about.
341+
map: &'m mut MapAccess<'de, 'a, R>,
342+
}
343+
344+
impl<'de, 'a, 'm, R> MapValueDeserializer<'de, 'a, 'm, R>
345+
where
346+
R: XmlRead<'de>,
347+
{
348+
/// Returns a text event, used inside [`deserialize_primitives!()`]
349+
#[inline]
350+
fn next_text(&mut self, unescape: bool) -> Result<BytesCData<'de>, DeError> {
351+
self.map.de.next_text_impl(unescape, false)
352+
}
353+
354+
/// Returns a decoder, used inside [`deserialize_primitives!()`]
355+
#[inline]
356+
fn decoder(&self) -> Decoder {
357+
self.map.de.reader.decoder()
358+
}
359+
}
360+
361+
impl<'de, 'a, 'm, R> de::Deserializer<'de> for MapValueDeserializer<'de, 'a, 'm, R>
362+
where
363+
R: XmlRead<'de>,
364+
{
365+
type Error = DeError;
366+
367+
deserialize_primitives!(mut);
368+
369+
forward!(deserialize_option);
370+
forward!(deserialize_unit);
371+
forward!(deserialize_unit_struct(name: &'static str));
372+
forward!(deserialize_newtype_struct(name: &'static str));
373+
374+
forward!(deserialize_seq);
375+
forward!(deserialize_tuple(len: usize));
376+
forward!(deserialize_tuple_struct(name: &'static str, len: usize));
377+
378+
forward!(deserialize_map);
379+
forward!(deserialize_struct(
380+
name: &'static str,
381+
fields: &'static [&'static str]
382+
));
383+
384+
forward!(deserialize_enum(
385+
name: &'static str,
386+
variants: &'static [&'static str]
387+
));
388+
389+
forward!(deserialize_any);
390+
forward!(deserialize_ignored_any);
391+
392+
#[inline]
393+
fn is_human_readable(&self) -> bool {
394+
self.map.de.is_human_readable()
395+
}
396+
}

0 commit comments

Comments
 (0)