Coverage Report

Created: 2026-11-12 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/quick-xml-0.42.0/src/de/key.rs
Line
Count
Source
1
use crate::de::simple_type::UnitOnly;
2
use crate::errors::serialize::DeError;
3
use crate::events::BytesStart;
4
use crate::name::QName;
5
use crate::utils::CowRef;
6
use serde::de::{DeserializeSeed, Deserializer, EnumAccess, Visitor};
7
use serde::forward_to_deserialize_any;
8
use std::borrow::Cow;
9
10
macro_rules! deserialize_num {
11
    ($method:ident, $visit:ident) => {
12
0
        fn $method<V>(self, visitor: V) -> Result<V::Value, Self::Error>
13
0
        where
14
0
            V: Visitor<'de>,
15
        {
16
0
            match self.name.parse() {
17
0
                Ok(number) => visitor.$visit(number),
18
0
                Err(_) => self.name.deserialize_str(visitor),
19
            }
20
0
        }
Unexecuted instantiation: <quick_xml::de::key::QNameDeserializer as serde_core::de::Deserializer>::deserialize_i8::<_>
Unexecuted instantiation: <quick_xml::de::key::QNameDeserializer as serde_core::de::Deserializer>::deserialize_u8::<_>
Unexecuted instantiation: <quick_xml::de::key::QNameDeserializer as serde_core::de::Deserializer>::deserialize_f32::<_>
Unexecuted instantiation: <quick_xml::de::key::QNameDeserializer as serde_core::de::Deserializer>::deserialize_f64::<_>
Unexecuted instantiation: <quick_xml::de::key::QNameDeserializer as serde_core::de::Deserializer>::deserialize_i16::<_>
Unexecuted instantiation: <quick_xml::de::key::QNameDeserializer as serde_core::de::Deserializer>::deserialize_i32::<_>
Unexecuted instantiation: <quick_xml::de::key::QNameDeserializer as serde_core::de::Deserializer>::deserialize_i64::<_>
Unexecuted instantiation: <quick_xml::de::key::QNameDeserializer as serde_core::de::Deserializer>::deserialize_u16::<_>
Unexecuted instantiation: <quick_xml::de::key::QNameDeserializer as serde_core::de::Deserializer>::deserialize_u32::<_>
Unexecuted instantiation: <quick_xml::de::key::QNameDeserializer as serde_core::de::Deserializer>::deserialize_u64::<_>
Unexecuted instantiation: <quick_xml::de::key::QNameDeserializer as serde_core::de::Deserializer>::deserialize_i128::<_>
Unexecuted instantiation: <quick_xml::de::key::QNameDeserializer as serde_core::de::Deserializer>::deserialize_u128::<_>
21
    };
22
}
23
24
/// Extracts the local name from a qualified name as a string slice.
25
#[inline]
26
0
fn local_name_str<'n>(name: QName<'n>) -> &'n str {
27
0
    name.local_name().into_inner()
