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