1use crate::upnp::{DecodeXml, EncodeXml};
2use instant_xml::{Deserializer, FromXml, Id, Kind, ToXml};
3
4#[derive(Debug, PartialEq, Clone, Default)]
8pub struct DecodeXmlString<T>(pub Option<T>)
9where
10 T: DecodeXml;
11
12impl<'xml, T> FromXml<'xml> for DecodeXmlString<T>
13where
14 T: DecodeXml,
15{
16 #[inline]
17 fn matches(id: Id<'_>, field: Option<Id<'_>>) -> bool {
18 match field {
19 Some(field) => id == field,
20 None => false,
21 }
22 }
23
24 fn deserialize<'cx>(
25 target: &mut <Self as FromXml<'_>>::Accumulator,
26 field: &'static str,
27 deserializer: &mut Deserializer<'cx, '_>,
28 ) -> std::result::Result<(), instant_xml::Error> {
29 if target.is_some() {
30 return Err(instant_xml::Error::DuplicateValue(field));
31 }
32
33 match deserializer.take_str()? {
34 Some(value) => {
35 let is_empty = value.trim().is_empty() || value == "NOT_IMPLEMENTED";
38
39 if !is_empty {
40 let parsed = T::decode_xml(&value).map_err(|err| {
41 instant_xml::Error::Other(format!(
42 "failed to decode_xml for {field}: `{err:#}` {value}"
43 ))
44 })?;
45 target.replace(DecodeXmlString(Some(parsed)));
46 }
47 Ok(())
48 }
49 None => {
50 Ok(())
52 }
53 }
54 }
55
56 type Accumulator = Option<Self>;
57 const KIND: Kind = Kind::Scalar;
59}
60
61impl<T> ToXml for DecodeXmlString<T>
62where
63 T: DecodeXml,
64 T: EncodeXml,
65{
66 fn serialize<W>(
67 &self,
68 id: Option<Id<'_>>,
69 serializer: &mut instant_xml::Serializer<'_, W>,
70 ) -> std::result::Result<(), instant_xml::Error>
71 where
72 W: std::fmt::Write + ?Sized,
73 {
74 let encoded = match &self.0 {
75 Some(inner) => inner.encode_xml()?,
76 None => String::new(),
77 };
78 encoded.serialize(id, serializer)
79 }
80}
81
82impl<T: DecodeXml> DecodeXmlString<T> {
83 pub fn into_inner(self) -> Option<T> {
84 self.0
85 }
86}
87
88impl<T: DecodeXml> std::ops::Deref for DecodeXmlString<T> {
89 type Target = Option<T>;
90 fn deref(&self) -> &Option<T> {
91 &self.0
92 }
93}
94
95impl<T: DecodeXml> From<T> for DecodeXmlString<T> {
96 fn from(value: T) -> DecodeXmlString<T> {
97 DecodeXmlString(Some(value))
98 }
99}
100
101impl<T: DecodeXml> From<Option<T>> for DecodeXmlString<T> {
102 fn from(value: Option<T>) -> DecodeXmlString<T> {
103 DecodeXmlString(value)
104 }
105}