28
0
}
29
30
/// A deserializer for xml names of elements and attributes.
31
///
32
/// Used for deserializing values from:
33
/// - attribute names (`<... name="..." ...>`)
34
/// - element names (`<name>...</name>`)
35
///
36
/// Converts a name to an identifier string using the following rules:
37
///
38
/// - if it is an [`attribute`] name, put `@` in front of the identifier
39
/// - if it is a namespace binding (`xmlns` or `xmlns:xxx`) put the decoded name
40
///   to the identifier
41
/// - if it is an attribute in the `xml` namespace, put the decoded name
42
///   to the identifier
43
/// - put the decoded [`local_name()`] of a name to the identifier
44
///
45
/// The final identifier looks like `[@]local_name`, or `@xmlns`, or `@xmlns:binding` or
46
/// `xml:attribute` (where `[]` means optional element).
47
///
48
/// The deserializer also supports deserializing names as other primitive types:
49
/// - numbers
50
/// - booleans
51
/// - unit (`()`) and unit structs
52
/// - unit variants of the enumerations
53
///
54
/// Because `serde` does not define on which side type conversion should be
55
/// performed, and because [`Deserialize`] implementation for that primitives
56
/// in serde does not accept strings, the deserializer will perform conversion
57
/// by itself.
58
///
59
/// The deserializer is able to deserialize unit and unit structs, but any name
60
/// will be converted to the same unit instance. This is asymmetry with a serializer,
61
/// which not able to serialize those types, because empty names are impossible
62
/// in XML.
63
///
64
/// `deserialize_any()` returns the same result as `deserialize_identifier()`.
65
///
66
/// # Lifetimes
67
///
68
/// - `'i`: lifetime of the data that the deserializer borrows from the parsed input
69
/// - `'d`: lifetime of a deserializer that holds a buffer with content of events
70
///
71
/// [`attribute`]: Self::from_attr
72
/// [`local_name()`]: QName::local_name
73
/// [`Deserialize`]: serde::Deserialize
74
pub struct QNameDeserializer<'i, 'd> {
75
    name: CowRef<'i, 'd, str>,
76
}
77
78
impl<'i, 'd> QNameDeserializer<'i, 'd> {
79
    /// Creates deserializer from name of an attribute
80
0
    pub fn from_attr(name: QName<'d>, key_buf: &'d mut String) -> Result<Self, DeError> {
81
        // https://github.com/tafia/quick-xml/issues/537
82
        // Namespace bindings (xmlns:xxx) map to `@xmlns:xxx` instead of `@xxx`
83
0
        if name.as_namespace_binding().is_some() {
84
0
            key_buf.push_str(name.as_ref());
85
0
        } else {
86
            // https://github.com/tafia/quick-xml/issues/841
87
            // we also want to map to the full name for `xml:xxx`, because `xml:xxx` attributes
88
            // can apper only in this literal form, as `xml` prefix cannot be redeclared or unbound
89
0
            let (local, prefix_opt) = name.decompose();
90
0
            if prefix_opt.map_or(false, |prefix| prefix.is_xml()) {
91
0
                key_buf.push_str(name.as_ref());
92
0
            } else {
93
0
                key_buf.push_str(local.as_ref());
94
0
            }
95
        };
96
97
0
        Ok(Self {
98
0
            name: CowRef::Slice(key_buf),
99
0
        })
100
0
    }
101
102
    /// Creates deserializer from name of an element
103
0
    pub fn from_elem(start: &'d BytesStart<'i>) -> Result<Self, DeError> {
104
0
        let local = match start.buf {
105
0
            Cow::Borrowed(b) => CowRef::Input(local_name_str(QName(&b[..start.name_len]))),
106
0
            Cow::Owned(ref o) => CowRef::Slice(local_name_str(QName(&o[..start.name_len]))),
107
        };
108
109
0
        Ok(Self { name: local })
110
0
    }
111
}
112
113
impl<'de, 'd> Deserializer<'de> for QNameDeserializer<'de, 'd> {
114
    type Error = DeError;
115
116
    forward_to_deserialize_any! {
117
        char str string
118
        bytes byte_buf
119
        seq tuple tuple_struct
120
        map struct
121
        ignored_any
122
    }
123
124
    /// According to the <https://www.w3.org/TR/xmlschema11-2/#boolean>,
125
    /// valid boolean representations are only `"true"`, `"false"`, `"1"`,
126
    /// and `"0"`.
127
0
    fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
128
0
    where
129
0
        V: Visitor<'de>,
130
    {
131
0
        self.name.deserialize_bool(visitor)
132
0
    }
133
134
    deserialize_num!(deserialize_i8, visit_i8);
135
    deserialize_num!(deserialize_i16, visit_i16);
136
    deserialize_num!(deserialize_i32, visit_i32);
137
    deserialize_num!(deserialize_i64, visit_i64);
138
139
    deserialize_num!(deserialize_u8, visit_u8);
140
    deserialize_num!(deserialize_u16, visit_u16);
141
    deserialize_num!(deserialize_u32, visit_u32);
142
    deserialize_num!(deserialize_u64, visit_u64);
143
144
    deserialize_num!(deserialize_i128, visit_i128);
145
    deserialize_num!(deserialize_u128, visit_u128);
146
147
    deserialize_num!(deserialize_f32, visit_f32);
148
    deserialize_num!(deserialize_f64, visit_f64);
149
150
    /// Calls [`Visitor::visit_unit`]
151
0
    fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
152
0
    where
153
0
        V: Visitor<'de>,
154
    {
155
0
        visitor.visit_unit()
156
0
    }
157
158
    /// Forwards deserialization to the [`Self::deserialize_unit`]
159
0
    fn deserialize_unit_struct<V>(
160
0
        self,
161
0
        _name: &'static str,
162
0
        visitor: V,
163
0
    ) -> Result<V::Value, Self::Error>
164
0
    where
165
0
        V: Visitor<'de>,
166
    {
167
0
        self.deserialize_unit(visitor)
168
0
    }
169
170
    /// Forwards deserialization to the [`Self::deserialize_identifier`]
171
    #[inline]
172
0
    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
173
0
    where
174
0
        V: Visitor<'de>,
175
    {
176
0
        self.deserialize_identifier(visitor)
177
0
    }
178
179
    /// If `name` is an empty string then calls [`Visitor::visit_none`],
180
    /// otherwise calls [`Visitor::visit_some`] with itself
181
0
    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
182
0
    where
183
0
        V: Visitor<'de>,
184
    {
185
0
        if self.name.is_empty() {
186
0
            visitor.visit_none()
187
        } else {
188
0
            visitor.visit_some(self)
189
        }
190
0
    }
