1use std::{
2 io::{Read, Write},
3 str::{from_utf8, Utf8Error},
4};
5
6use opcua_xml::{XmlReadError, XmlStreamReader, XmlStreamWriter, XmlWriteError};
7
8use crate::{Context, EncodingResult, Error, UaNullable};
9
10impl From<XmlReadError> for Error {
11 fn from(value: XmlReadError) -> Self {
12 Self::decoding(value)
13 }
14}
15
16impl From<XmlWriteError> for Error {
17 fn from(value: XmlWriteError) -> Self {
18 Self::encoding(value)
19 }
20}
21
22impl From<Utf8Error> for Error {
23 fn from(value: Utf8Error) -> Self {
24 Self::decoding(value)
25 }
26}
27
28pub trait XmlType {
30 const TAG: &'static str;
33 fn tag(&self) -> &str {
35 Self::TAG
36 }
37}
38
39pub trait XmlDecodable: XmlType {
41 fn decode(
43 read: &mut XmlStreamReader<&mut dyn Read>,
44 context: &Context<'_>,
45 ) -> Result<Self, Error>
46 where
47 Self: Sized;
48}
49
50pub trait XmlEncodable: XmlType + UaNullable {
52 fn encode(
54 &self,
55 writer: &mut XmlStreamWriter<&mut dyn Write>,
56 context: &Context<'_>,
57 ) -> EncodingResult<()>;
58}
59
60pub trait XmlWriteExt {
62 fn encode_child<T: XmlEncodable + ?Sized>(
64 &mut self,
65 tag: &str,
66 value: &T,
67 context: &Context<'_>,
68 ) -> EncodingResult<()>;
69}
70
71impl XmlWriteExt for XmlStreamWriter<&mut dyn Write> {
72 fn encode_child<T: XmlEncodable + ?Sized>(
73 &mut self,
74 tag: &str,
75 value: &T,
76 context: &Context<'_>,
77 ) -> EncodingResult<()> {
78 self.write_start(tag)?;
79 value.encode(self, context)?;
80 self.write_end(tag)?;
81
82 Ok(())
83 }
84}
85
86pub trait XmlReadExt {
88 fn iter_children_include_empty(
92 &mut self,
93 process: impl FnMut(String, Option<&mut Self>, &Context<'_>) -> EncodingResult<()>,
94 context: &Context<'_>,
95 ) -> EncodingResult<()>;
96 fn iter_children(
99 &mut self,
100 cb: impl FnMut(String, &mut Self, &Context<'_>) -> EncodingResult<()>,
101 context: &Context<'_>,
102 ) -> EncodingResult<()>;
103
104 fn get_single_child<T>(
107 &mut self,
108 tag: &str,
109 cb: impl FnMut(&mut Self, &Context<'_>) -> Result<T, Error>,
110 context: &Context<'_>,
111 ) -> EncodingResult<Option<T>>;
112
113 fn decode_single_child<T: XmlDecodable>(
116 &mut self,
117 tag: &str,
118 context: &Context<'_>,
119 ) -> Result<Option<T>, Error>;
120
121 fn get_first_child<T>(
124 &mut self,
125 cb: impl FnOnce(String, &mut Self, &Context<'_>) -> Result<T, Error>,
126 context: &Context<'_>,
127 ) -> EncodingResult<Option<T>>;
128}
129
130impl XmlReadExt for XmlStreamReader<&mut dyn Read> {
131 fn iter_children_include_empty(
132 &mut self,
133 mut process: impl FnMut(String, Option<&mut Self>, &Context<'_>) -> EncodingResult<()>,
134 context: &Context<'_>,
135 ) -> EncodingResult<()> {
136 loop {
137 match self.next_event()? {
138 opcua_xml::events::Event::Start(s) => {
139 let local_name = s.local_name();
140 let name = from_utf8(local_name.as_ref())?;
141 process(name.to_owned(), Some(self), context)?;
142 }
143 opcua_xml::events::Event::Empty(s) => {
144 let local_name = s.local_name();
145 let name = from_utf8(local_name.as_ref())?;
146 process(name.to_owned(), None, context)?;
147 }
148 opcua_xml::events::Event::End(_) | opcua_xml::events::Event::Eof => {
149 return Ok(());
150 }
151 _ => (),
152 }
153 }
154 }
155
156 fn iter_children(
157 &mut self,
158 mut process: impl FnMut(String, &mut Self, &Context<'_>) -> EncodingResult<()>,
159 context: &Context<'_>,
160 ) -> EncodingResult<()> {
161 loop {
162 match self.next_event()? {
163 opcua_xml::events::Event::Start(s) => {
164 let local_name = s.local_name();
165 let name = from_utf8(local_name.as_ref())?;
166 process(name.to_owned(), self, context)?;
167 }
168 opcua_xml::events::Event::End(_) | opcua_xml::events::Event::Eof => {
169 return Ok(());
170 }
171 _ => (),
172 }
173 }
174 }
175
176 fn get_single_child<T>(
177 &mut self,
178 tag: &str,
179 cb: impl FnOnce(&mut Self, &Context<'_>) -> Result<T, Error>,
180 context: &Context<'_>,
181 ) -> EncodingResult<Option<T>> {
182 let mut cb = Some(cb);
183 let mut res = None;
184 self.iter_children(
185 |key, reader, ctx| {
186 if tag == key {
187 if let Some(cb) = cb.take() {
188 res = Some(cb(reader, ctx)?);
189 return Ok(());
190 }
191 }
192 reader.skip_value()?;
193 Ok(())
194 },
195 context,
196 )?;
197 Ok(res)
198 }
199
200 fn decode_single_child<T: XmlDecodable>(
201 &mut self,
202 tag: &str,
203 context: &Context<'_>,
204 ) -> EncodingResult<Option<T>> {
205 self.get_single_child(tag, |reader, ctx| T::decode(reader, ctx), context)
206 }
207
208 fn get_first_child<T>(
209 &mut self,
210 cb: impl FnOnce(String, &mut Self, &Context<'_>) -> Result<T, Error>,
211 context: &Context<'_>,
212 ) -> EncodingResult<Option<T>> {
213 let mut cb = Some(cb);
214 let mut res = None;
215 self.iter_children(
216 |key, reader, ctx| {
217 if let Some(cb) = cb.take() {
218 res = Some(cb(key, reader, ctx)?);
219 return Ok(());
220 }
221 reader.skip_value()?;
222 Ok(())
223 },
224 context,
225 )?;
226 Ok(res)
227 }
228}