quick_xml/de/
attributes.rs

1//! Implementation of the deserializer from attributes
2
3use std::borrow::Cow;
4
5use serde::de::{DeserializeSeed, Deserializer, Error, IntoDeserializer, MapAccess, Visitor};
6use serde::forward_to_deserialize_any;
7
8use crate::de::key::QNameDeserializer;
9use crate::de::SimpleTypeDeserializer;
10use crate::errors::serialize::DeError;
11use crate::events::attributes::Attributes;
12
13impl<'i> Attributes<'i> {
14    /// Converts this iterator into a serde's [`MapAccess`] trait to use with serde.
15    /// The returned object also implements the [`Deserializer`] trait.
16    ///
17    /// # Parameters
18    /// - `prefix`: a prefix of the field names in structs that should be stripped
19    ///   to get the local attribute name. The [`crate::de::Deserializer`] uses `"@"`
20    ///   as a prefix, but [`Self::into_deserializer()`] uses empy string, which mean
21    ///   that we do not strip anything.
22    ///
23    /// # Example
24    /// ```
25    /// # use pretty_assertions::assert_eq;
26    /// use quick_xml::events::BytesStart;
27    /// use serde::Deserialize;
28    /// use serde::de::IntoDeserializer;
29    ///
30    /// #[derive(Debug, PartialEq, Deserialize)]
31    /// struct MyData<'i> {
32    ///     question: &'i str,
33    ///     answer: u32,
34    /// }
35    ///
36    /// #[derive(Debug, PartialEq, Deserialize)]
37    /// struct MyDataPrefixed<'i> {
38    ///     #[serde(rename = "@question")] question: &'i str,
39    ///     #[serde(rename = "@answer")]   answer: u32,
40    /// }
41    ///
42    /// let tag = BytesStart::from_content(
43    ///     "tag
44    ///         question = 'The Ultimate Question of Life, the Universe, and Everything'
45    ///         answer = '42'",
46    ///     3
47    /// );
48    /// // Strip nothing from the field names
49    /// let de = tag.attributes().clone().into_deserializer();
50    /// assert_eq!(
51    ///     MyData::deserialize(de).unwrap(),
52    ///     MyData {
53    ///         question: "The Ultimate Question of Life, the Universe, and Everything",
54    ///         answer: 42,
55    ///     }
56    /// );
57    ///
58    /// // Strip "@" from the field name
59    /// let de = tag.attributes().into_map_access("@");
60    /// assert_eq!(
61    ///     MyDataPrefixed::deserialize(de).unwrap(),
62    ///     MyDataPrefixed {
63    ///         question: "The Ultimate Question of Life, the Universe, and Everything",
64    ///         answer: 42,
65    ///     }
66    /// );
67    /// ```
68    #[inline]
69    pub const fn into_map_access(self, prefix: &'static str) -> AttributesDeserializer<'i> {
70        AttributesDeserializer {
71            iter: self,
72            value: None,
73            prefix,
74            key_buf: String::new(),
75        }
76    }
77}
78
79impl<'de> IntoDeserializer<'de, DeError> for Attributes<'de> {
80    type Deserializer = AttributesDeserializer<'de>;
81
82    #[inline]
83    fn into_deserializer(self) -> Self::Deserializer {
84        self.into_map_access("")
85    }
86}
87
88////////////////////////////////////////////////////////////////////////////////////////////////////
89
90/// A deserializer used to make possible to pack all attributes into a struct.
91/// It is created by [`Attributes::into_map_access`] or [`Attributes::into_deserializer`]
92/// methods.
93///
94/// This deserializer always call [`Visitor::visit_map`] with self as [`MapAccess`].
95///
96/// # Lifetime
97///
98/// `'i` is a lifetime of the original buffer from which attributes were parsed.
99/// In particular, when reader was created from a string, this is lifetime of the
100/// string.
101#[derive(Debug, Clone)]
102pub struct AttributesDeserializer<'i> {
103    iter: Attributes<'i>,
104    /// The value of the attribute, read in last call to `next_key_seed`.
105    value: Option<Cow<'i, [u8]>>,
106    /// This prefix will be stripped from struct fields before match against attribute name.
107    prefix: &'static str,
108    /// Buffer to store attribute name as a field name exposed to serde consumers.
109    /// Keeped in the serializer to avoid many small allocations
110    key_buf: String,
111}
112
113impl<'de> Deserializer<'de> for AttributesDeserializer<'de> {
114    type Error = DeError;
115
116    #[inline]
117    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
118    where
119        V: Visitor<'de>,
120    {
121        visitor.visit_map(self)
122    }
123
124    forward_to_deserialize_any! {
125        bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
126        bytes byte_buf option unit unit_struct newtype_struct seq tuple
127        tuple_struct map struct enum identifier ignored_any
128    }
129}
130
131impl<'de> MapAccess<'de> for AttributesDeserializer<'de> {
132    type Error = DeError;
133
134    fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
135    where
136        K: DeserializeSeed<'de>,
137    {
138        debug_assert_eq!(self.value, None);
139
140        match self.iter.next() {
141            None => Ok(None),
142            Some(Ok(attr)) => {
143                self.value = Some(attr.value);
144                self.key_buf.clear();
145                self.key_buf.push_str(self.prefix);
146                let de =
147                    QNameDeserializer::from_attr(attr.key, self.iter.decoder(), &mut self.key_buf)?;
148                seed.deserialize(de).map(Some)
149            }
150            Some(Err(err)) => Err(Error::custom(err)),
151        }
152    }
153
154    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
155    where
156        V: DeserializeSeed<'de>,
157    {
158        match self.value.take() {
159            Some(value) => {
160                let de =
161                    SimpleTypeDeserializer::from_part(&value, 0..value.len(), self.iter.decoder());
162                seed.deserialize(de)
163            }
164            None => Err(DeError::KeyNotRead),
165        }
166    }
167}