191
192
0
    fn deserialize_newtype_struct<V>(
193
0
        self,
194
0
        _name: &'static str,
195
0
        visitor: V,
196
0
    ) -> Result<V::Value, Self::Error>
197
0
    where
198
0
        V: Visitor<'de>,
199
    {
200
0
        visitor.visit_newtype_struct(self)
201
0
    }
202
203
    /// Calls a [`Visitor::visit_str`] if [`name`] contains only UTF-8
204
    /// compatible encoded characters and represents an element name and
205
    /// a [`Visitor::visit_string`] in all other cases.
206
    ///
207
    /// [`name`]: Self::name
208
0
    fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>
209
0
    where
210
0
        V: Visitor<'de>,
211
    {
212
0
        match self.name {
213
0
            CowRef::Input(name) => visitor.visit_borrowed_str(name),
214
0
            CowRef::Slice(name) => visitor.visit_str(name),
215
0
            CowRef::Owned(name) => visitor.visit_string(name),
216
        }
217
0
    }
218
219
0
    fn deserialize_enum<V>(
220
0
        self,
221
0
        _name: &str,
222
0
        _variants: &'static [&'static str],
223
0
        visitor: V,
224
0
    ) -> Result<V::Value, Self::Error>
225
0
    where
226
0
        V: Visitor<'de>,
227
    {
228
0
        visitor.visit_enum(self)
229
0
    }
230
}
231
232
impl<'de, 'd> EnumAccess<'de> for QNameDeserializer<'de, 'd> {
233
    type Error = DeError;
234
    type Variant = UnitOnly;
235
236
0
    fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
237
0
    where
238
0
        V: DeserializeSeed<'de>,
239
    {
240
0
        let name = seed.deserialize(self)?;
241
0
        Ok((name, UnitOnly))
242
0
    }
