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