1use std::borrow::Cow;
2use std::fmt;
3use std::net::IpAddr;
4use std::str;
5use std::str::FromStr;
6use std::{any::type_name, marker::PhantomData};
7
8#[cfg(feature = "chrono")]
9use chrono::{DateTime, NaiveDate, NaiveDateTime, Utc};
10
11use crate::{Accumulate, Deserializer, Error, FromXml, Id, Kind, Serializer, ToXml};
12
13pub fn from_xml_str<T: FromStr>(
19 into: &mut Option<T>,
20 field: &'static str,
21 deserializer: &mut Deserializer<'_, '_>,
22) -> Result<(), Error> {
23 if into.is_some() {
24 return Err(Error::DuplicateValue(field));
25 }
26
27 let value = match deserializer.take_str()? {
28 Some(value) => value,
29 None => return Ok(()),
30 };
31
32 match T::from_str(value.as_ref()) {
33 Ok(value) => {
34 *into = Some(value);
35 Ok(())
36 }
37 Err(_) => Err(Error::UnexpectedValue(format!(
38 "unable to parse {} from `{value}`",
39 type_name::<T>()
40 ))),
41 }
42}
43
44struct FromXmlStr<T: FromStr>(T);
45
46impl<'xml, T: FromStr> FromXml<'xml> for FromXmlStr<T> {
47 #[inline]
48 fn matches(id: Id<'_>, field: Option<Id<'_>>) -> bool {
49 match field {
50 Some(field) => id == field,
51 None => false,
52 }
53 }
54
55 fn deserialize(
56 into: &mut Self::Accumulator,
57 field: &'static str,
58 deserializer: &mut Deserializer<'_, 'xml>,
59 ) -> Result<(), Error> {
60 if into.is_some() {
61 return Err(Error::DuplicateValue(field));
62 }
63
64 let value = match deserializer.take_str()? {
65 Some(value) => value,
66 None => return Ok(()),
67 };
68
69 match T::from_str(value.as_ref()) {
70 Ok(value) => {
71 *into = Some(FromXmlStr(value));
72 Ok(())
73 }
74 Err(_) => Err(Error::UnexpectedValue(format!(
75 "unable to parse {} from `{value}` for {field}",
76 type_name::<T>()
77 ))),
78 }
79 }
80
81 type Accumulator = Option<FromXmlStr<T>>;
82 const KIND: Kind = Kind::Scalar;
83}
84
85impl<'xml> FromXml<'xml> for bool {
86 #[inline]
87 fn matches(id: Id<'_>, field: Option<Id<'_>>) -> bool {
88 match field {
89 Some(field) => id == field,
90 None => false,
91 }
92 }
93
94 fn deserialize<'cx>(
95 into: &mut Self::Accumulator,
96 field: &'static str,
97 deserializer: &mut Deserializer<'cx, 'xml>,
98 ) -> Result<(), Error> {
99 if into.is_some() {
100 return Err(Error::DuplicateValue(field));
101 }
102
103 let value = match deserializer.take_str()? {
104 Some(value) => value,
105 None => return Ok(()),
106 };
107
108 let value = match value.as_ref() {
109 "true" | "1" => true,
110 "false" | "0" => false,
111 val => {
112 return Err(Error::UnexpectedValue(format!(
113 "unable to parse bool from '{val}' for {field}"
114 )))
115 }
116 };
117
118 *into = Some(value);
119 Ok(())
120 }
121
122 type Accumulator = Option<bool>;
123 const KIND: Kind = Kind::Scalar;
124}
125
126pub fn display_to_xml(
132 value: &impl fmt::Display,
133 field: Option<Id<'_>>,
134 serializer: &mut Serializer<impl fmt::Write + ?Sized>,
135) -> Result<(), Error> {
136 DisplayToXml(value).serialize(field, serializer)
137}
138
139struct DisplayToXml<'a, T: fmt::Display>(pub &'a T);
140
141impl<T> ToXml for DisplayToXml<'_, T>
142where
143 T: fmt::Display,
144{
145 fn serialize<W: fmt::Write + ?Sized>(
146 &self,
147 field: Option<Id<'_>>,
148 serializer: &mut Serializer<W>,
149 ) -> Result<(), Error> {
150 let prefix = match field {
151 Some(id) => {
152 let prefix = serializer.write_start(id.name, id.ns)?;
153 serializer.end_start()?;
154 Some((prefix, id.name))
155 }
156 None => None,
157 };
158
159 serializer.write_str(self.0)?;
160 if let Some((prefix, name)) = prefix {
161 serializer.write_close(prefix, name)?;
162 }
163
164 Ok(())
165 }
166}
167
168macro_rules! to_xml_for_number {
169 ($typ:ty) => {
170 impl ToXml for $typ {
171 fn serialize<W: fmt::Write + ?Sized>(
172 &self,
173 field: Option<Id<'_>>,
174 serializer: &mut Serializer<W>,
175 ) -> Result<(), Error> {
176 DisplayToXml(self).serialize(field, serializer)
177 }
178 }
179 };
180}
181
182macro_rules! from_xml_for_number {
183 ($typ:ty) => {
184 impl<'xml> FromXml<'xml> for $typ {
185 #[inline]
186 fn matches(id: Id<'_>, field: Option<Id<'_>>) -> bool {
187 match field {
188 Some(field) => id == field,
189 None => false,
190 }
191 }
192
193 fn deserialize<'cx>(
194 into: &mut Self::Accumulator,
195 field: &'static str,
196 deserializer: &mut Deserializer<'cx, 'xml>,
197 ) -> Result<(), Error> {
198 if into.is_some() {
199 return Err(Error::DuplicateValue(field));
200 }
201
202 let Some(value) = deserializer.take_str()? else {
203 return Ok(());
204 };
205
206 match <$typ>::from_str(value.as_ref().trim()) {
207 Ok(value) => *into = Some(value),
208 Err(_) => {
209 return Err(Error::UnexpectedValue(format!(
210 "unable to parse number {} from `{value}` for {field}",
211 type_name::<$typ>()
212 )))
213 }
214 }
215
216 Ok(())
217 }
218
219 type Accumulator = Option<Self>;
220 const KIND: Kind = Kind::Scalar;
221 }
222 };
223}
224
225from_xml_for_number!(i8);
226from_xml_for_number!(i16);
227from_xml_for_number!(i32);
228from_xml_for_number!(i64);
229from_xml_for_number!(isize);
230from_xml_for_number!(u8);
231from_xml_for_number!(u16);
232from_xml_for_number!(u32);
233from_xml_for_number!(u64);
234from_xml_for_number!(usize);
235from_xml_for_number!(f32);
236from_xml_for_number!(f64);
237
238impl<'xml> FromXml<'xml> for char {
239 #[inline]
240 fn matches(id: Id<'_>, field: Option<Id<'_>>) -> bool {
241 match field {
242 Some(field) => id == field,
243 None => false,
244 }
245 }
246
247 fn deserialize<'cx>(
248 into: &mut Self::Accumulator,
249 field: &'static str,
250 deserializer: &mut Deserializer<'cx, 'xml>,
251 ) -> Result<(), Error> {
252 if into.is_some() {
253 return Err(Error::DuplicateValue(field));
254 }
255
256 let mut value = None;
257 FromXmlStr::<Self>::deserialize(&mut value, field, deserializer)?;
258 if let Some(value) = value {
259 *into = Some(value.0);
260 }
261
262 Ok(())
263 }
264
265 type Accumulator = Option<Self>;
266 const KIND: Kind = Kind::Scalar;
267}
268
269impl<'xml> FromXml<'xml> for String {
270 #[inline]
271 fn matches(id: Id<'_>, field: Option<Id<'_>>) -> bool {
272 match field {
273 Some(field) => id == field,
274 None => false,
275 }
276 }
277
278 fn deserialize<'cx>(
279 into: &mut Self::Accumulator,
280 field: &'static str,
281 deserializer: &mut Deserializer<'cx, 'xml>,
282 ) -> Result<(), Error> {
283 if into.is_some() {
284 return Err(Error::DuplicateValue(field));
285 }
286
287 *into = Some(match deserializer.take_str()? {
288 Some(value) => value.into_owned(),
289 None => String::new(),
290 });
291
292 Ok(())
293 }
294
295 type Accumulator = Option<String>;
296 const KIND: Kind = Kind::Scalar;
297}
298
299impl<'xml, 'a> FromXml<'xml> for Cow<'a, str> {
300 #[inline]
301 fn matches(id: Id<'_>, field: Option<Id<'_>>) -> bool {
302 match field {
303 Some(field) => id == field,
304 None => false,
305 }
306 }
307
308 fn deserialize(
309 into: &mut Self::Accumulator,
310 field: &'static str,
311 deserializer: &mut Deserializer<'_, 'xml>,
312 ) -> Result<(), Error> {
313 if into.inner.is_some() {
314 return Err(Error::DuplicateValue(field));
315 }
316
317 into.inner = Some(match deserializer.take_str()? {
318 Some(value) => value.into_owned().into(),
319 None => "".into(),
320 });
321
322 Ok(())
323 }
324
325 type Accumulator = CowStrAccumulator<'xml, 'a>;
326 const KIND: Kind = Kind::Scalar;
327}
328
329#[derive(Default)]
331pub struct CowStrAccumulator<'xml, 'a> {
332 pub(crate) inner: Option<Cow<'a, str>>,
333 marker: PhantomData<&'xml str>,
334}
335
336impl<'a> Accumulate<Cow<'a, str>> for CowStrAccumulator<'_, 'a> {
337 fn try_done(self, field: &'static str) -> Result<Cow<'a, str>, Error> {
338 match self.inner {
339 Some(inner) => Ok(inner),
340 None => Err(Error::MissingValue(field)),
341 }
342 }
343}
344
345impl<'xml, T: FromXml<'xml>> FromXml<'xml> for Cow<'_, [T]>
349where
350 [T]: ToOwned<Owned = Vec<T>>,
351{
352 #[inline]
353 fn matches(id: Id<'_>, field: Option<Id<'_>>) -> bool {
354 T::matches(id, field)
355 }
356
357 fn deserialize(
358 into: &mut Self::Accumulator,
359 field: &'static str,
360 deserializer: &mut Deserializer<'_, 'xml>,
361 ) -> Result<(), Error> {
362 let mut value = T::Accumulator::default();
363 T::deserialize(&mut value, field, deserializer)?;
364 into.push(value.try_done(field)?);
365 Ok(())
366 }
367
368 type Accumulator = Vec<T>;
369 const KIND: Kind = Kind::Scalar;
370}
371
372impl<T: ToXml> ToXml for Cow<'_, [T]>
373where
374 [T]: ToOwned,
375{
376 fn serialize<W: fmt::Write + ?Sized>(
377 &self,
378 field: Option<Id<'_>>,
379 serializer: &mut Serializer<W>,
380 ) -> Result<(), Error> {
381 self.as_ref().serialize(field, serializer)
382 }
383}
384
385impl<'xml, T: FromXml<'xml>> FromXml<'xml> for Option<T> {
386 #[inline]
387 fn matches(id: Id<'_>, field: Option<Id<'_>>) -> bool {
388 T::matches(id, field)
389 }
390
391 fn deserialize<'cx>(
392 into: &mut Self::Accumulator,
393 field: &'static str,
394 deserializer: &mut Deserializer<'cx, 'xml>,
395 ) -> Result<(), Error> {
396 <T>::deserialize(&mut into.value, field, deserializer)?;
397 Ok(())
398 }
399
400 type Accumulator = OptionAccumulator<T, T::Accumulator>;
401 const KIND: Kind = <T>::KIND;
402}
403
404pub struct OptionAccumulator<T, A: Accumulate<T>> {
406 value: A,
407 marker: PhantomData<T>,
408}
409
410impl<T, A: Accumulate<T>> OptionAccumulator<T, A> {
411 pub fn get_mut(&mut self) -> &mut A {
413 &mut self.value
414 }
415}
416
417impl<T, A: Accumulate<T>> Default for OptionAccumulator<T, A> {
418 fn default() -> Self {
419 Self {
420 value: A::default(),
421 marker: PhantomData,
422 }
423 }
424}
425
426impl<T, A: Accumulate<T>> Accumulate<Option<T>> for OptionAccumulator<T, A> {
427 fn try_done(self, field: &'static str) -> Result<Option<T>, Error> {
428 match self.value.try_done(field) {
429 Ok(value) => Ok(Some(value)),
430 Err(_) => Ok(None),
431 }
432 }
433}
434
435to_xml_for_number!(i8);
436to_xml_for_number!(i16);
437to_xml_for_number!(i32);
438to_xml_for_number!(i64);
439to_xml_for_number!(isize);
440to_xml_for_number!(u8);
441to_xml_for_number!(u16);
442to_xml_for_number!(u32);
443to_xml_for_number!(u64);
444to_xml_for_number!(usize);
445to_xml_for_number!(f32);
446to_xml_for_number!(f64);
447
448impl ToXml for bool {
449 fn serialize<W: fmt::Write + ?Sized>(
450 &self,
451 field: Option<Id<'_>>,
452 serializer: &mut Serializer<W>,
453 ) -> Result<(), Error> {
454 let value = match self {
455 true => "true",
456 false => "false",
457 };
458
459 DisplayToXml(&value).serialize(field, serializer)
460 }
461}
462
463impl ToXml for String {
464 fn serialize<W: fmt::Write + ?Sized>(
465 &self,
466 field: Option<Id<'_>>,
467 serializer: &mut Serializer<W>,
468 ) -> Result<(), Error> {
469 DisplayToXml(&encode(self)?).serialize(field, serializer)
470 }
471}
472
473impl ToXml for char {
474 fn serialize<W: fmt::Write + ?Sized>(
475 &self,
476 field: Option<Id<'_>>,
477 serializer: &mut Serializer<W>,
478 ) -> Result<(), Error> {
479 let mut tmp = [0u8; 4];
480 DisplayToXml(&encode(&*self.encode_utf8(&mut tmp))?).serialize(field, serializer)
481 }
482}
483
484impl ToXml for str {
485 fn serialize<W: fmt::Write + ?Sized>(
486 &self,
487 field: Option<Id<'_>>,
488 serializer: &mut Serializer<W>,
489 ) -> Result<(), Error> {
490 DisplayToXml(&encode(self)?).serialize(field, serializer)
491 }
492}
493
494impl ToXml for Cow<'_, str> {
495 fn serialize<W: fmt::Write + ?Sized>(
496 &self,
497 field: Option<Id<'_>>,
498 serializer: &mut Serializer<W>,
499 ) -> Result<(), Error> {
500 DisplayToXml(&encode(self)?).serialize(field, serializer)
501 }
502}
503
504impl<T: ToXml> ToXml for Option<T> {
505 fn serialize<W: fmt::Write + ?Sized>(
506 &self,
507 field: Option<Id<'_>>,
508 serializer: &mut Serializer<W>,
509 ) -> Result<(), Error> {
510 match self {
511 Some(v) => v.serialize(field, serializer),
512 None => Ok(()),
513 }
514 }
515
516 fn present(&self) -> bool {
517 self.is_some()
518 }
519}
520
521impl<T: ToXml + ?Sized> ToXml for Box<T> {
522 fn serialize<W: fmt::Write + ?Sized>(
523 &self,
524 field: Option<Id<'_>>,
525 serializer: &mut Serializer<W>,
526 ) -> Result<(), Error> {
527 self.as_ref().serialize(field, serializer)
528 }
529}
530
531impl<'xml, T: FromXml<'xml>> FromXml<'xml> for Box<T> {
532 #[inline]
533 fn matches(id: Id<'_>, field: Option<Id<'_>>) -> bool {
534 T::matches(id, field)
535 }
536
537 fn deserialize<'cx>(
538 into: &mut Self::Accumulator,
539 field: &'static str,
540 deserializer: &mut Deserializer<'cx, 'xml>,
541 ) -> Result<(), Error> {
542 if into.is_some() {
543 return Err(Error::DuplicateValue(field));
544 }
545
546 let mut value = T::Accumulator::default();
547 T::deserialize(&mut value, field, deserializer)?;
548 *into = Some(Box::new(value.try_done(field)?));
549
550 Ok(())
551 }
552
553 type Accumulator = Option<Self>;
554 const KIND: Kind = T::KIND;
555}
556
557fn encode(input: &str) -> Result<Cow<'_, str>, Error> {
558 let mut result = String::with_capacity(input.len());
559 let mut last_end = 0;
560 for (start, c) in input.char_indices() {
561 let to = match c {
562 '&' => "&",
563 '"' => """,
564 '<' => "<",
565 '>' => ">",
566 '\'' => "'",
567 _ => continue,
568 };
569 result.push_str(input.get(last_end..start).unwrap());
570 result.push_str(to);
571 last_end = start + 1;
572 }
573
574 if result.is_empty() {
575 return Ok(Cow::Borrowed(input));
576 }
577
578 result.push_str(input.get(last_end..input.len()).unwrap());
579 Ok(Cow::Owned(result))
580}
581
582impl<'xml, T: FromXml<'xml>> FromXml<'xml> for Vec<T> {
583 #[inline]
584 fn matches(id: Id<'_>, field: Option<Id<'_>>) -> bool {
585 T::matches(id, field)
586 }
587
588 fn deserialize<'cx>(
589 into: &mut Self::Accumulator,
590 field: &'static str,
591 deserializer: &mut Deserializer<'cx, 'xml>,
592 ) -> Result<(), Error> {
593 let mut value = T::Accumulator::default();
594 T::deserialize(&mut value, field, deserializer)?;
595 into.push(value.try_done(field)?);
596 Ok(())
597 }
598
599 type Accumulator = Vec<T>;
600 const KIND: Kind = T::KIND;
601}
602
603impl<T: ToXml> ToXml for Vec<T> {
604 fn serialize<W: fmt::Write + ?Sized>(
605 &self,
606 field: Option<Id<'_>>,
607 serializer: &mut Serializer<W>,
608 ) -> Result<(), Error> {
609 self.as_slice().serialize(field, serializer)
610 }
611}
612
613impl<T: ToXml> ToXml for [T] {
614 fn serialize<W: fmt::Write + ?Sized>(
615 &self,
616 field: Option<Id<'_>>,
617 serializer: &mut Serializer<W>,
618 ) -> Result<(), Error> {
619 for i in self {
620 i.serialize(field, serializer)?;
621 }
622
623 Ok(())
624 }
625}
626
627#[cfg(feature = "chrono")]
628impl ToXml for DateTime<Utc> {
629 fn serialize<W: fmt::Write + ?Sized>(
630 &self,
631 field: Option<Id<'_>>,
632 serializer: &mut Serializer<W>,
633 ) -> Result<(), Error> {
634 let prefix = match field {
635 Some(id) => {
636 let prefix = serializer.write_start(id.name, id.ns)?;
637 serializer.end_start()?;
638 Some((prefix, id.name))
639 }
640 None => None,
641 };
642
643 serializer.write_str(&self.to_rfc3339())?;
644 if let Some((prefix, name)) = prefix {
645 serializer.write_close(prefix, name)?;
646 }
647
648 Ok(())
649 }
650}
651
652#[cfg(feature = "chrono")]
653impl<'xml> FromXml<'xml> for DateTime<Utc> {
654 #[inline]
655 fn matches(id: Id<'_>, field: Option<Id<'_>>) -> bool {
656 match field {
657 Some(field) => id == field,
658 None => false,
659 }
660 }
661
662 fn deserialize<'cx>(
663 into: &mut Self::Accumulator,
664 field: &'static str,
665 deserializer: &mut Deserializer<'cx, 'xml>,
666 ) -> Result<(), Error> {
667 if into.is_some() {
668 return Err(Error::DuplicateValue(field));
669 }
670
671 let value = match deserializer.take_str()? {
672 Some(value) => value,
673 None => return Ok(()),
674 };
675
676 match DateTime::parse_from_rfc3339(value.as_ref()) {
677 Ok(dt) if dt.timezone().utc_minus_local() == 0 => {
678 *into = Some(dt.with_timezone(&Utc));
679 Ok(())
680 }
681 _ => Err(Error::Other("invalid date/time".into())),
682 }
683 }
684
685 type Accumulator = Option<Self>;
686 const KIND: Kind = Kind::Scalar;
687}
688
689#[cfg(feature = "chrono")]
690impl ToXml for NaiveDateTime {
691 fn serialize<W: fmt::Write + ?Sized>(
692 &self,
693 field: Option<Id<'_>>,
694 serializer: &mut Serializer<W>,
695 ) -> Result<(), Error> {
696 let prefix = match field {
697 Some(id) => {
698 let prefix = serializer.write_start(id.name, id.ns)?;
699 serializer.end_start()?;
700 Some((prefix, id.name))
701 }
702 None => None,
703 };
704
705 serializer.write_str(&self.format("%Y-%m-%dT%H:%M:%S%.f"))?;
706 if let Some((prefix, name)) = prefix {
707 serializer.write_close(prefix, name)?;
708 }
709
710 Ok(())
711 }
712}
713
714#[cfg(feature = "chrono")]
715impl<'xml> FromXml<'xml> for NaiveDateTime {
716 fn matches(id: Id<'_>, field: Option<Id<'_>>) -> bool {
717 match field {
718 Some(field) => id == field,
719 None => false,
720 }
721 }
722
723 fn deserialize<'cx>(
724 into: &mut Self::Accumulator,
725 field: &'static str,
726 deserializer: &mut Deserializer<'cx, 'xml>,
727 ) -> Result<(), Error> {
728 if into.is_some() {
729 return Err(Error::DuplicateValue(field));
730 }
731
732 let value = match deserializer.take_str()? {
733 Some(value) => value,
734 None => return Ok(()),
735 };
736
737 match NaiveDateTime::parse_from_str(value.as_ref(), "%Y-%m-%dT%H:%M:%S%.f") {
738 Ok(dt) => {
739 *into = Some(dt);
740 Ok(())
741 }
742 _ => Err(Error::Other("invalid date/time".into())),
743 }
744 }
745
746 type Accumulator = Option<Self>;
747
748 const KIND: Kind = Kind::Scalar;
749}
750
751#[cfg(feature = "chrono")]
752impl ToXml for NaiveDate {
753 fn serialize<W: fmt::Write + ?Sized>(
754 &self,
755 field: Option<Id<'_>>,
756 serializer: &mut Serializer<W>,
757 ) -> Result<(), Error> {
758 let prefix = match field {
759 Some(id) => {
760 let prefix = serializer.write_start(id.name, id.ns)?;
761 serializer.end_start()?;
762 Some((prefix, id.name))
763 }
764 None => None,
765 };
766
767 serializer.write_str(&self)?;
768 if let Some((prefix, name)) = prefix {
769 serializer.write_close(prefix, name)?;
770 }
771
772 Ok(())
773 }
774}
775
776#[cfg(feature = "chrono")]
777impl<'xml> FromXml<'xml> for NaiveDate {
778 #[inline]
779 fn matches(id: Id<'_>, field: Option<Id<'_>>) -> bool {
780 match field {
781 Some(field) => id == field,
782 None => false,
783 }
784 }
785
786 fn deserialize<'cx>(
787 into: &mut Self::Accumulator,
788 field: &'static str,
789 deserializer: &mut Deserializer<'cx, 'xml>,
790 ) -> Result<(), Error> {
791 if into.is_some() {
792 return Err(Error::DuplicateValue(field));
793 }
794
795 let value = match deserializer.take_str()? {
796 Some(value) => value,
797 None => return Ok(()),
798 };
799
800 match NaiveDate::parse_from_str(value.as_ref(), "%Y-%m-%d") {
801 Ok(d) => {
802 *into = Some(d);
803 Ok(())
804 }
805 _ => Err(Error::Other("invalid date/time".into())),
806 }
807 }
808
809 type Accumulator = Option<Self>;
810 const KIND: Kind = Kind::Scalar;
811}
812
813impl<'xml> FromXml<'xml> for () {
814 #[inline]
815 fn matches(id: Id<'_>, field: Option<Id<'_>>) -> bool {
816 match field {
817 Some(field) => id == field,
818 None => false,
819 }
820 }
821
822 fn deserialize<'cx>(
823 into: &mut Self::Accumulator,
824 _: &'static str,
825 _: &mut Deserializer<'cx, 'xml>,
826 ) -> Result<(), Error> {
827 *into = Some(());
828 Ok(())
829 }
830
831 type Accumulator = Option<Self>;
832 const KIND: Kind = Kind::Scalar;
833}
834
835impl ToXml for IpAddr {
836 fn serialize<W: fmt::Write + ?Sized>(
837 &self,
838 field: Option<Id<'_>>,
839 serializer: &mut Serializer<W>,
840 ) -> Result<(), Error> {
841 DisplayToXml(self).serialize(field, serializer)
842 }
843}
844
845impl<'xml> FromXml<'xml> for IpAddr {
846 #[inline]
847 fn matches(id: Id<'_>, field: Option<Id<'_>>) -> bool {
848 match field {
849 Some(field) => id == field,
850 None => false,
851 }
852 }
853
854 fn deserialize<'cx>(
855 into: &mut Self::Accumulator,
856 field: &'static str,
857 deserializer: &mut Deserializer<'cx, 'xml>,
858 ) -> Result<(), Error> {
859 if into.is_some() {
860 return Err(Error::DuplicateValue(field));
861 }
862
863 let mut value = None;
864 FromXmlStr::<Self>::deserialize(&mut value, field, deserializer)?;
865 if let Some(value) = value {
866 *into = Some(value.0);
867 }
868
869 Ok(())
870 }
871
872 type Accumulator = Option<Self>;
873 const KIND: Kind = Kind::Scalar;
874}
875
876#[cfg(test)]
877mod tests {
878 use super::*;
879
880 #[test]
881 fn encode_unicode() {
882 let input = "Iñtërnâ&tiônàlizætiøn";
883 assert_eq!(encode(input).unwrap(), "Iñtërnâ&tiônàlizætiøn");
884 }
885}