243
}
244
245
////////////////////////////////////////////////////////////////////////////////////////////////////
246
247
#[cfg(test)]
248
mod tests {
249
    use super::*;
250
    use crate::se::key::QNameSerializer;
251
    use crate::utils::{ByteBuf, Bytes};
252
    use pretty_assertions::assert_eq;
253
    use serde::de::IgnoredAny;
254
    use serde::{Deserialize, Serialize};
255
    use std::collections::HashMap;
256
257
    #[derive(Debug, Deserialize, Serialize, PartialEq)]
258
    struct Unit;
259
260
    #[derive(Debug, Deserialize, Serialize, PartialEq)]
261
    struct Newtype(String);
262
263
    #[derive(Debug, Deserialize, Serialize, PartialEq)]
264
    struct Tuple((), ());
265
266
    #[derive(Debug, Deserialize, Serialize, PartialEq)]
267
    struct Struct {
268
        key: String,
269
        val: usize,
270
    }
271
272
    #[derive(Debug, Deserialize, Serialize, PartialEq)]
273
    enum Enum {
274
        Unit,
275
        #[serde(rename = "@Attr")]
276
        Attr,
277
        Newtype(String),
278
        Tuple(String, usize),
279
        Struct {
280
            key: String,
281
            val: usize,
282
        },
283
    }
284
285
    #[derive(Debug, Deserialize, PartialEq)]
286
    #[serde(field_identifier)]
287
    enum Id {
288
        Field,
289
    }
290
291
    #[derive(Debug, Deserialize)]
292
    #[serde(transparent)]
293
    struct Any(IgnoredAny);
294
    impl PartialEq for Any {
295
        fn eq(&self, _other: &Any) -> bool {
296
            true
297
        }
298
    }
299
300
    /// Checks that given `$input` successfully deserializing into given `$result`
301
    macro_rules! deserialized_to_only {
302
        ($name:ident: $type:ty = $input:literal => $result:expr) => {
303
            #[test]
304
            fn $name() {
305
                let de = QNameDeserializer {
306
                    name: CowRef::Input($input),
307
                };
308
                let data: $type = Deserialize::deserialize(de).unwrap();
309
310
                assert_eq!(data, $result);
311
            }
312
        };
313
    }
314
315
    /// Checks that given `$input` successfully deserializing into given `$result`
316
    macro_rules! deserialized_to {
317
        ($name:ident: $type:ty = $input:literal => $result:expr) => {
318
            #[test]
319
            fn $name() {
320
                let de = QNameDeserializer {
321
                    name: CowRef::Input($input),
322
                };
323
                let data: $type = Deserialize::deserialize(de).unwrap();
324
325
                assert_eq!(data, $result);
326
327
                // Roundtrip to ensure that serializer corresponds to deserializer
328
                assert_eq!(
329
                    data.serialize(QNameSerializer {
330
                        writer: String::new()
331
                    })
332
                    .unwrap(),
333
                    $input
334
                );
335
            }
336
        };
337
    }
338
339
    /// Checks that attempt to deserialize given `$input` as a `$type` results to a
340
    /// deserialization error `$kind` with `$reason`
341
    macro_rules! err {
342
        ($name:ident: $type:ty = $input:literal => $kind:ident($reason:literal)) => {
343
            #[test]
344
            fn $name() {
345
                let de = QNameDeserializer {
346
                    name: CowRef::Input($input),
347
                };
348
                let err = <$type as Deserialize>::deserialize(de).unwrap_err();
349
350
                match err {
351
                    DeError::$kind(e) => assert_eq!(e, $reason),
352
                    _ => panic!(
353
                        "Expected `Err({}({}))`, but got `{:?}`",
354
                        stringify!($kind),
355
                        $reason,
356
                        err
357
                    ),
358
                }
359
            }
360
        };
361
    }
362
363
    deserialized_to!(false_: bool = "false" => false);
364
    deserialized_to!(true_: bool  = "true" => true);
365
366
    deserialized_to!(i8_:  i8  = "-2" => -2);
367
    deserialized_to!(i16_: i16 = "-2" => -2);
368
    deserialized_to!(i32_: i32 = "-2" => -2);
369
    deserialized_to!(i64_: i64 = "-2" => -2);
370
371
    deserialized_to!(u8_:  u8  = "3" => 3);
372
    deserialized_to!(u16_: u16 = "3" => 3);
373
    deserialized_to!(u32_: u32 = "3" => 3);
374
    deserialized_to!(u64_: u64 = "3" => 3);
375
376
    deserialized_to!(i128_: i128 = "-2" => -2);
377
    deserialized_to!(u128_: u128 = "2" => 2);
378
379
    deserialized_to!(f32_: f32 = "1.23" => 1.23);
380
    deserialized_to!(f64_: f64 = "1.23" => 1.23);
381
382
    deserialized_to!(char_unescaped: char = "h" => 'h');
383
    err!(char_escaped: char = "&lt;"
384
        => Custom("invalid value: string \"&lt;\", expected a character"));
385
386
    deserialized_to!(string: String = "&lt;escaped&#x20;string" => "&lt;escaped&#x20;string");
387
    deserialized_to!(borrowed_str: &str = "name" => "name");
388
389
    err!(byte_buf: ByteBuf = "&lt;escaped&#x20;string"
390
        => Custom("invalid type: string \"&lt;escaped&#x20;string\", expected byte data"));
391
    err!(borrowed_bytes: Bytes = "name"
392
        => Custom("invalid type: string \"name\", expected borrowed bytes"));
393
394
    deserialized_to!(option_none: Option<String> = "" => None);
395
    deserialized_to!(option_some: Option<String> = "name" => Some("name".into()));
396
397
    // Unit structs cannot be represented in some meaningful way, but it meaningful
398
    // to use them as a placeholder when we want to deserialize _something_
399
    deserialized_to_only!(unit: () = "anything" => ());
400
    deserialized_to_only!(unit_struct: Unit = "anything" => Unit);
401
402
    deserialized_to!(newtype: Newtype = "&lt;escaped&#x20;string" => Newtype("&lt;escaped&#x20;string".into()));
403
404
    err!(seq: Vec<()> = "name"
405
        => Custom("invalid type: string \"name\", expected a sequence"));
406
    err!(tuple: ((), ()) = "name"
407
        => Custom("invalid type: string \"name\", expected a tuple of size 2"));
408
    err!(tuple_struct: Tuple = "name"
409
        => Custom("invalid type: string \"name\", expected tuple struct Tuple"));
410
411
    err!(map: HashMap<(), ()> = "name"
412
        => Custom("invalid type: string \"name\", expected a map"));
413
    err!(struct_: Struct = "name"
414
        => Custom("invalid type: string \"name\", expected struct Struct"));
415
416
    deserialized_to!(enum_unit: Enum = "Unit" => Enum::Unit);
417
    deserialized_to!(enum_unit_for_attr: Enum = "@Attr" => Enum::Attr);
418
    err!(enum_newtype: Enum = "Newtype"
419
        => Custom("invalid type: unit value, expected a string"));
420
    err!(enum_tuple: Enum = "Tuple"
421
        => Custom("invalid type: unit value, expected tuple variant Enum::Tuple"));
422
    err!(enum_struct: Enum = "Struct"
423
        => Custom("invalid type: unit value, expected struct variant Enum::Struct"));
424
425
    // Field identifiers cannot be serialized, and IgnoredAny represented _something_
426
    // which is not concrete
427
    deserialized_to_only!(identifier: Id = "Field" => Id::Field);
428
    deserialized_to_only!(ignored_any: Any = "any-name" => Any(IgnoredAny));
429
}