Coverage Report

Created: 2025-10-31 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/quick-xml-0.37.5/src/se/key.rs
Line
Count
Source
1
use crate::se::SeError;
2
use serde::ser::{Impossible, Serialize, Serializer};
3
use serde::serde_if_integer128;
4
use std::fmt::Write;
5
6
/// A serializer, that ensures, that only plain types can be serialized,
7
/// so result can be used as an XML tag or attribute name.
8
///
9
/// This serializer does not check that name does not contain characters that
10
/// [not allowed] in XML names, because in some cases it should pass names
11
/// that would be filtered on higher level.
12
///
13
/// [not allowed]: https://www.w3.org/TR/xml11/#sec-common-syn
14
pub struct QNameSerializer<W: Write> {
15
    /// Writer to which this serializer writes content
16
    pub writer: W,
17
}
18
19
impl<W: Write> QNameSerializer<W> {
20
    #[inline]
21
0
    fn write_str(&mut self, value: &str) -> Result<(), SeError> {
22
0
        Ok(self.writer.write_str(value)?)
23
0
    }
24
}
25
26
impl<W: Write> Serializer for QNameSerializer<W> {
27
    type Ok = W;
28
    type Error = SeError;
29
30
    type SerializeSeq = Impossible<Self::Ok, Self::Error>;
31
    type SerializeTuple = Impossible<Self::Ok, Self::Error>;
32
    type SerializeTupleStruct = Impossible<Self::Ok, Self::Error>;
33
    type SerializeTupleVariant = Impossible<Self::Ok, Self::Error>;
34
    type SerializeMap = Impossible<Self::Ok, Self::Error>;
35
    type SerializeStruct = Impossible<Self::Ok, Self::Error>;
36
    type SerializeStructVariant = Impossible<Self::Ok, Self::Error>;
37
38
    write_primitive!();
39
40
0
    fn serialize_str(mut self, value: &str) -> Result<Self::Ok, Self::Error> {
41
0
        self.write_str(value)?;
42
0
        Ok(self.writer)
43
0
    }
44
45
    /// Because unit type can be represented only by empty string which is not
46
    /// a valid XML name, serialization of unit returns `Err(Unsupported)`
47
0
    fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
48
0
        Err(SeError::Unsupported(
49
0
            "cannot serialize unit type `()` as an XML tag name".into(),
50
0
        ))
51
0
    }
52
53
    /// Because unit struct can be represented only by empty string which is not
54
    /// a valid XML name, serialization of unit struct returns `Err(Unsupported)`
55
0
    fn serialize_unit_struct(self, name: &'static str) -> Result<Self::Ok, Self::Error> {
56
0
        Err(SeError::Unsupported(
57
0
            format!("cannot serialize unit struct `{}` as an XML tag name", name).into(),
58
0
        ))
59
0
    }
60
61
    /// We cannot store both a variant discriminant and a variant value,
62
    /// so serialization of enum newtype variant returns `Err(Unsupported)`
63
0
    fn serialize_newtype_variant<T: ?Sized + Serialize>(
64
0
        self,
65
0
        name: &'static str,
66
0
        _variant_index: u32,
67
0
        variant: &'static str,
68
0
        _value: &T,
69
0
    ) -> Result<Self::Ok, SeError> {
70
0
        Err(SeError::Unsupported(
71
0
            format!(
72
0
                "cannot serialize enum newtype variant `{}::{}` as an XML tag name",
73
0
                name, variant
74
0
            )
75
0
            .into(),
76
0
        ))
77
0
    }
78
79
0
    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
80
0
        Err(SeError::Unsupported(
81
0
            "cannot serialize sequence as an XML tag name".into(),
82
0
        ))
83
0
    }
84
85
0
    fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
86
0
        Err(SeError::Unsupported(
87
0
            "cannot serialize tuple as an XML tag name".into(),
88
0
        ))
89
0
    }
90
91
0
    fn serialize_tuple_struct(
92
0
        self,
93
0
        name: &'static str,
94
0
        _len: usize,
95
0
    ) -> Result<Self::SerializeTupleStruct, Self::Error> {
96
0
        Err(SeError::Unsupported(
97
0
            format!(
98
0
                "cannot serialize tuple struct `{}` as an XML tag name",
99
0
                name
100
0
            )
101
0
            .into(),
102
0
        ))
103
0
    }
