/rust/registry/src/index.crates.io-1949cf8c6b5b557f/quick-xml-0.39.3/src/se/element.rs
Line | Count | Source |
1 | | //! Contains serializer for an XML element |
2 | | |
3 | | use crate::de::{TEXT_KEY, VALUE_KEY}; |
4 | | use crate::se::content::ContentSerializer; |
5 | | use crate::se::key::QNameSerializer; |
6 | | use crate::se::simple_type::{QuoteTarget, SimpleSeq, SimpleTypeSerializer}; |
7 | | use crate::se::text::TextSerializer; |
8 | | use crate::se::{EmptyElementHandling, SeError, WriteResult, XmlName}; |
9 | | use serde::ser::{ |
10 | | Impossible, Serialize, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, |
11 | | SerializeTuple, SerializeTupleStruct, SerializeTupleVariant, Serializer, |
12 | | }; |
13 | | use std::fmt::Write; |
14 | | |
15 | | /// Writes simple type content between [`ElementSerializer::key`] tags. |
16 | | macro_rules! write_primitive { |
17 | | ($method:ident ( $ty:ty )) => { |
18 | 0 | fn $method(self, value: $ty) -> Result<Self::Ok, Self::Error> { |
19 | 0 | self.ser.write_wrapped(self.key, |ser| ser.$method(value)) Unexecuted instantiation: <quick_xml::se::element::ElementSerializer<_> as serde_core::ser::Serializer>::serialize_i8::{closure#0}Unexecuted instantiation: <quick_xml::se::element::ElementSerializer<_> as serde_core::ser::Serializer>::serialize_u8::{closure#0}Unexecuted instantiation: <quick_xml::se::element::ElementSerializer<_> as serde_core::ser::Serializer>::serialize_f32::{closure#0}Unexecuted instantiation: <quick_xml::se::element::ElementSerializer<_> as serde_core::ser::Serializer>::serialize_f64::{closure#0}Unexecuted instantiation: <quick_xml::se::element::ElementSerializer<_> as serde_core::ser::Serializer>::serialize_i16::{closure#0}Unexecuted instantiation: <quick_xml::se::element::ElementSerializer<_> as serde_core::ser::Serializer>::serialize_i32::{closure#0}Unexecuted instantiation: <quick_xml::se::element::ElementSerializer<_> as serde_core::ser::Serializer>::serialize_i64::{closure#0}Unexecuted instantiation: <quick_xml::se::element::ElementSerializer<_> as serde_core::ser::Serializer>::serialize_u16::{closure#0}Unexecuted instantiation: <quick_xml::se::element::ElementSerializer<_> as serde_core::ser::Serializer>::serialize_u32::{closure#0}Unexecuted instantiation: <quick_xml::se::element::ElementSerializer<_> as serde_core::ser::Serializer>::serialize_u64::{closure#0}Unexecuted instantiation: <quick_xml::se::element::ElementSerializer<_> as serde_core::ser::Serializer>::serialize_bool::{closure#0}Unexecuted instantiation: <quick_xml::se::element::ElementSerializer<_> as serde_core::ser::Serializer>::serialize_char::{closure#0}Unexecuted instantiation: <quick_xml::se::element::ElementSerializer<_> as serde_core::ser::Serializer>::serialize_i128::{closure#0}Unexecuted instantiation: <quick_xml::se::element::ElementSerializer<_> as serde_core::ser::Serializer>::serialize_u128::{closure#0}Unexecuted instantiation: <quick_xml::se::element::ElementSerializer<_> as serde_core::ser::Serializer>::serialize_bytes::{closure#0} |
20 | 0 | } Unexecuted instantiation: <quick_xml::se::element::ElementSerializer<_> as serde_core::ser::Serializer>::serialize_i8 Unexecuted instantiation: <quick_xml::se::element::ElementSerializer<_> as serde_core::ser::Serializer>::serialize_u8 Unexecuted instantiation: <quick_xml::se::element::ElementSerializer<_> as serde_core::ser::Serializer>::serialize_f32 Unexecuted instantiation: <quick_xml::se::element::ElementSerializer<_> as serde_core::ser::Serializer>::serialize_f64 Unexecuted instantiation: <quick_xml::se::element::ElementSerializer<_> as serde_core::ser::Serializer>::serialize_i16 Unexecuted instantiation: <quick_xml::se::element::ElementSerializer<_> as serde_core::ser::Serializer>::serialize_i32 Unexecuted instantiation: <quick_xml::se::element::ElementSerializer<_> as serde_core::ser::Serializer>::serialize_i64 Unexecuted instantiation: <quick_xml::se::element::ElementSerializer<_> as serde_core::ser::Serializer>::serialize_u16 Unexecuted instantiation: <quick_xml::se::element::ElementSerializer<_> as serde_core::ser::Serializer>::serialize_u32 Unexecuted instantiation: <quick_xml::se::element::ElementSerializer<_> as serde_core::ser::Serializer>::serialize_u64 Unexecuted instantiation: <quick_xml::se::element::ElementSerializer<_> as serde_core::ser::Serializer>::serialize_bool Unexecuted instantiation: <quick_xml::se::element::ElementSerializer<_> as serde_core::ser::Serializer>::serialize_char Unexecuted instantiation: <quick_xml::se::element::ElementSerializer<_> as serde_core::ser::Serializer>::serialize_i128 Unexecuted instantiation: <quick_xml::se::element::ElementSerializer<_> as serde_core::ser::Serializer>::serialize_u128 Unexecuted instantiation: <quick_xml::se::element::ElementSerializer<_> as serde_core::ser::Serializer>::serialize_bytes |
21 | | }; |
22 | | } |
23 | | |
24 | | //////////////////////////////////////////////////////////////////////////////////////////////////// |
25 | | |
26 | | /// A serializer used to serialize element with specified name. Unlike the [`ContentSerializer`], |
27 | | /// this serializer never uses variant names of enum variants, and because of that |
28 | | /// it is unable to serialize any enum values, except unit variants. |
29 | | /// |
30 | | /// Returns the classification of the last written type. |
31 | | /// |
32 | | /// This serializer is used for an ordinary fields in structs, which are not special |
33 | | /// fields named `$text` ([`TEXT_KEY`]) or `$value` ([`VALUE_KEY`]). `$text` field |
34 | | /// should be serialized using [`SimpleTypeSerializer`] and `$value` field should be |
35 | | /// serialized using [`ContentSerializer`]. |
36 | | /// |
37 | | /// This serializer does the following: |
38 | | /// - numbers converted to a decimal representation and serialized as `<key>value</key>`; |
39 | | /// - booleans serialized ether as `<key>true</key>` or `<key>false</key>`; |
40 | | /// - strings and characters are serialized as `<key>value</key>`. In particular, |
41 | | /// an empty string is serialized as `<key/>`; |
42 | | /// - `None` is serialized as `<key/>`; |
43 | | /// - `Some` and newtypes are serialized as an inner type using the same serializer; |
44 | | /// - units (`()`) and unit structs are serialized as `<key/>`; |
45 | | /// - sequences, tuples and tuple structs are serialized as repeated `<key>` tag. |
46 | | /// In particular, empty sequence is serialized to nothing; |
47 | | /// - structs are serialized as a sequence of fields wrapped in a `<key>` tag. Each |
48 | | /// field is serialized recursively using either `ElementSerializer`, [`ContentSerializer`] |
49 | | /// (`$value` fields), or [`SimpleTypeSerializer`] (`$text` fields). |
50 | | /// In particular, the empty struct is serialized as `<key/>`; |
51 | | /// - maps are serialized as a sequence of entries wrapped in a `<key>` tag. If key is |
52 | | /// serialized to a special name, the same rules as for struct fields are applied. |
53 | | /// In particular, the empty map is serialized as `<key/>`; |
54 | | /// - enums: |
55 | | /// - unit variants are serialized as `<key>variant</key>`; |
56 | | /// - other variants are not supported ([`SeError::Unsupported`] is returned); |
57 | | /// |
58 | | /// Usage of empty tags depends on the [`ContentSerializer::empty_element_handling`] setting. |
59 | | pub struct ElementSerializer<'w, 'k, W: Write> { |
60 | | /// The inner serializer that contains the settings and mostly do the actual work |
61 | | pub ser: ContentSerializer<'w, 'k, W>, |
62 | | /// Tag name used to wrap serialized types except enum variants which uses the variant name |
63 | | pub(super) key: XmlName<'k>, |
64 | | } |
65 | | |
66 | | impl<'w, 'k, W: Write> Serializer for ElementSerializer<'w, 'k, W> { |
67 | | type Ok = WriteResult; |
68 | | type Error = SeError; |
69 | | |
70 | | type SerializeSeq = Self; |
71 | | type SerializeTuple = Self; |
72 | | type SerializeTupleStruct = Self; |
73 | | type SerializeTupleVariant = Impossible<Self::Ok, Self::Error>; |
74 | | type SerializeMap = Map<'w, 'k, W>; |
75 | | type SerializeStruct = Struct<'w, 'k, W>; |
76 | | type SerializeStructVariant = Struct<'w, 'k, W>; |
77 | | |
78 | | write_primitive!(serialize_bool(bool)); |
79 | | |
80 | | write_primitive!(serialize_i8(i8)); |
81 | | write_primitive!(serialize_i16(i16)); |
82 | | write_primitive!(serialize_i32(i32)); |
83 | | write_primitive!(serialize_i64(i64)); |
84 | | |
85 | | write_primitive!(serialize_u8(u8)); |
86 | | write_primitive!(serialize_u16(u16)); |
87 | | write_primitive!(serialize_u32(u32)); |
88 | | write_primitive!(serialize_u64(u64)); |
89 | | |
90 | | write_primitive!(serialize_i128(i128)); |
91 | | write_primitive!(serialize_u128(u128)); |
92 | | |
93 | | write_primitive!(serialize_f32(f32)); |
94 | | write_primitive!(serialize_f64(f64)); |
95 | | |
96 | | write_primitive!(serialize_char(char)); |
97 | | write_primitive!(serialize_bytes(&[u8])); |
98 | | |
99 | 0 | fn serialize_str(self, value: &str) -> Result<Self::Ok, Self::Error> { |
100 | 0 | if value.is_empty() { |
101 | 0 | self.ser.write_empty(self.key) |
102 | | } else { |
103 | 0 | self.ser |
104 | 0 | .write_wrapped(self.key, |ser| ser.serialize_str(value)) |
105 | | } |
106 | 0 | } |
107 | | |
108 | | /// By serde contract we should serialize key of [`None`] values. If someone |
109 | | /// wants to skip the field entirely, he should use |
110 | | /// `#[serde(skip_serializing_if = "Option::is_none")]`. |
111 | | /// |
112 | | /// In XML when we serialize field, we write field name as: |
113 | | /// - element name, or |
114 | | /// - attribute name |
115 | | /// |
116 | | /// and field value as |
117 | | /// - content of the element, or |
118 | | /// - attribute value |
119 | | /// |
120 | | /// So serialization of `None` works the same as [serialization of `()`](#method.serialize_unit) |
121 | 0 | fn serialize_none(self) -> Result<Self::Ok, Self::Error> { |
122 | 0 | self.serialize_unit() |
123 | 0 | } |
124 | | |
125 | 0 | fn serialize_some<T: ?Sized + Serialize>(self, value: &T) -> Result<Self::Ok, Self::Error> { |
126 | 0 | value.serialize(self) |
127 | 0 | } |
128 | | |
129 | 0 | fn serialize_unit(self) -> Result<Self::Ok, Self::Error> { |
130 | 0 | self.ser.write_empty(self.key) |
131 | 0 | } |
132 | | |
133 | 0 | fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> { |
134 | 0 | self.ser.write_empty(self.key) |
135 | 0 | } |
136 | | |
137 | | /// Writes a tag with name [`Self::key`] and content of unit variant inside. |
138 | | /// If variant is a special `$text` value, then empty tag `<key/>` is written. |
139 | | /// Otherwise a `<key>variant</key>` is written. |
140 | 0 | fn serialize_unit_variant( |
141 | 0 | self, |
142 | 0 | name: &'static str, |
143 | 0 | variant_index: u32, |
144 | 0 | variant: &'static str, |
145 | 0 | ) -> Result<Self::Ok, Self::Error> { |
146 | 0 | if variant == TEXT_KEY { |
147 | 0 | self.ser.write_empty(self.key) |
148 | | } else { |
149 | 0 | self.ser.write_wrapped(self.key, |ser| { |
150 | 0 | ser.serialize_unit_variant(name, variant_index, variant) |
151 | 0 | }) |
152 | | } |
153 | 0 | } |
154 | | |
155 | 0 | fn serialize_newtype_struct<T: ?Sized + Serialize>( |
156 | 0 | self, |
157 | 0 | _name: &'static str, |
158 | 0 | value: &T, |
159 | 0 | ) -> Result<Self::Ok, Self::Error> { |
160 | 0 | value.serialize(self) |
161 | 0 | } |
162 | | |
163 | | /// Always returns [`SeError::Unsupported`]. Newtype variants can be serialized |
164 | | /// only in `$value` fields, which is serialized using [`ContentSerializer`]. |
165 | | #[inline] |
166 | 0 | fn serialize_newtype_variant<T: ?Sized + Serialize>( |
167 | 0 | self, |
168 | 0 | name: &'static str, |
169 | 0 | _variant_index: u32, |
170 | 0 | variant: &'static str, |
171 | 0 | _value: &T, |
172 | 0 | ) -> Result<Self::Ok, Self::Error> { |
173 | 0 | Err(SeError::Unsupported( |
174 | 0 | format!( |
175 | 0 | "cannot serialize enum newtype variant `{}::{}`", |
176 | 0 | name, variant |
177 | 0 | ) |
178 | 0 | .into(), |
179 | 0 | )) |
180 | 0 | } |
181 | | |
182 | | #[inline] |
183 | 0 | fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> { |
184 | 0 | Ok(self) |
185 | 0 | } |
186 | | |
187 | | #[inline] |
188 | 0 | fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> { |
189 | 0 | self.serialize_seq(Some(len)) |
190 | 0 | } |
191 | | |
192 | | #[inline] |
193 | 0 | fn serialize_tuple_struct( |
194 | 0 | self, |
195 | 0 | _name: &'static str, |
196 | 0 | len: usize, |
197 | 0 | ) -> Result<Self::SerializeTupleStruct, Self::Error> { |
198 | 0 | self.serialize_tuple(len) |
199 | 0 | } |
200 | | |
201 | | /// Always returns [`SeError::Unsupported`]. Tuple variants can be serialized |
202 | | /// only in `$value` fields, which is serialized using [`ContentSerializer`]. |
203 | | #[inline] |
204 | 0 | fn serialize_tuple_variant( |
205 | 0 | self, |
206 | 0 | name: &'static str, |
207 | 0 | _variant_index: u32, |
208 | 0 | variant: &'static str, |
209 | 0 | _len: usize, |
210 | 0 | ) -> Result<Self::SerializeTupleVariant, Self::Error> { |
211 | 0 | Err(SeError::Unsupported( |
212 | 0 | format!( |
213 | 0 | "cannot serialize enum tuple variant `{}::{}`", |
214 | 0 | name, variant |
215 | 0 | ) |
216 | 0 | .into(), |
217 | 0 | )) |
218 | 0 | } |
219 | | |
220 | 0 | fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> { |
221 | | Ok(Map { |
222 | 0 | ser: self.serialize_struct("", 0)?, |
223 | 0 | key: None, |
224 | | }) |
225 | 0 | } |
226 | | |
227 | | #[inline] |
228 | 0 | fn serialize_struct( |
229 | 0 | mut self, |
230 | 0 | _name: &'static str, |
231 | 0 | _len: usize, |
232 | 0 | ) -> Result<Self::SerializeStruct, Self::Error> { |
233 | 0 | self.ser.write_indent()?; |
234 | 0 | self.ser.indent.increase(); |
235 | | |
236 | 0 | self.ser.writer.write_char('<')?; |
237 | 0 | self.ser.writer.write_str(self.key.0)?; |
238 | 0 | Ok(Struct { |
239 | 0 | ser: self, |
240 | 0 | children: String::new(), |
241 | 0 | write_indent: true, |
242 | 0 | }) |
243 | 0 | } |
244 | | |
245 | | /// Always returns [`SeError::Unsupported`]. Struct variants can be serialized |
246 | | /// only in `$value` fields, which is serialized using [`ContentSerializer`]. |
247 | | #[inline] |
248 | 0 | fn serialize_struct_variant( |
249 | 0 | self, |
250 | 0 | name: &'static str, |
251 | 0 | _variant_index: u32, |
252 | 0 | variant: &'static str, |
253 | 0 | _len: usize, |
254 | 0 | ) -> Result<Self::SerializeStructVariant, Self::Error> { |
255 | 0 | Err(SeError::Unsupported( |
256 | 0 | format!( |
257 | 0 | "cannot serialize enum struct variant `{}::{}`", |
258 | 0 | name, variant |
259 | 0 | ) |
260 | 0 | .into(), |
261 | 0 | )) |
262 | 0 | } |
263 | | } |
264 | | |
265 | | impl<'w, 'k, W: Write> SerializeSeq for ElementSerializer<'w, 'k, W> { |
266 | | type Ok = WriteResult; |
267 | | type Error = SeError; |
268 | | |
269 | 0 | fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error> |
270 | 0 | where |
271 | 0 | T: ?Sized + Serialize, |
272 | | { |
273 | 0 | value.serialize(ElementSerializer { |
274 | 0 | ser: self.ser.new_seq_element_serializer(true), |
275 | 0 | key: self.key, |
276 | 0 | })?; |
277 | | // Write indent for the next element |
278 | 0 | self.ser.write_indent = true; |
279 | 0 | Ok(()) |
280 | 0 | } |
281 | | |
282 | | #[inline] |
283 | 0 | fn end(self) -> Result<Self::Ok, Self::Error> { |
284 | 0 | Ok(WriteResult::Element) |
285 | 0 | } |
286 | | } |
287 | | |
288 | | impl<'w, 'k, W: Write> SerializeTuple for ElementSerializer<'w, 'k, W> { |
289 | | type Ok = WriteResult; |
290 | | type Error = SeError; |
291 | | |
292 | | #[inline] |
293 | 0 | fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error> |
294 | 0 | where |
295 | 0 | T: ?Sized + Serialize, |
296 | | { |
297 | 0 | SerializeSeq::serialize_element(self, value) |
298 | 0 | } |
299 | | |
300 | | #[inline] |
301 | 0 | fn end(self) -> Result<Self::Ok, Self::Error> { |
302 | 0 | SerializeSeq::end(self) |
303 | 0 | } |
304 | | } |
305 | | |
306 | | impl<'w, 'k, W: Write> SerializeTupleStruct for ElementSerializer<'w, 'k, W> { |
307 | | type Ok = WriteResult; |
308 | | type Error = SeError; |
309 | | |
310 | | #[inline] |
311 | 0 | fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error> |
312 | 0 | where |
313 | 0 | T: ?Sized + Serialize, |
314 | | { |
315 | 0 | SerializeSeq::serialize_element(self, value) |
316 | 0 | } |
317 | | |
318 | | #[inline] |
319 | 0 | fn end(self) -> Result<Self::Ok, Self::Error> { |
320 | 0 | SerializeSeq::end(self) |
321 | 0 | } |
322 | | } |
323 | | |
324 | | //////////////////////////////////////////////////////////////////////////////////////////////////// |
325 | | |
326 | | /// A serializer for tuple variants. Tuples can be serialized in two modes: |
327 | | /// - wrapping each tuple field into a tag |
328 | | /// - without wrapping, fields are delimited by a space |
329 | | pub enum Tuple<'w, 'k, W: Write> { |
330 | | /// Serialize each tuple field as an element |
331 | | Element(ElementSerializer<'w, 'k, W>), |
332 | | /// Serialize tuple as an `xs:list`: space-delimited content of fields |
333 | | Text(SimpleSeq<&'w mut W>), |
334 | | } |
335 | | |
336 | | impl<'w, 'k, W: Write> SerializeTupleVariant for Tuple<'w, 'k, W> { |
337 | | type Ok = WriteResult; |
338 | | type Error = SeError; |
339 | | |
340 | | #[inline] |
341 | 0 | fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error> |
342 | 0 | where |
343 | 0 | T: ?Sized + Serialize, |
344 | | { |
345 | 0 | match self { |
346 | 0 | Self::Element(ser) => SerializeTuple::serialize_element(ser, value), |
347 | 0 | Self::Text(ser) => SerializeTuple::serialize_element(ser, value), |
348 | | } |
349 | 0 | } |
350 | | |
351 | | #[inline] |
352 | 0 | fn end(self) -> Result<Self::Ok, Self::Error> { |
353 | 0 | match self { |
354 | 0 | Self::Element(ser) => SerializeTuple::end(ser), |
355 | | // Do not write indent after `$text` fields because it may be interpreted as |
356 | | // part of content when deserialize |
357 | 0 | Self::Text(ser) => SerializeTuple::end(ser).map(|_| WriteResult::SensitiveText), |
358 | | } |
359 | 0 | } |
360 | | } |
361 | | |
362 | | //////////////////////////////////////////////////////////////////////////////////////////////////// |
363 | | |
364 | | /// A serializer for struct variants, which serializes the struct contents inside |
365 | | /// of wrapping tags (`<${tag}>...</${tag}>`). |
366 | | /// |
367 | | /// Returns the classification of the last written type. |
368 | | /// |
369 | | /// Serialization of each field depends on it representation: |
370 | | /// - attributes written directly to the higher serializer |
371 | | /// - elements buffered into internal buffer and at the end written into higher |
372 | | /// serializer |
373 | | pub struct Struct<'w, 'k, W: Write> { |
374 | | ser: ElementSerializer<'w, 'k, W>, |
375 | | /// Buffer to store serialized elements |
376 | | // TODO: Customization point: allow direct writing of elements, but all |
377 | | // attributes should be listed first. Fail, if attribute encountered after |
378 | | // element. Use feature to configure |
379 | | children: String, |
380 | | /// Whether need to write indent after the last written field |
381 | | write_indent: bool, |
382 | | } |
383 | | |
384 | | impl<'w, 'k, W: Write> Struct<'w, 'k, W> { |
385 | | #[inline] |
386 | 0 | fn write_field<T>(&mut self, key: &str, value: &T) -> Result<(), SeError> |
387 | 0 | where |
388 | 0 | T: ?Sized + Serialize, |
389 | | { |
390 | | //TODO: Customization point: allow user to determine if field is attribute or not |
391 | 0 | if let Some(key) = key.strip_prefix('@') { |
392 | 0 | let key = XmlName::try_from(key)?; |
393 | 0 | self.write_attribute(key, value) |
394 | | } else { |
395 | 0 | self.write_element(key, value) |
396 | | } |
397 | 0 | } |
398 | | |
399 | | /// Writes `value` as an attribute |
400 | | #[inline] |
401 | 0 | fn write_attribute<T>(&mut self, key: XmlName, value: &T) -> Result<(), SeError> |
402 | 0 | where |
403 | 0 | T: ?Sized + Serialize, |
404 | | { |
405 | | //TODO: Customization point: each attribute on new line |
406 | 0 | self.ser.ser.writer.write_char(' ')?; |
407 | 0 | self.ser.ser.writer.write_str(key.0)?; |
408 | 0 | self.ser.ser.writer.write_char('=')?; |
409 | | |
410 | | //TODO: Customization point: preferred quote style |
411 | 0 | self.ser.ser.writer.write_char('"')?; |
412 | 0 | value.serialize(SimpleTypeSerializer { |
413 | 0 | writer: &mut self.ser.ser.writer, |
414 | 0 | target: QuoteTarget::DoubleQAttr, |
415 | 0 | level: self.ser.ser.level, |
416 | 0 | })?; |
417 | 0 | self.ser.ser.writer.write_char('"')?; |
418 | | |
419 | 0 | Ok(()) |
420 | 0 | } |
421 | | |
422 | | /// Writes `value` either as a text content, or as an element. |
423 | | /// |
424 | | /// If `key` has a magic value [`TEXT_KEY`], then `value` serialized as a |
425 | | /// [simple type]. |
426 | | /// |
427 | | /// If `key` has a magic value [`VALUE_KEY`], then `value` serialized as a |
428 | | /// [content] without wrapping in tags, otherwise it is wrapped in |
429 | | /// `<${key}>...</${key}>`. |
430 | | /// |
431 | | /// [simple type]: SimpleTypeSerializer |
432 | | /// [content]: ContentSerializer |
433 | 0 | fn write_element<T>(&mut self, key: &str, value: &T) -> Result<(), SeError> |
434 | 0 | where |
435 | 0 | T: ?Sized + Serialize, |
436 | | { |
437 | 0 | let ser = ContentSerializer { |
438 | 0 | writer: &mut self.children, |
439 | 0 | level: self.ser.ser.level, |
440 | 0 | indent: self.ser.ser.indent.borrow(), |
441 | 0 | // If previous field does not require indent, do not write it |
442 | 0 | write_indent: self.write_indent, |
443 | 0 | text_format: self.ser.ser.text_format, |
444 | 0 | allow_primitive: true, |
445 | 0 | empty_element_handling: self.ser.ser.empty_element_handling, |
446 | 0 | }; |
447 | | |
448 | 0 | if key == TEXT_KEY { |
449 | 0 | value.serialize(TextSerializer(ser.into_simple_type_serializer()?))?; |
450 | | // Text was written so we don't need to indent next field |
451 | 0 | self.write_indent = false; |
452 | 0 | } else if key == VALUE_KEY { |
453 | | // If element was written then we need to indent next field unless it is a text field |
454 | 0 | self.write_indent = value.serialize(ser)?.allow_indent(); |
455 | | } else { |
456 | 0 | value.serialize(ElementSerializer { |
457 | 0 | key: XmlName::try_from(key)?, |
458 | 0 | ser, |
459 | 0 | })?; |
460 | | // Element was written so we need to indent next field unless it is a text field |
461 | 0 | self.write_indent = true; |
462 | | } |
463 | 0 | Ok(()) |
464 | 0 | } |
465 | | } |
466 | | |
467 | | impl<'w, 'k, W: Write> SerializeStruct for Struct<'w, 'k, W> { |
468 | | type Ok = WriteResult; |
469 | | type Error = SeError; |
470 | | |
471 | 0 | fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> |
472 | 0 | where |
473 | 0 | T: ?Sized + Serialize, |
474 | | { |
475 | 0 | self.write_field(key, value) |
476 | 0 | } |
477 | | |
478 | 0 | fn end(mut self) -> Result<Self::Ok, Self::Error> { |
479 | 0 | self.ser.ser.indent.decrease(); |
480 | | |
481 | 0 | if self.children.is_empty() { |
482 | 0 | match self.ser.ser.empty_element_handling { |
483 | | EmptyElementHandling::SelfClosed => { |
484 | 0 | self.ser.ser.writer.write_str("/>")?; |
485 | | } |
486 | | EmptyElementHandling::SelfClosedWithSpace => { |
487 | 0 | self.ser.ser.writer.write_str(" />")?; |
488 | | } |
489 | | EmptyElementHandling::Expanded => { |
490 | 0 | self.ser.ser.writer.write_str("></")?; |
491 | 0 | self.ser.ser.writer.write_str(self.ser.key.0)?; |
492 | 0 | self.ser.ser.writer.write_char('>')?; |
493 | | } |
494 | | } |
495 | | } else { |
496 | 0 | self.ser.ser.writer.write_char('>')?; |
497 | 0 | self.ser.ser.writer.write_str(&self.children)?; |
498 | | |
499 | 0 | if self.write_indent { |
500 | 0 | self.ser.ser.indent.write_indent(&mut self.ser.ser.writer)?; |
501 | 0 | } |
502 | | |
503 | 0 | self.ser.ser.writer.write_str("</")?; |
504 | 0 | self.ser.ser.writer.write_str(self.ser.key.0)?; |
505 | 0 | self.ser.ser.writer.write_char('>')?; |
506 | | } |
507 | 0 | Ok(WriteResult::Element) |
508 | 0 | } |
509 | | } |
510 | | |
511 | | impl<'w, 'k, W: Write> SerializeStructVariant for Struct<'w, 'k, W> { |
512 | | type Ok = WriteResult; |
513 | | type Error = SeError; |
514 | | |
515 | | #[inline] |
516 | 0 | fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> |
517 | 0 | where |
518 | 0 | T: ?Sized + Serialize, |
519 | | { |
520 | 0 | SerializeStruct::serialize_field(self, key, value) |
521 | 0 | } |
522 | | |
523 | | #[inline] |
524 | 0 | fn end(self) -> Result<Self::Ok, Self::Error> { |
525 | 0 | SerializeStruct::end(self) |
526 | 0 | } |
527 | | } |
528 | | |
529 | | //////////////////////////////////////////////////////////////////////////////////////////////////// |
530 | | |
531 | | pub struct Map<'w, 'k, W: Write> { |
532 | | ser: Struct<'w, 'k, W>, |
533 | | /// Key, serialized by `QNameSerializer` if consumer uses `serialize_key` + |
534 | | /// `serialize_value` calls instead of `serialize_entry` |
535 | | key: Option<String>, |
536 | | } |
537 | | |
538 | | impl<'w, 'k, W: Write> Map<'w, 'k, W> { |
539 | 0 | fn make_key<T>(&mut self, key: &T) -> Result<String, SeError> |
540 | 0 | where |
541 | 0 | T: ?Sized + Serialize, |
542 | | { |
543 | 0 | key.serialize(QNameSerializer { |
544 | 0 | writer: String::new(), |
545 | 0 | }) |
546 | 0 | } |
547 | | } |
548 | | |
549 | | impl<'w, 'k, W: Write> SerializeMap for Map<'w, 'k, W> { |
550 | | type Ok = WriteResult; |
551 | | type Error = SeError; |
552 | | |
553 | 0 | fn serialize_key<T>(&mut self, key: &T) -> Result<(), Self::Error> |
554 | 0 | where |
555 | 0 | T: ?Sized + Serialize, |
556 | | { |
557 | 0 | if self.key.take().is_some() { |
558 | 0 | return Err(SeError::Custom( |
559 | 0 | "calling `serialize_key` twice without `serialize_value`".to_string(), |
560 | 0 | )); |
561 | 0 | } |
562 | 0 | self.key = Some(self.make_key(key)?); |
563 | 0 | Ok(()) |
564 | 0 | } |
565 | | |
566 | 0 | fn serialize_value<T>(&mut self, value: &T) -> Result<(), Self::Error> |
567 | 0 | where |
568 | 0 | T: ?Sized + Serialize, |
569 | | { |
570 | 0 | if let Some(key) = self.key.take() { |
571 | 0 | return self.ser.write_field(&key, value); |
572 | 0 | } |
573 | 0 | Err(SeError::Custom( |
574 | 0 | "calling `serialize_value` without call of `serialize_key`".to_string(), |
575 | 0 | )) |
576 | 0 | } |
577 | | |
578 | 0 | fn serialize_entry<K, V>(&mut self, key: &K, value: &V) -> Result<(), Self::Error> |
579 | 0 | where |
580 | 0 | K: ?Sized + Serialize, |
581 | 0 | V: ?Sized + Serialize, |
582 | | { |
583 | 0 | let key = self.make_key(key)?; |
584 | 0 | self.ser.write_field(&key, value) |
585 | 0 | } |
586 | | |
587 | 0 | fn end(mut self) -> Result<Self::Ok, Self::Error> { |
588 | 0 | if let Some(key) = self.key.take() { |
589 | 0 | return Err(SeError::Custom(format!( |
590 | 0 | "calling `end` without call of `serialize_value` for key `{key}`" |
591 | 0 | ))); |
592 | 0 | } |
593 | 0 | SerializeStruct::end(self.ser) |
594 | 0 | } |
595 | | } |
596 | | |
597 | | //////////////////////////////////////////////////////////////////////////////////////////////////// |
598 | | |
599 | | #[cfg(test)] |
600 | | mod tests { |
601 | | use super::*; |
602 | | use crate::se::content::tests::*; |
603 | | use crate::se::{Indent, QuoteLevel, TextFormat}; |
604 | | use crate::utils::Bytes; |
605 | | use serde::Serialize; |
606 | | use std::collections::BTreeMap; |
607 | | |
608 | | #[derive(Debug, Serialize, PartialEq)] |
609 | | struct OptionalElements { |
610 | | a: Option<&'static str>, |
611 | | |
612 | | #[serde(skip_serializing_if = "Option::is_none")] |
613 | | b: Option<&'static str>, |
614 | | } |
615 | | #[derive(Debug, Serialize, PartialEq)] |
616 | | struct OptionalAttributes { |
617 | | #[serde(rename = "@a")] |
618 | | a: Option<&'static str>, |
619 | | |
620 | | #[serde(rename = "@b")] |
621 | | #[serde(skip_serializing_if = "Option::is_none")] |
622 | | b: Option<&'static str>, |
623 | | } |
624 | | |
625 | | mod without_indent { |
626 | | use super::*; |
627 | | use crate::se::content::tests::Struct; |
628 | | use pretty_assertions::assert_eq; |
629 | | |
630 | | /// Checks that given `$data` successfully serialized as `$expected` |
631 | | macro_rules! serialize_as { |
632 | | ($name:ident: $data:expr => $expected:expr) => { |
633 | | #[test] |
634 | | fn $name() { |
635 | | let mut buffer = String::new(); |
636 | | let ser = ElementSerializer { |
637 | | ser: ContentSerializer { |
638 | | writer: &mut buffer, |
639 | | level: QuoteLevel::Full, |
640 | | indent: Indent::None, |
641 | | write_indent: false, |
642 | | text_format: TextFormat::Text, |
643 | | allow_primitive: true, |
644 | | empty_element_handling: EmptyElementHandling::SelfClosed, |
645 | | }, |
646 | | key: XmlName("root"), |
647 | | }; |
648 | | |
649 | | let result = $data.serialize(ser).unwrap(); |
650 | | assert_eq!(buffer, $expected); |
651 | | assert_eq!(result, WriteResult::Element); |
652 | | } |
653 | | }; |
654 | | } |
655 | | |
656 | | /// Checks that attempt to serialize given `$data` results to a |
657 | | /// serialization error `$kind` with `$reason` |
658 | | macro_rules! err { |
659 | | ($name:ident: $data:expr => $kind:ident($reason:literal)) => { |
660 | | #[test] |
661 | | fn $name() { |
662 | | let mut buffer = String::new(); |
663 | | let ser = ElementSerializer { |
664 | | ser: ContentSerializer { |
665 | | writer: &mut buffer, |
666 | | level: QuoteLevel::Full, |
667 | | indent: Indent::None, |
668 | | write_indent: false, |
669 | | text_format: TextFormat::Text, |
670 | | allow_primitive: true, |
671 | | empty_element_handling: EmptyElementHandling::SelfClosed, |
672 | | }, |
673 | | key: XmlName("root"), |
674 | | }; |
675 | | |
676 | | match $data.serialize(ser).unwrap_err() { |
677 | | SeError::$kind(e) => assert_eq!(e, $reason), |
678 | | e => panic!( |
679 | | "Expected `Err({}({}))`, but got `{:?}`", |
680 | | stringify!($kind), |
681 | | $reason, |
682 | | e |
683 | | ), |
684 | | } |
685 | | // We can write something before fail |
686 | | // assert_eq!(buffer, ""); |
687 | | } |
688 | | }; |
689 | | } |
690 | | |
691 | | serialize_as!(false_: false => "<root>false</root>"); |
692 | | serialize_as!(true_: true => "<root>true</root>"); |
693 | | |
694 | | serialize_as!(i8_: -42i8 => "<root>-42</root>"); |
695 | | serialize_as!(i16_: -4200i16 => "<root>-4200</root>"); |
696 | | serialize_as!(i32_: -42000000i32 => "<root>-42000000</root>"); |
697 | | serialize_as!(i64_: -42000000000000i64 => "<root>-42000000000000</root>"); |
698 | | serialize_as!(isize_: -42000000isize => "<root>-42000000</root>"); |
699 | | |
700 | | serialize_as!(u8_: 42u8 => "<root>42</root>"); |
701 | | serialize_as!(u16_: 4200u16 => "<root>4200</root>"); |
702 | | serialize_as!(u32_: 42000000u32 => "<root>42000000</root>"); |
703 | | serialize_as!(u64_: 42000000000000u64 => "<root>42000000000000</root>"); |
704 | | serialize_as!(usize_: 42000000usize => "<root>42000000</root>"); |
705 | | |
706 | | serialize_as!(i128_: -420000000000000000000000000000i128 => "<root>-420000000000000000000000000000</root>"); |
707 | | serialize_as!(u128_: 420000000000000000000000000000u128 => "<root>420000000000000000000000000000</root>"); |
708 | | |
709 | | serialize_as!(f32_: 4.2f32 => "<root>4.2</root>"); |
710 | | serialize_as!(f64_: 4.2f64 => "<root>4.2</root>"); |
711 | | |
712 | | serialize_as!(char_non_escaped: 'h' => "<root>h</root>"); |
713 | | serialize_as!(char_lt: '<' => "<root><</root>"); |
714 | | serialize_as!(char_gt: '>' => "<root>></root>"); |
715 | | serialize_as!(char_amp: '&' => "<root>&</root>"); |
716 | | serialize_as!(char_apos: '\'' => "<root>'</root>"); |
717 | | serialize_as!(char_quot: '"' => "<root>"</root>"); |
718 | | |
719 | | serialize_as!(str_non_escaped: "non-escaped string" => "<root>non-escaped string</root>"); |
720 | | serialize_as!(str_escaped: "<\"escaped & string'>" => "<root><"escaped & string'></root>"); |
721 | | |
722 | | err!(bytes: Bytes(b"<\"escaped & bytes'>") => Unsupported("`serialize_bytes` not supported yet")); |
723 | | |
724 | | serialize_as!(option_none: Option::<&str>::None => "<root/>"); |
725 | | serialize_as!(option_some: Some("non-escaped string") => "<root>non-escaped string</root>"); |
726 | | serialize_as!(option_some_empty_str: Some("") => "<root/>"); |
727 | | |
728 | | serialize_as!(unit: () => "<root/>"); |
729 | | serialize_as!(unit_struct: Unit => "<root/>"); |
730 | | serialize_as!(unit_struct_escaped: UnitEscaped => "<root/>"); |
731 | | |
732 | | serialize_as!(enum_unit: Enum::Unit => "<root>Unit</root>"); |
733 | | serialize_as!(enum_unit_escaped: Enum::UnitEscaped => "<root><"&'></root>"); |
734 | | |
735 | | serialize_as!(newtype: Newtype(42) => "<root>42</root>"); |
736 | | err!(enum_newtype: Enum::Newtype(42) |
737 | | => Unsupported("cannot serialize enum newtype variant `Enum::Newtype`")); |
738 | | |
739 | | serialize_as!(seq: vec![1, 2, 3] |
740 | | => "<root>1</root>\ |
741 | | <root>2</root>\ |
742 | | <root>3</root>"); |
743 | | serialize_as!(seq_empty: Vec::<usize>::new() => ""); |
744 | | serialize_as!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize) |
745 | | => "<root><"&'></root>\ |
746 | | <root>with\t\n\r spaces</root>\ |
747 | | <root>3</root>"); |
748 | | serialize_as!(tuple_struct: Tuple("first", 42) |
749 | | => "<root>first</root>\ |
750 | | <root>42</root>"); |
751 | | err!(enum_tuple: Enum::Tuple("first", 42) |
752 | | => Unsupported("cannot serialize enum tuple variant `Enum::Tuple`")); |
753 | | |
754 | | serialize_as!(map: BTreeMap::from([("_1", 2), ("_3", 4)]) |
755 | | => "<root>\ |
756 | | <_1>2</_1>\ |
757 | | <_3>4</_3>\ |
758 | | </root>"); |
759 | | serialize_as!(struct_: Struct { key: "answer", val: (42, 42) } |
760 | | => "<root>\ |
761 | | <key>answer</key>\ |
762 | | <val>42</val>\ |
763 | | <val>42</val>\ |
764 | | </root>"); |
765 | | err!(enum_struct: Enum::Struct { key: "answer", val: (42, 42) } |
766 | | => Unsupported("cannot serialize enum struct variant `Enum::Struct`")); |
767 | | |
768 | | /// Special field name `$text` should be serialized as text content. |
769 | | /// Sequences serialized as an `xs:list` content |
770 | | mod text_field { |
771 | | use super::*; |
772 | | |
773 | | /// `$text` key in a map |
774 | | mod map { |
775 | | use super::*; |
776 | | use pretty_assertions::assert_eq; |
777 | | |
778 | | macro_rules! text { |
779 | | ($name:ident: $data:expr) => { |
780 | | serialize_as!($name: |
781 | | BTreeMap::from([("$text", $data)]) |
782 | | => "<root/>"); |
783 | | }; |
784 | | ($name:ident: $data:expr => $expected:literal) => { |
785 | | serialize_as!($name: |
786 | | BTreeMap::from([("$text", $data)]) |
787 | | => concat!("<root>", $expected,"</root>")); |
788 | | }; |
789 | | } |
790 | | |
791 | | text!(false_: false => "false"); |
792 | | text!(true_: true => "true"); |
793 | | |
794 | | text!(i8_: -42i8 => "-42"); |
795 | | text!(i16_: -4200i16 => "-4200"); |
796 | | text!(i32_: -42000000i32 => "-42000000"); |
797 | | text!(i64_: -42000000000000i64 => "-42000000000000"); |
798 | | text!(isize_: -42000000isize => "-42000000"); |
799 | | |
800 | | text!(u8_: 42u8 => "42"); |
801 | | text!(u16_: 4200u16 => "4200"); |
802 | | text!(u32_: 42000000u32 => "42000000"); |
803 | | text!(u64_: 42000000000000u64 => "42000000000000"); |
804 | | text!(usize_: 42000000usize => "42000000"); |
805 | | |
806 | | text!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000"); |
807 | | text!(u128_: 420000000000000000000000000000u128 => "420000000000000000000000000000"); |
808 | | |
809 | | text!(f32_: 4.2f32 => "4.2"); |
810 | | text!(f64_: 4.2f64 => "4.2"); |
811 | | |
812 | | text!(char_non_escaped: 'h' => "h"); |
813 | | text!(char_lt: '<' => "<"); |
814 | | text!(char_gt: '>' => ">"); |
815 | | text!(char_amp: '&' => "&"); |
816 | | text!(char_apos: '\'' => "'"); |
817 | | text!(char_quot: '"' => """); |
818 | | text!(char_space: ' ' => " "); |
819 | | |
820 | | text!(str_non_escaped: "non-escaped string" => "non-escaped string"); |
821 | | text!(str_escaped: "<\"escaped & string'>" => "<"escaped & string'>"); |
822 | | |
823 | | err!(bytes: |
824 | | Text { |
825 | | before: "answer", |
826 | | content: Bytes(b"<\"escaped & bytes'>"), |
827 | | after: "answer", |
828 | | } |
829 | | => Unsupported("`serialize_bytes` not supported yet")); |
830 | | |
831 | | text!(option_none: Option::<&str>::None); |
832 | | text!(option_some: Some("non-escaped string") => "non-escaped string"); |
833 | | text!(option_some_empty_str: Some("")); |
834 | | |
835 | | text!(unit: ()); |
836 | | text!(unit_struct: Unit); |
837 | | text!(unit_struct_escaped: UnitEscaped); |
838 | | |
839 | | text!(enum_unit: Enum::Unit => "Unit"); |
840 | | text!(enum_unit_escaped: Enum::UnitEscaped => "<"&'>"); |
841 | | |
842 | | text!(newtype: Newtype(42) => "42"); |
843 | | // We have no space where name of a variant can be stored |
844 | | err!(enum_newtype: |
845 | | Text { |
846 | | before: "answer", |
847 | | content: Enum::Newtype(42), |
848 | | after: "answer", |
849 | | } |
850 | | => Unsupported("cannot serialize enum newtype variant `Enum::Newtype` as text content value")); |
851 | | |
852 | | // Sequences are serialized separated by spaces, all spaces inside are escaped |
853 | | text!(seq: vec![1, 2, 3] => "1 2 3"); |
854 | | text!(seq_empty: Vec::<usize>::new()); |
855 | | text!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize) |
856 | | => "<"&'> \ |
857 | | with	  spaces \ |
858 | | 3"); |
859 | | text!(tuple_struct: Tuple("first", 42) => "first 42"); |
860 | | // We have no space where name of a variant can be stored |
861 | | err!(enum_tuple: |
862 | | Text { |
863 | | before: "answer", |
864 | | content: Enum::Tuple("first", 42), |
865 | | after: "answer", |
866 | | } |
867 | | => Unsupported("cannot serialize enum tuple variant `Enum::Tuple` as text content value")); |
868 | | |
869 | | // Complex types cannot be serialized in `$text` field |
870 | | err!(map: |
871 | | Text { |
872 | | before: "answer", |
873 | | content: BTreeMap::from([("_1", 2), ("_3", 4)]), |
874 | | after: "answer", |
875 | | } |
876 | | => Unsupported("cannot serialize map as text content value")); |
877 | | err!(struct_: |
878 | | Text { |
879 | | before: "answer", |
880 | | content: Struct { key: "answer", val: (42, 42) }, |
881 | | after: "answer", |
882 | | } |
883 | | => Unsupported("cannot serialize struct `Struct` as text content value")); |
884 | | err!(enum_struct: |
885 | | Text { |
886 | | before: "answer", |
887 | | content: Enum::Struct { key: "answer", val: (42, 42) }, |
888 | | after: "answer", |
889 | | } |
890 | | => Unsupported("cannot serialize enum struct variant `Enum::Struct` as text content value")); |
891 | | } |
892 | | |
893 | | /// `$text` field inside a struct |
894 | | mod struct_ { |
895 | | use super::*; |
896 | | use pretty_assertions::assert_eq; |
897 | | |
898 | | macro_rules! text { |
899 | | ($name:ident: $data:expr => $expected:literal) => { |
900 | | serialize_as!($name: |
901 | | Text { |
902 | | before: "answer", |
903 | | content: $data, |
904 | | after: "answer", |
905 | | } |
906 | | => concat!( |
907 | | "<root><before>answer</before>", |
908 | | $expected, |
909 | | "<after>answer</after></root>", |
910 | | )); |
911 | | }; |
912 | | } |
913 | | |
914 | | text!(false_: false => "false"); |
915 | | text!(true_: true => "true"); |
916 | | |
917 | | text!(i8_: -42i8 => "-42"); |
918 | | text!(i16_: -4200i16 => "-4200"); |
919 | | text!(i32_: -42000000i32 => "-42000000"); |
920 | | text!(i64_: -42000000000000i64 => "-42000000000000"); |
921 | | text!(isize_: -42000000isize => "-42000000"); |
922 | | |
923 | | text!(u8_: 42u8 => "42"); |
924 | | text!(u16_: 4200u16 => "4200"); |
925 | | text!(u32_: 42000000u32 => "42000000"); |
926 | | text!(u64_: 42000000000000u64 => "42000000000000"); |
927 | | text!(usize_: 42000000usize => "42000000"); |
928 | | |
929 | | text!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000"); |
930 | | text!(u128_: 420000000000000000000000000000u128 => "420000000000000000000000000000"); |
931 | | |
932 | | text!(f32_: 4.2f32 => "4.2"); |
933 | | text!(f64_: 4.2f64 => "4.2"); |
934 | | |
935 | | text!(char_non_escaped: 'h' => "h"); |
936 | | text!(char_lt: '<' => "<"); |
937 | | text!(char_gt: '>' => ">"); |
938 | | text!(char_amp: '&' => "&"); |
939 | | text!(char_apos: '\'' => "'"); |
940 | | text!(char_quot: '"' => """); |
941 | | text!(char_space: ' ' => " "); |
942 | | |
943 | | text!(str_non_escaped: "non-escaped string" => "non-escaped string"); |
944 | | text!(str_escaped: "<\"escaped & string'>" => "<"escaped & string'>"); |
945 | | |
946 | | err!(bytes: |
947 | | Text { |
948 | | before: "answer", |
949 | | content: Bytes(b"<\"escaped & bytes'>"), |
950 | | after: "answer", |
951 | | } |
952 | | => Unsupported("`serialize_bytes` not supported yet")); |
953 | | |
954 | | text!(option_none: Option::<&str>::None => ""); |
955 | | text!(option_some: Some("non-escaped string") => "non-escaped string"); |
956 | | text!(option_some_empty_str: Some("") => ""); |
957 | | |
958 | | text!(unit: () => ""); |
959 | | text!(unit_struct: Unit => ""); |
960 | | text!(unit_struct_escaped: UnitEscaped => ""); |
961 | | |
962 | | text!(enum_unit: Enum::Unit => "Unit"); |
963 | | text!(enum_unit_escaped: Enum::UnitEscaped => "<"&'>"); |
964 | | |
965 | | text!(newtype: Newtype(42) => "42"); |
966 | | // We have no space where name of a variant can be stored |
967 | | err!(enum_newtype: |
968 | | Text { |
969 | | before: "answer", |
970 | | content: Enum::Newtype(42), |
971 | | after: "answer", |
972 | | } |
973 | | => Unsupported("cannot serialize enum newtype variant `Enum::Newtype` as text content value")); |
974 | | |
975 | | // Sequences are serialized separated by spaces, all spaces inside are escaped |
976 | | text!(seq: vec![1, 2, 3] => "1 2 3"); |
977 | | text!(seq_empty: Vec::<usize>::new() => ""); |
978 | | text!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize) |
979 | | => "<"&'> \ |
980 | | with	  spaces \ |
981 | | 3"); |
982 | | text!(tuple_struct: Tuple("first", 42) => "first 42"); |
983 | | // We have no space where name of a variant can be stored |
984 | | err!(enum_tuple: |
985 | | Text { |
986 | | before: "answer", |
987 | | content: Enum::Tuple("first", 42), |
988 | | after: "answer", |
989 | | } |
990 | | => Unsupported("cannot serialize enum tuple variant `Enum::Tuple` as text content value")); |
991 | | |
992 | | // Complex types cannot be serialized in `$text` field |
993 | | err!(map: |
994 | | Text { |
995 | | before: "answer", |
996 | | content: BTreeMap::from([("_1", 2), ("_3", 4)]), |
997 | | after: "answer", |
998 | | } |
999 | | => Unsupported("cannot serialize map as text content value")); |
1000 | | err!(struct_: |
1001 | | Text { |
1002 | | before: "answer", |
1003 | | content: Struct { key: "answer", val: (42, 42) }, |
1004 | | after: "answer", |
1005 | | } |
1006 | | => Unsupported("cannot serialize struct `Struct` as text content value")); |
1007 | | err!(enum_struct: |
1008 | | Text { |
1009 | | before: "answer", |
1010 | | content: Enum::Struct { key: "answer", val: (42, 42) }, |
1011 | | after: "answer", |
1012 | | } |
1013 | | => Unsupported("cannot serialize enum struct variant `Enum::Struct` as text content value")); |
1014 | | } |
1015 | | } |
1016 | | |
1017 | | /// Special field name `$value` should be serialized using name, provided |
1018 | | /// by the type of value instead of a key. Sequences serialized as a list |
1019 | | /// of tags with that name (each element can have their own name) |
1020 | | mod value_field { |
1021 | | use super::*; |
1022 | | |
1023 | | /// `$value` key in a map |
1024 | | mod map { |
1025 | | use super::*; |
1026 | | use pretty_assertions::assert_eq; |
1027 | | |
1028 | | macro_rules! value { |
1029 | | ($name:ident: $data:expr) => { |
1030 | | serialize_as!($name: |
1031 | | BTreeMap::from([("$value", $data)]) |
1032 | | => "<root/>"); |
1033 | | }; |
1034 | | ($name:ident: $data:expr => $expected:literal) => { |
1035 | | serialize_as!($name: |
1036 | | BTreeMap::from([("$value", $data)]) |
1037 | | => concat!("<root>", $expected,"</root>")); |
1038 | | }; |
1039 | | } |
1040 | | |
1041 | | value!(false_: false => "false"); |
1042 | | value!(true_: true => "true"); |
1043 | | |
1044 | | value!(i8_: -42i8 => "-42"); |
1045 | | value!(i16_: -4200i16 => "-4200"); |
1046 | | value!(i32_: -42000000i32 => "-42000000"); |
1047 | | value!(i64_: -42000000000000i64 => "-42000000000000"); |
1048 | | value!(isize_: -42000000isize => "-42000000"); |
1049 | | |
1050 | | value!(u8_: 42u8 => "42"); |
1051 | | value!(u16_: 4200u16 => "4200"); |
1052 | | value!(u32_: 42000000u32 => "42000000"); |
1053 | | value!(u64_: 42000000000000u64 => "42000000000000"); |
1054 | | value!(usize_: 42000000usize => "42000000"); |
1055 | | |
1056 | | value!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000"); |
1057 | | value!(u128_: 420000000000000000000000000000u128 => "420000000000000000000000000000"); |
1058 | | |
1059 | | value!(f32_: 4.2f32 => "4.2"); |
1060 | | value!(f64_: 4.2f64 => "4.2"); |
1061 | | |
1062 | | value!(char_non_escaped: 'h' => "h"); |
1063 | | value!(char_lt: '<' => "<"); |
1064 | | value!(char_gt: '>' => ">"); |
1065 | | value!(char_amp: '&' => "&"); |
1066 | | value!(char_apos: '\'' => "'"); |
1067 | | value!(char_quot: '"' => """); |
1068 | | value!(char_space: ' ' => " "); |
1069 | | |
1070 | | value!(str_non_escaped: "non-escaped string" => "non-escaped string"); |
1071 | | value!(str_escaped: "<\"escaped & string'>" => "<"escaped & string'>"); |
1072 | | |
1073 | | err!(bytes: |
1074 | | BTreeMap::from([("$value", Bytes(b"<\"escaped & bytes'>"))]) |
1075 | | => Unsupported("`serialize_bytes` not supported yet")); |
1076 | | |
1077 | | value!(option_none: Option::<&str>::None); |
1078 | | value!(option_some: Some("non-escaped string") => "non-escaped string"); |
1079 | | value!(option_some_empty_str: Some("")); |
1080 | | |
1081 | | value!(unit: ()); |
1082 | | value!(unit_struct: Unit); |
1083 | | value!(unit_struct_escaped: UnitEscaped); |
1084 | | |
1085 | | value!(enum_unit: Enum::Unit => "<Unit/>"); |
1086 | | err!(enum_unit_escaped: |
1087 | | BTreeMap::from([("$value", Enum::UnitEscaped)]) |
1088 | | => Unsupported("character `<` is not allowed at the start of an XML name `<\"&'>`")); |
1089 | | |
1090 | | value!(newtype: Newtype(42) => "42"); |
1091 | | value!(enum_newtype: Enum::Newtype(42) => "<Newtype>42</Newtype>"); |
1092 | | |
1093 | | // Note that sequences of primitives serialized without delimiters! |
1094 | | err!(seq: |
1095 | | BTreeMap::from([("$value", vec![1, 2, 3])]) |
1096 | | => Unsupported("consequent primitives would be serialized without delimiter and cannot be deserialized back")); |
1097 | | value!(seq_empty: Vec::<usize>::new()); |
1098 | | err!(tuple: |
1099 | | BTreeMap::from([("$value", ("<\"&'>", "with\t\n\r spaces", 3usize))]) |
1100 | | => Unsupported("consequent primitives would be serialized without delimiter and cannot be deserialized back")); |
1101 | | err!(tuple_struct: |
1102 | | BTreeMap::from([("$value", Tuple("first", 42))]) |
1103 | | => Unsupported("consequent primitives would be serialized without delimiter and cannot be deserialized back")); |
1104 | | value!(enum_tuple: Enum::Tuple("first", 42) |
1105 | | => "<Tuple>first</Tuple>\ |
1106 | | <Tuple>42</Tuple>"); |
1107 | | |
1108 | | // We cannot wrap map in any container and should not |
1109 | | // flatten it, so it is impossible to serialize maps |
1110 | | err!(map: |
1111 | | BTreeMap::from([("$value", BTreeMap::from([("_1", 2), ("_3", 4)]))]) |
1112 | | => Unsupported("serialization of map types is not supported in `$value` field")); |
1113 | | value!(struct_: |
1114 | | Struct { key: "answer", val: (42, 42) } |
1115 | | => "<Struct>\ |
1116 | | <key>answer</key>\ |
1117 | | <val>42</val>\ |
1118 | | <val>42</val>\ |
1119 | | </Struct>"); |
1120 | | value!(enum_struct: |
1121 | | Enum::Struct { key: "answer", val: (42, 42) } |
1122 | | => "<Struct>\ |
1123 | | <key>answer</key>\ |
1124 | | <val>42</val>\ |
1125 | | <val>42</val>\ |
1126 | | </Struct>"); |
1127 | | } |
1128 | | |
1129 | | /// `$value` field inside a struct |
1130 | | mod struct_ { |
1131 | | use super::*; |
1132 | | use pretty_assertions::assert_eq; |
1133 | | |
1134 | | macro_rules! value { |
1135 | | ($name:ident: $data:expr => $expected:literal) => { |
1136 | | serialize_as!($name: |
1137 | | Value { |
1138 | | before: "answer", |
1139 | | content: $data, |
1140 | | after: "answer", |
1141 | | } |
1142 | | => concat!( |
1143 | | "<root><before>answer</before>", |
1144 | | $expected, |
1145 | | "<after>answer</after></root>", |
1146 | | )); |
1147 | | }; |
1148 | | } |
1149 | | |
1150 | | value!(false_: false => "false"); |
1151 | | value!(true_: true => "true"); |
1152 | | |
1153 | | value!(i8_: -42i8 => "-42"); |
1154 | | value!(i16_: -4200i16 => "-4200"); |
1155 | | value!(i32_: -42000000i32 => "-42000000"); |
1156 | | value!(i64_: -42000000000000i64 => "-42000000000000"); |
1157 | | value!(isize_: -42000000isize => "-42000000"); |
1158 | | |
1159 | | value!(u8_: 42u8 => "42"); |
1160 | | value!(u16_: 4200u16 => "4200"); |
1161 | | value!(u32_: 42000000u32 => "42000000"); |
1162 | | value!(u64_: 42000000000000u64 => "42000000000000"); |
1163 | | value!(usize_: 42000000usize => "42000000"); |
1164 | | |
1165 | | value!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000"); |
1166 | | value!(u128_: 420000000000000000000000000000u128 => "420000000000000000000000000000"); |
1167 | | |
1168 | | value!(f32_: 4.2f32 => "4.2"); |
1169 | | value!(f64_: 4.2f64 => "4.2"); |
1170 | | |
1171 | | value!(char_non_escaped: 'h' => "h"); |
1172 | | value!(char_lt: '<' => "<"); |
1173 | | value!(char_gt: '>' => ">"); |
1174 | | value!(char_amp: '&' => "&"); |
1175 | | value!(char_apos: '\'' => "'"); |
1176 | | value!(char_quot: '"' => """); |
1177 | | value!(char_space: ' ' => " "); |
1178 | | |
1179 | | value!(str_non_escaped: "non-escaped string" => "non-escaped string"); |
1180 | | value!(str_escaped: "<\"escaped & string'>" => "<"escaped & string'>"); |
1181 | | |
1182 | | err!(bytes: |
1183 | | Value { |
1184 | | before: "answer", |
1185 | | content: Bytes(b"<\"escaped & bytes'>"), |
1186 | | after: "answer", |
1187 | | } |
1188 | | => Unsupported("`serialize_bytes` not supported yet")); |
1189 | | |
1190 | | value!(option_none: Option::<&str>::None => ""); |
1191 | | value!(option_some: Some("non-escaped string") => "non-escaped string"); |
1192 | | value!(option_some_empty_str: Some("") => ""); |
1193 | | |
1194 | | value!(unit: () => ""); |
1195 | | value!(unit_struct: Unit => ""); |
1196 | | value!(unit_struct_escaped: UnitEscaped => ""); |
1197 | | |
1198 | | value!(enum_unit: Enum::Unit => "<Unit/>"); |
1199 | | err!(enum_unit_escaped: |
1200 | | Value { |
1201 | | before: "answer", |
1202 | | content: Enum::UnitEscaped, |
1203 | | after: "answer", |
1204 | | } |
1205 | | => Unsupported("character `<` is not allowed at the start of an XML name `<\"&'>`")); |
1206 | | |
1207 | | value!(newtype: Newtype(42) => "42"); |
1208 | | value!(enum_newtype: Enum::Newtype(42) => "<Newtype>42</Newtype>"); |
1209 | | |
1210 | | // Note that sequences of primitives serialized without delimiters! |
1211 | | err!(seq: |
1212 | | Value { |
1213 | | before: "answer", |
1214 | | content: vec![1, 2, 3], |
1215 | | after: "answer", |
1216 | | } |
1217 | | => Unsupported("consequent primitives would be serialized without delimiter and cannot be deserialized back")); |
1218 | | value!(seq_empty: Vec::<usize>::new() => ""); |
1219 | | err!(tuple: |
1220 | | Value { |
1221 | | before: "answer", |
1222 | | content: ("<\"&'>", "with\t\n\r spaces", 3usize), |
1223 | | after: "answer", |
1224 | | } |
1225 | | => Unsupported("consequent primitives would be serialized without delimiter and cannot be deserialized back")); |
1226 | | err!(tuple_struct: |
1227 | | Value { |
1228 | | before: "answer", |
1229 | | content: Tuple("first", 42), |
1230 | | after: "answer", |
1231 | | } |
1232 | | => Unsupported("consequent primitives would be serialized without delimiter and cannot be deserialized back")); |
1233 | | value!(enum_tuple: Enum::Tuple("first", 42) |
1234 | | => "<Tuple>first</Tuple>\ |
1235 | | <Tuple>42</Tuple>"); |
1236 | | |
1237 | | // We cannot wrap map in any container and should not |
1238 | | // flatten it, so it is impossible to serialize maps |
1239 | | err!(map: |
1240 | | Value { |
1241 | | before: "answer", |
1242 | | content: BTreeMap::from([("_1", 2), ("_3", 4)]), |
1243 | | after: "answer", |
1244 | | } |
1245 | | => Unsupported("serialization of map types is not supported in `$value` field")); |
1246 | | value!(struct_: |
1247 | | Struct { key: "answer", val: (42, 42) } |
1248 | | => "<Struct>\ |
1249 | | <key>answer</key>\ |
1250 | | <val>42</val>\ |
1251 | | <val>42</val>\ |
1252 | | </Struct>"); |
1253 | | value!(enum_struct: |
1254 | | Enum::Struct { key: "answer", val: (42, 42) } |
1255 | | => "<Struct>\ |
1256 | | <key>answer</key>\ |
1257 | | <val>42</val>\ |
1258 | | <val>42</val>\ |
1259 | | </Struct>"); |
1260 | | } |
1261 | | } |
1262 | | |
1263 | | mod attributes { |
1264 | | use super::*; |
1265 | | use pretty_assertions::assert_eq; |
1266 | | |
1267 | | serialize_as!(map_attr: BTreeMap::from([("@key1", 1), ("@key2", 2)]) |
1268 | | => r#"<root key1="1" key2="2"/>"#); |
1269 | | serialize_as!(map_mixed: BTreeMap::from([("@key1", 1), ("key2", 2)]) |
1270 | | => r#"<root key1="1"><key2>2</key2></root>"#); |
1271 | | |
1272 | | serialize_as!(struct_: Attributes { key: "answer", val: (42, 42) } |
1273 | | => r#"<root key="answer" val="42 42"/>"#); |
1274 | | serialize_as!(struct_before: AttributesBefore { key: "answer", val: 42 } |
1275 | | => r#"<root key="answer"><val>42</val></root>"#); |
1276 | | serialize_as!(struct_after: AttributesAfter { key: "answer", val: 42 } |
1277 | | => r#"<root val="42"><key>answer</key></root>"#); |
1278 | | |
1279 | | err!(enum_: Enum::Attributes { key: "answer", val: (42, 42) } |
1280 | | => Unsupported("cannot serialize enum struct variant `Enum::Attributes`")); |
1281 | | |
1282 | | /// Test for https://github.com/tafia/quick-xml/issues/252 |
1283 | | mod optional { |
1284 | | use super::*; |
1285 | | use pretty_assertions::assert_eq; |
1286 | | |
1287 | | serialize_as!(none: |
1288 | | OptionalAttributes { a: None, b: None } |
1289 | | => r#"<root a=""/>"#); |
1290 | | serialize_as!(some_empty_str: |
1291 | | OptionalAttributes { |
1292 | | a: Some(""), |
1293 | | b: Some(""), |
1294 | | } |
1295 | | => r#"<root a="" b=""/>"#); |
1296 | | serialize_as!(some_non_empty: |
1297 | | OptionalAttributes { |
1298 | | a: Some("1"), |
1299 | | b: Some("2"), |
1300 | | } |
1301 | | => r#"<root a="1" b="2"/>"#); |
1302 | | } |
1303 | | } |
1304 | | |
1305 | | /// Test for https://github.com/tafia/quick-xml/issues/252 |
1306 | | mod optional { |
1307 | | use super::*; |
1308 | | use pretty_assertions::assert_eq; |
1309 | | |
1310 | | serialize_as!(none: |
1311 | | OptionalElements { a: None, b: None } |
1312 | | => "<root>\ |
1313 | | <a/>\ |
1314 | | </root>"); |
1315 | | serialize_as!(some_empty_str: |
1316 | | OptionalElements { |
1317 | | a: Some(""), |
1318 | | b: Some(""), |
1319 | | } |
1320 | | => "<root>\ |
1321 | | <a/>\ |
1322 | | <b/>\ |
1323 | | </root>"); |
1324 | | serialize_as!(some_non_empty: |
1325 | | OptionalElements { |
1326 | | a: Some("1"), |
1327 | | b: Some("2"), |
1328 | | } |
1329 | | => "<root>\ |
1330 | | <a>1</a>\ |
1331 | | <b>2</b>\ |
1332 | | </root>"); |
1333 | | } |
1334 | | } |
1335 | | |
1336 | | mod with_indent { |
1337 | | use super::*; |
1338 | | use crate::se::content::tests::Struct; |
1339 | | use crate::writer::Indentation; |
1340 | | use pretty_assertions::assert_eq; |
1341 | | |
1342 | | /// Checks that given `$data` successfully serialized as `$expected`. |
1343 | | /// Writes `$data` using [`ElementSerializer`] with indent of two spaces. |
1344 | | macro_rules! serialize_as { |
1345 | | ($name:ident: $data:expr => $expected:expr) => { |
1346 | | #[test] |
1347 | | fn $name() { |
1348 | | let mut buffer = String::new(); |
1349 | | let ser = ElementSerializer { |
1350 | | ser: ContentSerializer { |
1351 | | writer: &mut buffer, |
1352 | | level: QuoteLevel::Full, |
1353 | | indent: Indent::Owned(Indentation::new(b' ', 2)), |
1354 | | write_indent: false, |
1355 | | text_format: TextFormat::Text, |
1356 | | allow_primitive: true, |
1357 | | empty_element_handling: EmptyElementHandling::SelfClosed, |
1358 | | }, |
1359 | | key: XmlName("root"), |
1360 | | }; |
1361 | | |
1362 | | let result = $data.serialize(ser).unwrap(); |
1363 | | assert_eq!(buffer, $expected); |
1364 | | assert_eq!(result, WriteResult::Element); |
1365 | | } |
1366 | | }; |
1367 | | } |
1368 | | |
1369 | | /// Checks that attempt to serialize given `$data` results to a |
1370 | | /// serialization error `$kind` with `$reason` |
1371 | | macro_rules! err { |
1372 | | ($name:ident: $data:expr => $kind:ident($reason:literal)) => { |
1373 | | #[test] |
1374 | | fn $name() { |
1375 | | let mut buffer = String::new(); |
1376 | | let ser = ElementSerializer { |
1377 | | ser: ContentSerializer { |
1378 | | writer: &mut buffer, |
1379 | | level: QuoteLevel::Full, |
1380 | | indent: Indent::Owned(Indentation::new(b' ', 2)), |
1381 | | write_indent: false, |
1382 | | text_format: TextFormat::Text, |
1383 | | allow_primitive: true, |
1384 | | empty_element_handling: EmptyElementHandling::SelfClosed, |
1385 | | }, |
1386 | | key: XmlName("root"), |
1387 | | }; |
1388 | | |
1389 | | match $data.serialize(ser).unwrap_err() { |
1390 | | SeError::$kind(e) => assert_eq!(e, $reason), |
1391 | | e => panic!( |
1392 | | "Expected `Err({}({}))`, but got `{:?}`", |
1393 | | stringify!($kind), |
1394 | | $reason, |
1395 | | e |
1396 | | ), |
1397 | | } |
1398 | | // We can write something before fail |
1399 | | // assert_eq!(buffer, ""); |
1400 | | } |
1401 | | }; |
1402 | | } |
1403 | | |
1404 | | serialize_as!(false_: false => "<root>false</root>"); |
1405 | | serialize_as!(true_: true => "<root>true</root>"); |
1406 | | |
1407 | | serialize_as!(i8_: -42i8 => "<root>-42</root>"); |
1408 | | serialize_as!(i16_: -4200i16 => "<root>-4200</root>"); |
1409 | | serialize_as!(i32_: -42000000i32 => "<root>-42000000</root>"); |
1410 | | serialize_as!(i64_: -42000000000000i64 => "<root>-42000000000000</root>"); |
1411 | | serialize_as!(isize_: -42000000isize => "<root>-42000000</root>"); |
1412 | | |
1413 | | serialize_as!(u8_: 42u8 => "<root>42</root>"); |
1414 | | serialize_as!(u16_: 4200u16 => "<root>4200</root>"); |
1415 | | serialize_as!(u32_: 42000000u32 => "<root>42000000</root>"); |
1416 | | serialize_as!(u64_: 42000000000000u64 => "<root>42000000000000</root>"); |
1417 | | serialize_as!(usize_: 42000000usize => "<root>42000000</root>"); |
1418 | | |
1419 | | serialize_as!(i128_: -420000000000000000000000000000i128 => "<root>-420000000000000000000000000000</root>"); |
1420 | | serialize_as!(u128_: 420000000000000000000000000000u128 => "<root>420000000000000000000000000000</root>"); |
1421 | | |
1422 | | serialize_as!(f32_: 4.2f32 => "<root>4.2</root>"); |
1423 | | serialize_as!(f64_: 4.2f64 => "<root>4.2</root>"); |
1424 | | |
1425 | | serialize_as!(char_non_escaped: 'h' => "<root>h</root>"); |
1426 | | serialize_as!(char_lt: '<' => "<root><</root>"); |
1427 | | serialize_as!(char_gt: '>' => "<root>></root>"); |
1428 | | serialize_as!(char_amp: '&' => "<root>&</root>"); |
1429 | | serialize_as!(char_apos: '\'' => "<root>'</root>"); |
1430 | | serialize_as!(char_quot: '"' => "<root>"</root>"); |
1431 | | serialize_as!(char_space: ' ' => "<root> </root>"); |
1432 | | |
1433 | | serialize_as!(str_non_escaped: "non-escaped string" => "<root>non-escaped string</root>"); |
1434 | | serialize_as!(str_escaped: "<\"escaped & string'>" => "<root><"escaped & string'></root>"); |
1435 | | |
1436 | | err!(bytes: Bytes(b"<\"escaped & bytes'>") => Unsupported("`serialize_bytes` not supported yet")); |
1437 | | |
1438 | | serialize_as!(option_none: Option::<&str>::None => "<root/>"); |
1439 | | serialize_as!(option_some: Some("non-escaped string") => "<root>non-escaped string</root>"); |
1440 | | serialize_as!(option_some_empty: Some("") => "<root/>"); |
1441 | | |
1442 | | serialize_as!(unit: () => "<root/>"); |
1443 | | serialize_as!(unit_struct: Unit => "<root/>"); |
1444 | | serialize_as!(unit_struct_escaped: UnitEscaped => "<root/>"); |
1445 | | |
1446 | | serialize_as!(enum_unit: Enum::Unit => "<root>Unit</root>"); |
1447 | | serialize_as!(enum_unit_escaped: Enum::UnitEscaped => "<root><"&'></root>"); |
1448 | | |
1449 | | serialize_as!(newtype: Newtype(42) => "<root>42</root>"); |
1450 | | err!(enum_newtype: Enum::Newtype(42) |
1451 | | => Unsupported("cannot serialize enum newtype variant `Enum::Newtype`")); |
1452 | | |
1453 | | serialize_as!(seq: vec![1, 2, 3] |
1454 | | => "<root>1</root>\n\ |
1455 | | <root>2</root>\n\ |
1456 | | <root>3</root>"); |
1457 | | serialize_as!(seq_empty: Vec::<usize>::new() => ""); |
1458 | | serialize_as!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize) |
1459 | | => "<root><"&'></root>\n\ |
1460 | | <root>with\t\n\r spaces</root>\n\ |
1461 | | <root>3</root>"); |
1462 | | serialize_as!(tuple_struct: Tuple("first", 42) |
1463 | | => "<root>first</root>\n\ |
1464 | | <root>42</root>"); |
1465 | | err!(enum_tuple: Enum::Tuple("first", 42) |
1466 | | => Unsupported("cannot serialize enum tuple variant `Enum::Tuple`")); |
1467 | | |
1468 | | serialize_as!(map: BTreeMap::from([("_1", 2), ("_3", 4)]) |
1469 | | => "<root>\n \ |
1470 | | <_1>2</_1>\n \ |
1471 | | <_3>4</_3>\n\ |
1472 | | </root>"); |
1473 | | serialize_as!(struct_: Struct { key: "answer", val: (42, 42) } |
1474 | | => "<root>\n \ |
1475 | | <key>answer</key>\n \ |
1476 | | <val>42</val>\n \ |
1477 | | <val>42</val>\n\ |
1478 | | </root>"); |
1479 | | err!(enum_struct: Enum::Struct { key: "answer", val: (42, 42) } |
1480 | | => Unsupported("cannot serialize enum struct variant `Enum::Struct`")); |
1481 | | |
1482 | | /// Special field name `$text` should be serialized as text content. |
1483 | | /// Sequences serialized as an `xs:list` content |
1484 | | mod text_field { |
1485 | | use super::*; |
1486 | | |
1487 | | /// `$text` key in a map |
1488 | | mod map { |
1489 | | use super::*; |
1490 | | use pretty_assertions::assert_eq; |
1491 | | |
1492 | | macro_rules! text { |
1493 | | ($name:ident: $data:expr) => { |
1494 | | serialize_as!($name: |
1495 | | // Serialization started from ElementSerializer::serialize_map |
1496 | | BTreeMap::from([("$text", $data)]) |
1497 | | => "<root/>"); |
1498 | | }; |
1499 | | ($name:ident: $data:expr => $expected:literal) => { |
1500 | | serialize_as!($name: |
1501 | | // Serialization started from ElementSerializer::serialize_map |
1502 | | BTreeMap::from([("$text", $data)]) |
1503 | | => concat!("<root>", $expected,"</root>")); |
1504 | | }; |
1505 | | } |
1506 | | |
1507 | | text!(false_: false => "false"); |
1508 | | text!(true_: true => "true"); |
1509 | | |
1510 | | text!(i8_: -42i8 => "-42"); |
1511 | | text!(i16_: -4200i16 => "-4200"); |
1512 | | text!(i32_: -42000000i32 => "-42000000"); |
1513 | | text!(i64_: -42000000000000i64 => "-42000000000000"); |
1514 | | text!(isize_: -42000000isize => "-42000000"); |
1515 | | |
1516 | | text!(u8_: 42u8 => "42"); |
1517 | | text!(u16_: 4200u16 => "4200"); |
1518 | | text!(u32_: 42000000u32 => "42000000"); |
1519 | | text!(u64_: 42000000000000u64 => "42000000000000"); |
1520 | | text!(usize_: 42000000usize => "42000000"); |
1521 | | |
1522 | | text!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000"); |
1523 | | text!(u128_: 420000000000000000000000000000u128 => "420000000000000000000000000000"); |
1524 | | |
1525 | | text!(f32_: 4.2f32 => "4.2"); |
1526 | | text!(f64_: 4.2f64 => "4.2"); |
1527 | | |
1528 | | text!(char_non_escaped: 'h' => "h"); |
1529 | | text!(char_lt: '<' => "<"); |
1530 | | text!(char_gt: '>' => ">"); |
1531 | | text!(char_amp: '&' => "&"); |
1532 | | text!(char_apos: '\'' => "'"); |
1533 | | text!(char_quot: '"' => """); |
1534 | | text!(char_space: ' ' => " "); |
1535 | | |
1536 | | text!(str_non_escaped: "non-escaped string" => "non-escaped string"); |
1537 | | text!(str_escaped: "<\"escaped & string'>" => "<"escaped & string'>"); |
1538 | | |
1539 | | err!(bytes: |
1540 | | Text { |
1541 | | before: "answer", |
1542 | | content: Bytes(b"<\"escaped & bytes'>"), |
1543 | | after: "answer", |
1544 | | } |
1545 | | => Unsupported("`serialize_bytes` not supported yet")); |
1546 | | |
1547 | | text!(option_none: Option::<&str>::None); |
1548 | | text!(option_some: Some("non-escaped string") => "non-escaped string"); |
1549 | | text!(option_some_empty_str: Some("")); |
1550 | | |
1551 | | text!(unit: ()); |
1552 | | text!(unit_struct: Unit); |
1553 | | text!(unit_struct_escaped: UnitEscaped); |
1554 | | |
1555 | | text!(enum_unit: Enum::Unit => "Unit"); |
1556 | | text!(enum_unit_escaped: Enum::UnitEscaped => "<"&'>"); |
1557 | | |
1558 | | text!(newtype: Newtype(42) => "42"); |
1559 | | // We have no space where name of a variant can be stored |
1560 | | err!(enum_newtype: |
1561 | | Text { |
1562 | | before: "answer", |
1563 | | content: Enum::Newtype(42), |
1564 | | after: "answer", |
1565 | | } |
1566 | | => Unsupported("cannot serialize enum newtype variant `Enum::Newtype` as text content value")); |
1567 | | |
1568 | | // Sequences are serialized separated by spaces, all spaces inside are escaped |
1569 | | text!(seq: vec![1, 2, 3] => "1 2 3"); |
1570 | | text!(seq_empty: Vec::<usize>::new()); |
1571 | | text!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize) |
1572 | | => "<"&'> \ |
1573 | | with	  spaces \ |
1574 | | 3"); |
1575 | | text!(tuple_struct: Tuple("first", 42) => "first 42"); |
1576 | | // We have no space where name of a variant can be stored |
1577 | | err!(enum_tuple: |
1578 | | Text { |
1579 | | before: "answer", |
1580 | | content: Enum::Tuple("first", 42), |
1581 | | after: "answer", |
1582 | | } |
1583 | | => Unsupported("cannot serialize enum tuple variant `Enum::Tuple` as text content value")); |
1584 | | |
1585 | | // Complex types cannot be serialized in `$text` field |
1586 | | err!(map: |
1587 | | Text { |
1588 | | before: "answer", |
1589 | | content: BTreeMap::from([("_1", 2), ("_3", 4)]), |
1590 | | after: "answer", |
1591 | | } |
1592 | | => Unsupported("cannot serialize map as text content value")); |
1593 | | err!(struct_: |
1594 | | Text { |
1595 | | before: "answer", |
1596 | | content: Struct { key: "answer", val: (42, 42) }, |
1597 | | after: "answer", |
1598 | | } |
1599 | | => Unsupported("cannot serialize struct `Struct` as text content value")); |
1600 | | err!(enum_struct: |
1601 | | Text { |
1602 | | before: "answer", |
1603 | | content: Enum::Struct { key: "answer", val: (42, 42) }, |
1604 | | after: "answer", |
1605 | | } |
1606 | | => Unsupported("cannot serialize enum struct variant `Enum::Struct` as text content value")); |
1607 | | } |
1608 | | |
1609 | | /// `$text` field inside a struct |
1610 | | mod struct_ { |
1611 | | use super::*; |
1612 | | use pretty_assertions::assert_eq; |
1613 | | |
1614 | | macro_rules! text { |
1615 | | ($name:ident: $data:expr => $expected:literal) => { |
1616 | | serialize_as!($name: |
1617 | | // Serialization started from ElementSerializer::serialize_struct |
1618 | | Text { |
1619 | | before: "answer", |
1620 | | content: $data, |
1621 | | after: "answer", |
1622 | | } |
1623 | | => concat!( |
1624 | | "<root>\n <before>answer</before>", |
1625 | | $expected, |
1626 | | "<after>answer</after>\n</root>", |
1627 | | )); |
1628 | | }; |
1629 | | } |
1630 | | |
1631 | | text!(false_: false => "false"); |
1632 | | text!(true_: true => "true"); |
1633 | | |
1634 | | text!(i8_: -42i8 => "-42"); |
1635 | | text!(i16_: -4200i16 => "-4200"); |
1636 | | text!(i32_: -42000000i32 => "-42000000"); |
1637 | | text!(i64_: -42000000000000i64 => "-42000000000000"); |
1638 | | text!(isize_: -42000000isize => "-42000000"); |
1639 | | |
1640 | | text!(u8_: 42u8 => "42"); |
1641 | | text!(u16_: 4200u16 => "4200"); |
1642 | | text!(u32_: 42000000u32 => "42000000"); |
1643 | | text!(u64_: 42000000000000u64 => "42000000000000"); |
1644 | | text!(usize_: 42000000usize => "42000000"); |
1645 | | |
1646 | | text!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000"); |
1647 | | text!(u128_: 420000000000000000000000000000u128 => "420000000000000000000000000000"); |
1648 | | |
1649 | | text!(f32_: 4.2f32 => "4.2"); |
1650 | | text!(f64_: 4.2f64 => "4.2"); |
1651 | | |
1652 | | text!(char_non_escaped: 'h' => "h"); |
1653 | | text!(char_lt: '<' => "<"); |
1654 | | text!(char_gt: '>' => ">"); |
1655 | | text!(char_amp: '&' => "&"); |
1656 | | text!(char_apos: '\'' => "'"); |
1657 | | text!(char_quot: '"' => """); |
1658 | | text!(char_space: ' ' => " "); |
1659 | | |
1660 | | text!(str_non_escaped: "non-escaped string" => "non-escaped string"); |
1661 | | text!(str_escaped: "<\"escaped & string'>" => "<"escaped & string'>"); |
1662 | | |
1663 | | err!(bytes: |
1664 | | Text { |
1665 | | before: "answer", |
1666 | | content: Bytes(b"<\"escaped & bytes'>"), |
1667 | | after: "answer", |
1668 | | } |
1669 | | => Unsupported("`serialize_bytes` not supported yet")); |
1670 | | |
1671 | | text!(option_none: Option::<&str>::None => ""); |
1672 | | text!(option_some: Some("non-escaped string") => "non-escaped string"); |
1673 | | text!(option_some_empty_str: Some("") => ""); |
1674 | | |
1675 | | text!(unit: () => ""); |
1676 | | text!(unit_struct: Unit => ""); |
1677 | | text!(unit_struct_escaped: UnitEscaped => ""); |
1678 | | |
1679 | | text!(enum_unit: Enum::Unit => "Unit"); |
1680 | | text!(enum_unit_escaped: Enum::UnitEscaped => "<"&'>"); |
1681 | | |
1682 | | text!(newtype: Newtype(42) => "42"); |
1683 | | // We have no space where name of a variant can be stored |
1684 | | err!(enum_newtype: |
1685 | | Text { |
1686 | | before: "answer", |
1687 | | content: Enum::Newtype(42), |
1688 | | after: "answer", |
1689 | | } |
1690 | | => Unsupported("cannot serialize enum newtype variant `Enum::Newtype` as text content value")); |
1691 | | |
1692 | | // Sequences are serialized separated by spaces, all spaces inside are escaped |
1693 | | text!(seq: vec![1, 2, 3] => "1 2 3"); |
1694 | | text!(seq_empty: Vec::<usize>::new() => ""); |
1695 | | text!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize) |
1696 | | => "<"&'> \ |
1697 | | with	  spaces \ |
1698 | | 3"); |
1699 | | text!(tuple_struct: Tuple("first", 42) => "first 42"); |
1700 | | // We have no space where name of a variant can be stored |
1701 | | err!(enum_tuple: |
1702 | | Text { |
1703 | | before: "answer", |
1704 | | content: Enum::Tuple("first", 42), |
1705 | | after: "answer", |
1706 | | } |
1707 | | => Unsupported("cannot serialize enum tuple variant `Enum::Tuple` as text content value")); |
1708 | | |
1709 | | // Complex types cannot be serialized in `$text` field |
1710 | | err!(map: |
1711 | | Text { |
1712 | | before: "answer", |
1713 | | content: BTreeMap::from([("_1", 2), ("_3", 4)]), |
1714 | | after: "answer", |
1715 | | } |
1716 | | => Unsupported("cannot serialize map as text content value")); |
1717 | | err!(struct_: |
1718 | | Text { |
1719 | | before: "answer", |
1720 | | content: Struct { key: "answer", val: (42, 42) }, |
1721 | | after: "answer", |
1722 | | } |
1723 | | => Unsupported("cannot serialize struct `Struct` as text content value")); |
1724 | | err!(enum_struct: |
1725 | | Text { |
1726 | | before: "answer", |
1727 | | content: Enum::Struct { key: "answer", val: (42, 42) }, |
1728 | | after: "answer", |
1729 | | } |
1730 | | => Unsupported("cannot serialize enum struct variant `Enum::Struct` as text content value")); |
1731 | | } |
1732 | | } |
1733 | | |
1734 | | /// Special field name `$value` should be serialized using name, provided |
1735 | | /// by the type of value instead of a key. Sequences serialized as a list |
1736 | | /// of tags with that name (each element can have their own name) |
1737 | | mod value_field { |
1738 | | use super::*; |
1739 | | |
1740 | | /// `$value` key in a map |
1741 | | mod map { |
1742 | | use super::*; |
1743 | | use pretty_assertions::assert_eq; |
1744 | | |
1745 | | macro_rules! value { |
1746 | | ($name:ident: $data:expr) => { |
1747 | | serialize_as!($name: |
1748 | | // Serialization started from ElementSerializer::serialize_map |
1749 | | BTreeMap::from([("$value", $data)]) |
1750 | | => "<root/>"); |
1751 | | }; |
1752 | | ($name:ident: $data:expr => $expected:literal) => { |
1753 | | serialize_as!($name: |
1754 | | // Serialization started from ElementSerializer::serialize_map |
1755 | | BTreeMap::from([("$value", $data)]) |
1756 | | => concat!("<root>", $expected,"</root>")); |
1757 | | }; |
1758 | | } |
1759 | | |
1760 | | value!(false_: false => "false"); |
1761 | | value!(true_: true => "true"); |
1762 | | |
1763 | | value!(i8_: -42i8 => "-42"); |
1764 | | value!(i16_: -4200i16 => "-4200"); |
1765 | | value!(i32_: -42000000i32 => "-42000000"); |
1766 | | value!(i64_: -42000000000000i64 => "-42000000000000"); |
1767 | | value!(isize_: -42000000isize => "-42000000"); |
1768 | | |
1769 | | value!(u8_: 42u8 => "42"); |
1770 | | value!(u16_: 4200u16 => "4200"); |
1771 | | value!(u32_: 42000000u32 => "42000000"); |
1772 | | value!(u64_: 42000000000000u64 => "42000000000000"); |
1773 | | value!(usize_: 42000000usize => "42000000"); |
1774 | | |
1775 | | value!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000"); |
1776 | | value!(u128_: 420000000000000000000000000000u128 => "420000000000000000000000000000"); |
1777 | | |
1778 | | value!(f32_: 4.2f32 => "4.2"); |
1779 | | value!(f64_: 4.2f64 => "4.2"); |
1780 | | |
1781 | | value!(char_non_escaped: 'h' => "h"); |
1782 | | value!(char_lt: '<' => "<"); |
1783 | | value!(char_gt: '>' => ">"); |
1784 | | value!(char_amp: '&' => "&"); |
1785 | | value!(char_apos: '\'' => "'"); |
1786 | | value!(char_quot: '"' => """); |
1787 | | value!(char_space: ' ' => " "); |
1788 | | |
1789 | | value!(str_non_escaped: "non-escaped string" => "non-escaped string"); |
1790 | | value!(str_escaped: "<\"escaped & string'>" => "<"escaped & string'>"); |
1791 | | |
1792 | | err!(bytes: |
1793 | | BTreeMap::from([("$value", Bytes(b"<\"escaped & bytes'>"))]) |
1794 | | => Unsupported("`serialize_bytes` not supported yet")); |
1795 | | |
1796 | | value!(option_none: Option::<&str>::None); |
1797 | | value!(option_some: Some("non-escaped string") => "non-escaped string"); |
1798 | | value!(option_some_empty_str: Some("")); |
1799 | | |
1800 | | value!(unit: ()); |
1801 | | value!(unit_struct: Unit); |
1802 | | value!(unit_struct_escaped: UnitEscaped); |
1803 | | |
1804 | | value!(enum_unit: Enum::Unit => "\n <Unit/>\n"); |
1805 | | err!(enum_unit_escaped: |
1806 | | BTreeMap::from([("$value", Enum::UnitEscaped)]) |
1807 | | => Unsupported("character `<` is not allowed at the start of an XML name `<\"&'>`")); |
1808 | | |
1809 | | value!(newtype: Newtype(42) => "42"); |
1810 | | value!(enum_newtype: Enum::Newtype(42) => "\n <Newtype>42</Newtype>\n"); |
1811 | | |
1812 | | err!(seq: |
1813 | | BTreeMap::from([("$value", vec![1, 2, 3])]) |
1814 | | => Unsupported("consequent primitives would be serialized without delimiter and cannot be deserialized back")); |
1815 | | value!(seq_empty: Vec::<usize>::new()); |
1816 | | err!(tuple: |
1817 | | BTreeMap::from([("$value", ("<\"&'>", "with\t\n\r spaces", 3usize))]) |
1818 | | => Unsupported("consequent primitives would be serialized without delimiter and cannot be deserialized back")); |
1819 | | err!(tuple_struct: |
1820 | | BTreeMap::from([("$value", Tuple("first", 42))]) |
1821 | | => Unsupported("consequent primitives would be serialized without delimiter and cannot be deserialized back")); |
1822 | | value!(enum_tuple: Enum::Tuple("first", 42) |
1823 | | => "\n \ |
1824 | | <Tuple>first</Tuple>\n \ |
1825 | | <Tuple>42</Tuple>\n"); |
1826 | | |
1827 | | // We cannot wrap map in any container and should not |
1828 | | // flatten it, so it is impossible to serialize maps |
1829 | | err!(map: |
1830 | | BTreeMap::from([("$value", BTreeMap::from([("_1", 2), ("_3", 4)]))]) |
1831 | | => Unsupported("serialization of map types is not supported in `$value` field")); |
1832 | | value!(struct_: |
1833 | | Struct { key: "answer", val: (42, 42) } |
1834 | | => "\n \ |
1835 | | <Struct>\n \ |
1836 | | <key>answer</key>\n \ |
1837 | | <val>42</val>\n \ |
1838 | | <val>42</val>\n \ |
1839 | | </Struct>\n"); |
1840 | | value!(enum_struct: |
1841 | | Enum::Struct { key: "answer", val: (42, 42) } |
1842 | | => "\n \ |
1843 | | <Struct>\n \ |
1844 | | <key>answer</key>\n \ |
1845 | | <val>42</val>\n \ |
1846 | | <val>42</val>\n \ |
1847 | | </Struct>\n"); |
1848 | | } |
1849 | | |
1850 | | /// `$value` field inside a struct |
1851 | | mod struct_ { |
1852 | | use super::*; |
1853 | | use pretty_assertions::assert_eq; |
1854 | | |
1855 | | macro_rules! value { |
1856 | | ($name:ident: $data:expr => $expected:literal) => { |
1857 | | serialize_as!($name: |
1858 | | // Serialization started from ElementSerializer::serialize_struct |
1859 | | Value { |
1860 | | before: "answer", |
1861 | | content: $data, |
1862 | | after: "answer", |
1863 | | } |
1864 | | => concat!( |
1865 | | "<root>\n <before>answer</before>", |
1866 | | $expected, |
1867 | | "<after>answer</after>\n</root>", |
1868 | | )); |
1869 | | }; |
1870 | | } |
1871 | | |
1872 | | value!(false_: false => "false"); |
1873 | | value!(true_: true => "true"); |
1874 | | |
1875 | | value!(i8_: -42i8 => "-42"); |
1876 | | value!(i16_: -4200i16 => "-4200"); |
1877 | | value!(i32_: -42000000i32 => "-42000000"); |
1878 | | value!(i64_: -42000000000000i64 => "-42000000000000"); |
1879 | | value!(isize_: -42000000isize => "-42000000"); |
1880 | | |
1881 | | value!(u8_: 42u8 => "42"); |
1882 | | value!(u16_: 4200u16 => "4200"); |
1883 | | value!(u32_: 42000000u32 => "42000000"); |
1884 | | value!(u64_: 42000000000000u64 => "42000000000000"); |
1885 | | value!(usize_: 42000000usize => "42000000"); |
1886 | | |
1887 | | value!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000"); |
1888 | | value!(u128_: 420000000000000000000000000000u128 => "420000000000000000000000000000"); |
1889 | | |
1890 | | value!(f32_: 4.2f32 => "4.2"); |
1891 | | value!(f64_: 4.2f64 => "4.2"); |
1892 | | |
1893 | | value!(char_non_escaped: 'h' => "h"); |
1894 | | value!(char_lt: '<' => "<"); |
1895 | | value!(char_gt: '>' => ">"); |
1896 | | value!(char_amp: '&' => "&"); |
1897 | | value!(char_apos: '\'' => "'"); |
1898 | | value!(char_quot: '"' => """); |
1899 | | value!(char_space: ' ' => " "); |
1900 | | |
1901 | | value!(str_non_escaped: "non-escaped string" => "non-escaped string"); |
1902 | | value!(str_escaped: "<\"escaped & string'>" => "<"escaped & string'>"); |
1903 | | |
1904 | | err!(bytes: |
1905 | | Value { |
1906 | | before: "answer", |
1907 | | content: Bytes(b"<\"escaped & bytes'>"), |
1908 | | after: "answer", |
1909 | | } |
1910 | | => Unsupported("`serialize_bytes` not supported yet")); |
1911 | | |
1912 | | value!(option_none: Option::<&str>::None => ""); |
1913 | | value!(option_some: Some("non-escaped string") => "non-escaped string"); |
1914 | | value!(option_some_empty_str: Some("") => ""); |
1915 | | |
1916 | | value!(unit: () => "\n "); |
1917 | | value!(unit_struct: Unit => "\n "); |
1918 | | value!(unit_struct_escaped: UnitEscaped => "\n "); |
1919 | | |
1920 | | value!(enum_unit: Enum::Unit => "\n <Unit/>\n "); |
1921 | | err!(enum_unit_escaped: |
1922 | | Value { |
1923 | | before: "answer", |
1924 | | content: Enum::UnitEscaped, |
1925 | | after: "answer", |
1926 | | } |
1927 | | => Unsupported("character `<` is not allowed at the start of an XML name `<\"&'>`")); |
1928 | | |
1929 | | value!(newtype: Newtype(42) => "42"); |
1930 | | value!(enum_newtype: Enum::Newtype(42) => "\n <Newtype>42</Newtype>\n "); |
1931 | | |
1932 | | err!(seq: |
1933 | | Value { |
1934 | | before: "answer", |
1935 | | content: vec![1, 2, 3], |
1936 | | after: "answer", |
1937 | | } |
1938 | | => Unsupported("consequent primitives would be serialized without delimiter and cannot be deserialized back")); |
1939 | | value!(seq_empty: Vec::<usize>::new() => ""); |
1940 | | err!(tuple: |
1941 | | Value { |
1942 | | before: "answer", |
1943 | | content: ("<\"&'>", "with\t\n\r spaces", 3usize), |
1944 | | after: "answer", |
1945 | | } |
1946 | | => Unsupported("consequent primitives would be serialized without delimiter and cannot be deserialized back")); |
1947 | | err!(tuple_struct: |
1948 | | Value { |
1949 | | before: "answer", |
1950 | | content: Tuple("first", 42), |
1951 | | after: "answer", |
1952 | | } |
1953 | | => Unsupported("consequent primitives would be serialized without delimiter and cannot be deserialized back")); |
1954 | | value!(enum_tuple: Enum::Tuple("first", 42) |
1955 | | => "\n \ |
1956 | | <Tuple>first</Tuple>\n \ |
1957 | | <Tuple>42</Tuple>\n "); |
1958 | | |
1959 | | // We cannot wrap map in any container and should not |
1960 | | // flatten it, so it is impossible to serialize maps |
1961 | | err!(map: |
1962 | | Value { |
1963 | | before: "answer", |
1964 | | content: BTreeMap::from([("_1", 2), ("_3", 4)]), |
1965 | | after: "answer", |
1966 | | } |
1967 | | => Unsupported("serialization of map types is not supported in `$value` field")); |
1968 | | value!(struct_: |
1969 | | Value { |
1970 | | before: "answer", |
1971 | | content: Struct { key: "answer", val: (42, 42) }, |
1972 | | after: "answer", |
1973 | | } |
1974 | | => "\n \ |
1975 | | <Value>\n \ |
1976 | | <before>answer</before>\n \ |
1977 | | <Struct>\n \ |
1978 | | <key>answer</key>\n \ |
1979 | | <val>42</val>\n \ |
1980 | | <val>42</val>\n \ |
1981 | | </Struct>\n \ |
1982 | | <after>answer</after>\n \ |
1983 | | </Value>\n "); |
1984 | | value!(enum_struct: |
1985 | | Enum::Struct { key: "answer", val: (42, 42) } |
1986 | | => "\n \ |
1987 | | <Struct>\n \ |
1988 | | <key>answer</key>\n \ |
1989 | | <val>42</val>\n \ |
1990 | | <val>42</val>\n \ |
1991 | | </Struct>\n "); |
1992 | | } |
1993 | | } |
1994 | | |
1995 | | mod attributes { |
1996 | | use super::*; |
1997 | | use pretty_assertions::assert_eq; |
1998 | | |
1999 | | serialize_as!(map_attr: BTreeMap::from([("@key1", 1), ("@key2", 2)]) |
2000 | | => r#"<root key1="1" key2="2"/>"#); |
2001 | | serialize_as!(map_mixed: BTreeMap::from([("@key1", 1), ("key2", 2)]) |
2002 | | => "<root key1=\"1\">\n \ |
2003 | | <key2>2</key2>\n\ |
2004 | | </root>"); |
2005 | | |
2006 | | serialize_as!(struct_: Attributes { key: "answer", val: (42, 42) } |
2007 | | => r#"<root key="answer" val="42 42"/>"#); |
2008 | | serialize_as!(struct_before: AttributesBefore { key: "answer", val: 42 } |
2009 | | => "<root key=\"answer\">\n \ |
2010 | | <val>42</val>\n\ |
2011 | | </root>"); |
2012 | | serialize_as!(struct_after: AttributesAfter { key: "answer", val: 42 } |
2013 | | => "<root val=\"42\">\n \ |
2014 | | <key>answer</key>\n\ |
2015 | | </root>"); |
2016 | | |
2017 | | err!(enum_: Enum::Attributes { key: "answer", val: (42, 42) } |
2018 | | => Unsupported("cannot serialize enum struct variant `Enum::Attributes`")); |
2019 | | |
2020 | | /// Test for https://github.com/tafia/quick-xml/issues/252 |
2021 | | mod optional { |
2022 | | use super::*; |
2023 | | use pretty_assertions::assert_eq; |
2024 | | |
2025 | | serialize_as!(none: |
2026 | | OptionalAttributes { a: None, b: None } |
2027 | | => r#"<root a=""/>"#); |
2028 | | serialize_as!(some_empty_str: |
2029 | | OptionalAttributes { |
2030 | | a: Some(""), |
2031 | | b: Some("") |
2032 | | } |
2033 | | => r#"<root a="" b=""/>"#); |
2034 | | serialize_as!(some_non_empty: |
2035 | | OptionalAttributes { |
2036 | | a: Some("a"), |
2037 | | b: Some("b") |
2038 | | } |
2039 | | => r#"<root a="a" b="b"/>"#); |
2040 | | } |
2041 | | } |
2042 | | |
2043 | | /// Test for https://github.com/tafia/quick-xml/issues/252 |
2044 | | mod optional { |
2045 | | use super::*; |
2046 | | use pretty_assertions::assert_eq; |
2047 | | |
2048 | | serialize_as!(none: |
2049 | | OptionalElements { a: None, b: None } |
2050 | | => "<root>\n \ |
2051 | | <a/>\n\ |
2052 | | </root>"); |
2053 | | serialize_as!(some_empty_str: |
2054 | | OptionalElements { |
2055 | | a: Some(""), |
2056 | | b: Some("") |
2057 | | } |
2058 | | => "<root>\n \ |
2059 | | <a/>\n \ |
2060 | | <b/>\n\ |
2061 | | </root>"); |
2062 | | serialize_as!(some_non_empty: |
2063 | | OptionalElements { |
2064 | | a: Some("a"), |
2065 | | b: Some("b") |
2066 | | } |
2067 | | => "<root>\n \ |
2068 | | <a>a</a>\n \ |
2069 | | <b>b</b>\n\ |
2070 | | </root>"); |
2071 | | } |
2072 | | } |
2073 | | |
2074 | | mod expand_empty_elements { |
2075 | | use super::*; |
2076 | | use pretty_assertions::assert_eq; |
2077 | | |
2078 | | /// Checks that given `$data` successfully serialized as `$expected` |
2079 | | macro_rules! serialize_as { |
2080 | | ($name:ident: $data:expr => $expected:expr) => { |
2081 | | #[test] |
2082 | | fn $name() { |
2083 | | let mut buffer = String::new(); |
2084 | | let ser = ElementSerializer { |
2085 | | ser: ContentSerializer { |
2086 | | writer: &mut buffer, |
2087 | | level: QuoteLevel::Full, |
2088 | | indent: Indent::None, |
2089 | | write_indent: false, |
2090 | | text_format: TextFormat::Text, |
2091 | | allow_primitive: true, |
2092 | | empty_element_handling: EmptyElementHandling::Expanded, |
2093 | | }, |
2094 | | key: XmlName("root"), |
2095 | | }; |
2096 | | |
2097 | | let result = $data.serialize(ser).unwrap(); |
2098 | | assert_eq!(buffer, $expected); |
2099 | | assert_eq!(result, WriteResult::Element); |
2100 | | } |
2101 | | }; |
2102 | | } |
2103 | | |
2104 | | serialize_as!(option_some_empty: Some("") => "<root></root>"); |
2105 | | serialize_as!(option_some_empty_str: Some("") => "<root></root>"); |
2106 | | |
2107 | | serialize_as!(unit: () => "<root></root>"); |
2108 | | serialize_as!(unit_struct: Unit => "<root></root>"); |
2109 | | serialize_as!(unit_struct_escaped: UnitEscaped => "<root></root>"); |
2110 | | |
2111 | | serialize_as!(enum_unit: Enum::Unit => "<root>Unit</root>"); |
2112 | | serialize_as!(enum_unit_escaped: Enum::UnitEscaped => "<root><"&'></root>"); |
2113 | | } |
2114 | | } |