quick_xml/se/
key.rs

1use crate::errors::serialize::DeError;
2use serde::ser::{Impossible, Serialize, Serializer};
3use serde::serde_if_integer128;
4use 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
14pub struct QNameSerializer<W: Write> {
15    /// Writer to which this serializer writes content
16    pub writer: W,
17}
18
19impl<W: Write> QNameSerializer<W> {
20    #[inline]
21    fn write_str(&mut self, value: &str) -> Result<(), DeError> {
22        Ok(self.writer.write_str(value)?)
23    }
24}
25
26impl<W: Write> Serializer for QNameSerializer<W> {
27    type Ok = W;
28    type Error = DeError;
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    fn serialize_str(mut self, value: &str) -> Result<Self::Ok, Self::Error> {
41        self.write_str(value)?;
42        Ok(self.writer)
43    }
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    fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
48        Err(DeError::Unsupported(
49            "cannot serialize unit type `()` as an XML tag name".into(),
50        ))
51    }
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    fn serialize_unit_struct(self, name: &'static str) -> Result<Self::Ok, Self::Error> {
56        Err(DeError::Unsupported(
57            format!("cannot serialize unit struct `{}` as an XML tag name", name).into(),
58        ))
59    }
60
61    /// We cannot store both a variant discriminant and a variant value,
62    /// so serialization of enum newtype variant returns `Err(Unsupported)`
63    fn serialize_newtype_variant<T: ?Sized + Serialize>(
64        self,
65        name: &'static str,
66        _variant_index: u32,
67        variant: &'static str,
68        _value: &T,
69    ) -> Result<Self::Ok, DeError> {
70        Err(DeError::Unsupported(
71            format!(
72                "cannot serialize enum newtype variant `{}::{}` as an XML tag name",
73                name, variant
74            )
75            .into(),
76        ))
77    }
78
79    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
80        Err(DeError::Unsupported(
81            "cannot serialize sequence as an XML tag name".into(),
82        ))
83    }
84
85    fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
86        Err(DeError::Unsupported(
87            "cannot serialize tuple as an XML tag name".into(),
88        ))
89    }
90
91    fn serialize_tuple_struct(
92        self,
93        name: &'static str,
94        _len: usize,
95    ) -> Result<Self::SerializeTupleStruct, Self::Error> {
96        Err(DeError::Unsupported(
97            format!(
98                "cannot serialize tuple struct `{}` as an XML tag name",
99                name
100            )
101            .into(),
102        ))
103    }
104
105    fn serialize_tuple_variant(
106        self,
107        name: &'static str,
108        _variant_index: u32,
109        variant: &'static str,
110        _len: usize,
111    ) -> Result<Self::SerializeTupleVariant, Self::Error> {
112        Err(DeError::Unsupported(
113            format!(
114                "cannot serialize enum tuple variant `{}::{}` as an XML tag name",
115                name, variant
116            )
117            .into(),
118        ))
119    }
120
121    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
122        Err(DeError::Unsupported(
123            "cannot serialize map as an XML tag name".into(),
124        ))
125    }
126
127    fn serialize_struct(
128        self,
129        name: &'static str,
130        _len: usize,
131    ) -> Result<Self::SerializeStruct, Self::Error> {
132        Err(DeError::Unsupported(
133            format!("cannot serialize struct `{}` as an XML tag name", name).into(),
134        ))
135    }
136
137    fn serialize_struct_variant(
138        self,
139        name: &'static str,
140        _variant_index: u32,
141        variant: &'static str,
142        _len: usize,
143    ) -> Result<Self::SerializeStructVariant, Self::Error> {
144        Err(DeError::Unsupported(
145            format!(
146                "cannot serialize enum struct variant `{}::{}` as an XML tag name",
147                name, variant
148            )
149            .into(),
150        ))
151    }
152}
153
154#[cfg(test)]
155mod 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                    DeError::$kind(e) => assert_eq!(e, $reason),
218                    e => panic!(
219                        "Expected `{}({})`, found `{:?}`",
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}