104
105
0
    fn serialize_tuple_variant(
106
0
        self,
107
0
        name: &'static str,
108
0
        _variant_index: u32,
109
0
        variant: &'static str,
110
0
        _len: usize,
111
0
    ) -> Result<Self::SerializeTupleVariant, Self::Error> {
112
0
        Err(SeError::Unsupported(
113
0
            format!(
114
0
                "cannot serialize enum tuple variant `{}::{}` as an XML tag name",
115
0
                name, variant
116
0
            )
117
0
            .into(),
118
0
        ))
119
0
    }
120
121
0
    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
122
0
        Err(SeError::Unsupported(
123
0
            "cannot serialize map as an XML tag name".into(),
124
0
        ))
125
0
    }
126
127
0
    fn serialize_struct(
128
0
        self,
129
0
        name: &'static str,
130
0
        _len: usize,
131
0
    ) -> Result<Self::SerializeStruct, Self::Error> {
132
0
        Err(SeError::Unsupported(
133
0
            format!("cannot serialize struct `{}` as an XML tag name", name).into(),
134
0
        ))
135
0
    }
136
137
0
    fn serialize_struct_variant(
138
0
        self,
139
0
        name: &'static str,
140
0
        _variant_index: u32,
141
0
        variant: &'static str,
142
0
        _len: usize,
143
0
    ) -> Result<Self::SerializeStructVariant, Self::Error> {
144
0
        Err(SeError::Unsupported(
145
0
            format!(
146
0
                "cannot serialize enum struct variant `{}::{}` as an XML tag name",
147
0
                name, variant
148
0
            )
149
0
            .into(),
150
0
        ))
151
0
    }
