opcua_types/xml/
builtins.rs

1use super::{
2    encoding::{XmlDecodable, XmlEncodable, XmlType},
3    XmlReadExt, XmlWriteExt,
4};
5use crate::{Context, Error};
6use opcua_xml::{XmlStreamReader, XmlStreamWriter};
7use std::io::{Read, Write};
8
9macro_rules! xml_enc_number {
10    ($t:ty, $name:expr) => {
11        impl XmlType for $t {
12            const TAG: &'static str = $name;
13        }
14
15        impl XmlEncodable for $t {
16            fn encode(
17                &self,
18                writer: &mut XmlStreamWriter<&mut dyn Write>,
19                _context: &Context<'_>,
20            ) -> Result<(), Error> {
21                writer.write_text(&self.to_string())?;
22                Ok(())
23            }
24        }
25
26        impl XmlDecodable for $t {
27            fn decode(
28                read: &mut XmlStreamReader<&mut dyn Read>,
29                _context: &Context<'_>,
30            ) -> Result<Self, Error> {
31                Ok(read.consume_content()?)
32            }
33        }
34    };
35}
36
37const VALUE_INFINITY: &str = "INF";
38const VALUE_NEG_INFINITY: &str = "-INF";
39const VALUE_NAN: &str = "NaN";
40
41macro_rules! xml_enc_float {
42    ($t:ty, $name:expr) => {
43        impl XmlType for $t {
44            const TAG: &'static str = $name;
45        }
46
47        impl XmlEncodable for $t {
48            fn encode(
49                &self,
50                writer: &mut XmlStreamWriter<&mut dyn Write>,
51                _context: &Context<'_>,
52            ) -> Result<(), Error> {
53                if self.is_infinite() {
54                    if self.is_sign_positive() {
55                        writer.write_text(VALUE_INFINITY)?;
56                    } else {
57                        writer.write_text(VALUE_NEG_INFINITY)?;
58                    }
59                } else if self.is_nan() {
60                    writer.write_text(VALUE_NAN)?;
61                } else {
62                    writer.write_text(&self.to_string())?;
63                }
64                Ok(())
65            }
66        }
67
68        impl XmlDecodable for $t {
69            fn decode(
70                read: &mut XmlStreamReader<&mut dyn Read>,
71                _context: &Context<'_>,
72            ) -> Result<Self, Error> {
73                let val = read.consume_as_text()?;
74                match val.as_str() {
75                    VALUE_INFINITY => Ok(Self::INFINITY),
76                    VALUE_NEG_INFINITY => Ok(Self::NEG_INFINITY),
77                    VALUE_NAN => Ok(Self::NAN),
78                    _ => Ok(val.parse()?),
79                }
80            }
81        }
82    };
83}
84
85xml_enc_number!(u8, "Byte");
86xml_enc_number!(u16, "UInt16");
87xml_enc_number!(u32, "UInt32");
88xml_enc_number!(u64, "UInt64");
89xml_enc_number!(i8, "SByte");
90xml_enc_number!(i16, "Int16");
91xml_enc_number!(i32, "Int32");
92xml_enc_number!(i64, "Int64");
93xml_enc_float!(f32, "Float");
94xml_enc_float!(f64, "Double");
95
96impl XmlType for String {
97    const TAG: &'static str = "String";
98}
99
100impl XmlDecodable for String {
101    fn decode(
102        read: &mut XmlStreamReader<&mut dyn Read>,
103        _context: &Context<'_>,
104    ) -> Result<Self, Error>
105    where
106        Self: Sized,
107    {
108        Ok(read.consume_as_text()?)
109    }
110}
111
112impl XmlEncodable for String {
113    fn encode(
114        &self,
115        writer: &mut XmlStreamWriter<&mut dyn Write>,
116        _context: &Context<'_>,
117    ) -> Result<(), Error> {
118        writer.write_text(self)?;
119        Ok(())
120    }
121}
122
123impl XmlType for str {
124    const TAG: &'static str = "String";
125}
126
127impl XmlEncodable for str {
128    fn encode(
129        &self,
130        writer: &mut XmlStreamWriter<&mut dyn Write>,
131        _context: &Context<'_>,
132    ) -> Result<(), Error> {
133        writer.write_text(self)?;
134        Ok(())
135    }
136}
137
138impl XmlType for bool {
139    const TAG: &'static str = "Boolean";
140}
141
142impl XmlDecodable for bool {
143    fn decode(
144        read: &mut XmlStreamReader<&mut dyn Read>,
145        _context: &Context<'_>,
146    ) -> Result<Self, Error>
147    where
148        Self: Sized,
149    {
150        let val = read.consume_as_text()?;
151        match val.as_str() {
152            "true" | "1" => Ok(true),
153            "false" | "0" => Ok(false),
154            _ => Err(Error::decoding(format!("Invalid boolean value: {val}"))),
155        }
156    }
157}
158
159impl XmlEncodable for bool {
160    fn encode(
161        &self,
162        writer: &mut XmlStreamWriter<&mut dyn Write>,
163        _context: &Context<'_>,
164    ) -> Result<(), Error> {
165        writer.write_text(if *self { "true" } else { "false" })?;
166        Ok(())
167    }
168}
169
170impl<T> XmlType for Box<T>
171where
172    T: XmlType,
173{
174    const TAG: &'static str = T::TAG;
175    fn tag(&self) -> &str {
176        self.as_ref().tag()
177    }
178}
179
180impl<T> XmlDecodable for Box<T>
181where
182    T: XmlDecodable,
183{
184    fn decode(
185        read: &mut XmlStreamReader<&mut dyn Read>,
186        context: &Context<'_>,
187    ) -> Result<Self, Error> {
188        Ok(Box::new(T::decode(read, context)?))
189    }
190}
191
192impl<T> XmlEncodable for Box<T>
193where
194    T: XmlEncodable,
195{
196    fn encode(
197        &self,
198        writer: &mut XmlStreamWriter<&mut dyn Write>,
199        context: &Context<'_>,
200    ) -> Result<(), Error> {
201        self.as_ref().encode(writer, context)
202    }
203}
204
205impl<T> XmlType for Vec<T>
206where
207    T: XmlType,
208{
209    // Could be ListOf... but there's no static way to do so, and it isn't
210    // strictly necessary.
211    const TAG: &'static str = T::TAG;
212    fn tag(&self) -> &str {
213        self.first().map(|v| v.tag()).unwrap_or(Self::TAG)
214    }
215}
216
217impl<T> XmlDecodable for Vec<T>
218where
219    T: XmlDecodable + Default,
220{
221    fn decode(
222        read: &mut XmlStreamReader<&mut dyn Read>,
223        context: &Context<'_>,
224    ) -> Result<Self, Error> {
225        let mut vec = Vec::new();
226        read.iter_children_include_empty(
227            |_, reader, context| {
228                let Some(reader) = reader else {
229                    vec.push(T::default());
230                    return Ok(());
231                };
232                vec.push(T::decode(reader, context)?);
233                Ok(())
234            },
235            context,
236        )?;
237        Ok(vec)
238    }
239}
240
241impl<T> XmlEncodable for Vec<T>
242where
243    T: XmlEncodable,
244{
245    fn encode(
246        &self,
247        writer: &mut XmlStreamWriter<&mut dyn Write>,
248        context: &Context<'_>,
249    ) -> super::EncodingResult<()> {
250        for item in self {
251            if item.is_ua_null() {
252                writer.write_empty(item.tag())?;
253            } else {
254                writer.encode_child(item.tag(), item, context)?;
255            }
256        }
257        Ok(())
258    }
259}
260
261impl<T> XmlType for Option<T>
262where
263    T: XmlType,
264{
265    const TAG: &'static str = T::TAG;
266    fn tag(&self) -> &str {
267        self.as_ref().map(|v| v.tag()).unwrap_or(Self::TAG)
268    }
269}
270
271impl<T> XmlDecodable for Option<T>
272where
273    T: XmlDecodable,
274{
275    fn decode(
276        read: &mut XmlStreamReader<&mut dyn Read>,
277        context: &Context<'_>,
278    ) -> Result<Self, Error> {
279        // Effectively we treat missing fields as None, so here we just pass along
280        // to the decoder, since getting here means the field is present.
281        Ok(Some(T::decode(read, context)?))
282    }
283}
284
285impl<T> XmlEncodable for Option<T>
286where
287    T: XmlEncodable,
288{
289    fn encode(
290        &self,
291        writer: &mut XmlStreamWriter<&mut dyn Write>,
292        context: &Context<'_>,
293    ) -> super::EncodingResult<()> {
294        if let Some(value) = self {
295            value.encode(writer, context)?;
296        }
297        Ok(())
298    }
299}