152
}
153
154
#[cfg(test)]
155
mod tests {
156
    use super::*;
157
    use crate::utils::Bytes;
158
    use pretty_assertions::assert_eq;
159
    use serde::Serialize;
160
    use std::collections::BTreeMap;
161
162
    #[derive(Debug, Serialize, PartialEq)]
163
    struct Unit;
164
165
    #[derive(Debug, Serialize, PartialEq)]
166
    struct Newtype(bool);
167
168
    #[derive(Debug, Serialize, PartialEq)]
169
    struct Tuple(&'static str, usize);
170
171
    #[derive(Debug, Serialize, PartialEq)]
172
    struct Struct {
173
        key: &'static str,
174
        val: usize,
175
    }
176
177
    #[derive(Debug, Serialize, PartialEq)]
178
    enum Enum {
179
        Unit,
180
        #[serde(rename = "<\"&'>")]
181
        UnitEscaped,
182
        Newtype(bool),
183
        Tuple(&'static str, usize),
184
        Struct {
185
            key: &'static str,
186
            val: usize,
187
        },
188
    }
189
190
    /// Checks that given `$data` successfully serialized as `$expected`
191
    macro_rules! serialize_as {
192
        ($name:ident: $data:expr => $expected:literal) => {
193
            #[test]
194
            fn $name() {
195
                let ser = QNameSerializer {
196
                    writer: String::new(),
197
                };
198
199
                let buffer = $data.serialize(ser).unwrap();
200
                assert_eq!(buffer, $expected);
201
            }
202
        };
203
    }
204
205
    /// Checks that attempt to serialize given `$data` results to a
206
    /// serialization error `$kind` with `$reason`
207
    macro_rules! err {
208
        ($name:ident: $data:expr => $kind:ident($reason:literal)) => {
209
            #[test]
210
            fn $name() {
211
                let mut buffer = String::new();
212
                let ser = QNameSerializer {
213
                    writer: &mut buffer,
214
                };
215
216
                match $data.serialize(ser).unwrap_err() {
217
                    SeError::$kind(e) => assert_eq!(e, $reason),
218
                    e => panic!(
219
                        "Expected `Err({}({}))`, but got `{:?}`",
220
                        stringify!($kind),
221
                        $reason,
222
                        e
223
                    ),
224
                }
225
                assert_eq!(buffer, "");
226
            }
227
        };
228
    }
229
230
    serialize_as!(false_: false => "false");
231
    serialize_as!(true_:  true  => "true");
232
233
    serialize_as!(i8_:    -42i8                => "-42");
234
    serialize_as!(i16_:   -4200i16             => "-4200");
235
    serialize_as!(i32_:   -42000000i32         => "-42000000");
236
    serialize_as!(i64_:   -42000000000000i64   => "-42000000000000");
237
    serialize_as!(isize_: -42000000000000isize => "-42000000000000");
238
239
    serialize_as!(u8_:    42u8                => "42");
240
    serialize_as!(u16_:   4200u16             => "4200");
241
    serialize_as!(u32_:   42000000u32         => "42000000");
242
    serialize_as!(u64_:   42000000000000u64   => "42000000000000");
243
    serialize_as!(usize_: 42000000000000usize => "42000000000000");
244
245
    serde_if_integer128! {
246
        serialize_as!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000");
247
        serialize_as!(u128_:  420000000000000000000000000000u128 => "420000000000000000000000000000");
248
    }
249
250
    serialize_as!(f32_: 4.2f32 => "4.2");
251
    serialize_as!(f64_: 4.2f64 => "4.2");
252
253
    serialize_as!(char_non_escaped: 'h' => "h");
254
    serialize_as!(char_lt:   '<' => "<");
255
    serialize_as!(char_gt:   '>' => ">");
256
    serialize_as!(char_amp:  '&' => "&");
257
    serialize_as!(char_apos: '\'' => "'");
258
    serialize_as!(char_quot: '"' => "\"");
259
260
    serialize_as!(str_valid_name: "valid-name" => "valid-name");
261
    serialize_as!(str_space: "string with spaces" => "string with spaces");
262
    serialize_as!(str_lt:   "string<" => "string<");
263
    serialize_as!(str_gt:   "string>" => "string>");
264
    serialize_as!(str_amp:  "string&" => "string&");
265
    serialize_as!(str_apos: "string'" => "string'");
266
    serialize_as!(str_quot: "string\"" => "string\"");
267
268
    err!(bytes: Bytes(b"<\"escaped & bytes'>")
269
        => Unsupported("`serialize_bytes` not supported yet"));
270
271
    serialize_as!(option_none: Option::<&str>::None => "");
272
    serialize_as!(option_some: Some("non-escaped-string") => "non-escaped-string");
273
274
    err!(unit: ()
275
        => Unsupported("cannot serialize unit type `()` as an XML tag name"));
276
    err!(unit_struct: Unit
277
        => Unsupported("cannot serialize unit struct `Unit` as an XML tag name"));
278
279
    serialize_as!(enum_unit: Enum::Unit => "Unit");
280
    serialize_as!(enum_unit_escaped: Enum::UnitEscaped => "<\"&'>");
281
282
    serialize_as!(newtype: Newtype(true) => "true");
283
    err!(enum_newtype: Enum::Newtype(false)
284
        => Unsupported("cannot serialize enum newtype variant `Enum::Newtype` as an XML tag name"));
285
286
    err!(seq: vec![1, 2, 3]
287
        => Unsupported("cannot serialize sequence as an XML tag name"));
288
    err!(tuple: ("<\"&'>", "with\t\r\n spaces", 3usize)
289
        => Unsupported("cannot serialize tuple as an XML tag name"));
290
    err!(tuple_struct: Tuple("first", 42)
291
        => Unsupported("cannot serialize tuple struct `Tuple` as an XML tag name"));
292
    err!(enum_tuple: Enum::Tuple("first", 42)
293
        => Unsupported("cannot serialize enum tuple variant `Enum::Tuple` as an XML tag name"));
294
295
    err!(map: BTreeMap::from([("_1", 2), ("_3", 4)])
296
        => Unsupported("cannot serialize map as an XML tag name"));
297
    err!(struct_: Struct { key: "answer", val: 42 }
298
        => Unsupported("cannot serialize struct `Struct` as an XML tag name"));
299
    err!(enum_struct: Enum::Struct { key: "answer", val: 42 }
300
        => Unsupported("cannot serialize enum struct variant `Enum::Struct` as an XML tag name"));
301
}