1use crate::{
2 xml::*, Array, ByteString, DataValue, DateTime, DiagnosticInfo, ExpandedNodeId,
3 ExtensionObject, Guid, LocalizedText, NodeId, QualifiedName, StatusCode, UAString,
4};
5
6use super::{Variant, VariantScalarTypeId};
7
8impl XmlType for Variant {
9 const TAG: &'static str = "Variant";
10}
11impl VariantScalarTypeId {
12 pub fn xml_name(&self) -> &'static str {
14 match self {
15 VariantScalarTypeId::Boolean => "Boolean",
16 VariantScalarTypeId::SByte => "SByte",
17 VariantScalarTypeId::Byte => "Byte",
18 VariantScalarTypeId::Int16 => "Int16",
19 VariantScalarTypeId::UInt16 => "UInt16",
20 VariantScalarTypeId::Int32 => "Int32",
21 VariantScalarTypeId::UInt32 => "UInt32",
22 VariantScalarTypeId::Int64 => "Int64",
23 VariantScalarTypeId::UInt64 => "UInt64",
24 VariantScalarTypeId::Float => "Float",
25 VariantScalarTypeId::Double => "Double",
26 VariantScalarTypeId::String => "String",
27 VariantScalarTypeId::DateTime => "DateTime",
28 VariantScalarTypeId::Guid => "Guid",
29 VariantScalarTypeId::ByteString => "ByteString",
30 VariantScalarTypeId::XmlElement => "XmlElement",
31 VariantScalarTypeId::NodeId => "NodeId",
32 VariantScalarTypeId::ExpandedNodeId => "ExpandedNodeId",
33 VariantScalarTypeId::StatusCode => "StatusCode",
34 VariantScalarTypeId::QualifiedName => "QualifiedName",
35 VariantScalarTypeId::LocalizedText => "LocalizedText",
36 VariantScalarTypeId::ExtensionObject => "ExtensionObject",
37 VariantScalarTypeId::DataValue => "DataValue",
38 VariantScalarTypeId::Variant => "Variant",
39 VariantScalarTypeId::DiagnosticInfo => "DiagnosticInfo",
40 }
41 }
42
43 pub fn from_xml_name(name: &str) -> Option<Self> {
45 Some(match name {
46 "Boolean" => VariantScalarTypeId::Boolean,
47 "SByte" => VariantScalarTypeId::SByte,
48 "Byte" => VariantScalarTypeId::Byte,
49 "Int16" => VariantScalarTypeId::Int16,
50 "UInt16" => VariantScalarTypeId::UInt16,
51 "Int32" => VariantScalarTypeId::Int32,
52 "UInt32" => VariantScalarTypeId::UInt32,
53 "Int64" => VariantScalarTypeId::Int64,
54 "UInt64" => VariantScalarTypeId::UInt64,
55 "Float" => VariantScalarTypeId::Float,
56 "Double" => VariantScalarTypeId::Double,
57 "String" => VariantScalarTypeId::String,
58 "DateTime" => VariantScalarTypeId::DateTime,
59 "Guid" => VariantScalarTypeId::Guid,
60 "ByteString" => VariantScalarTypeId::ByteString,
61 "XmlElement" => VariantScalarTypeId::XmlElement,
62 "NodeId" => VariantScalarTypeId::NodeId,
63 "ExpandedNodeId" => VariantScalarTypeId::ExpandedNodeId,
64 "StatusCode" => VariantScalarTypeId::StatusCode,
65 "QualifiedName" => VariantScalarTypeId::QualifiedName,
66 "LocalizedText" => VariantScalarTypeId::LocalizedText,
67 "ExtensionObject" => VariantScalarTypeId::ExtensionObject,
68 "DataValue" => VariantScalarTypeId::DataValue,
69 "Variant" => VariantScalarTypeId::Variant,
70 "DiagnosticInfo" => VariantScalarTypeId::DiagnosticInfo,
71 _ => return None,
72 })
73 }
74}
75
76impl Variant {
77 pub fn get_variant_default(ty: VariantScalarTypeId) -> Variant {
79 match ty {
80 VariantScalarTypeId::Boolean => Variant::Boolean(Default::default()),
81 VariantScalarTypeId::SByte => Variant::SByte(Default::default()),
82 VariantScalarTypeId::Byte => Variant::Byte(Default::default()),
83 VariantScalarTypeId::Int16 => Variant::Int16(Default::default()),
84 VariantScalarTypeId::UInt16 => Variant::UInt16(Default::default()),
85 VariantScalarTypeId::Int32 => Variant::Int32(Default::default()),
86 VariantScalarTypeId::UInt32 => Variant::UInt32(Default::default()),
87 VariantScalarTypeId::Int64 => Variant::Int64(Default::default()),
88 VariantScalarTypeId::UInt64 => Variant::UInt64(Default::default()),
89 VariantScalarTypeId::Float => Variant::Float(Default::default()),
90 VariantScalarTypeId::Double => Variant::Double(Default::default()),
91 VariantScalarTypeId::String => Variant::String(Default::default()),
92 VariantScalarTypeId::DateTime => Variant::DateTime(Default::default()),
93 VariantScalarTypeId::Guid => Variant::Guid(Default::default()),
94 VariantScalarTypeId::ByteString => Variant::ByteString(Default::default()),
95 VariantScalarTypeId::XmlElement => Variant::XmlElement(Default::default()),
96 VariantScalarTypeId::NodeId => Variant::NodeId(Default::default()),
97 VariantScalarTypeId::ExpandedNodeId => Variant::ExpandedNodeId(Default::default()),
98 VariantScalarTypeId::StatusCode => Variant::StatusCode(Default::default()),
99 VariantScalarTypeId::QualifiedName => Variant::QualifiedName(Default::default()),
100 VariantScalarTypeId::LocalizedText => Variant::LocalizedText(Default::default()),
101 VariantScalarTypeId::ExtensionObject => Variant::ExtensionObject(Default::default()),
102 VariantScalarTypeId::DataValue => Variant::DataValue(Default::default()),
103 VariantScalarTypeId::Variant => Variant::Variant(Default::default()),
104 VariantScalarTypeId::DiagnosticInfo => Variant::DiagnosticInfo(Default::default()),
105 }
106 }
107
108 pub fn xml_decode_variant_value(
110 stream: &mut XmlStreamReader<&mut dyn std::io::Read>,
111 context: &Context<'_>,
112 key: &str,
113 ) -> EncodingResult<Self> {
114 if let Some(ty) = key.strip_prefix("ListOf") {
115 let ty = VariantScalarTypeId::from_xml_name(ty)
116 .ok_or_else(|| Error::decoding(format!("Invalid variant contents: {key}")))?;
117 let mut vec = Vec::new();
118 stream.iter_children_include_empty(
119 |key, stream, context| {
120 let Some(stream) = stream else {
121 let ty = VariantScalarTypeId::from_xml_name(&key).ok_or_else(|| {
122 Error::decoding(format!("Invalid variant contents: {key}"))
123 })?;
124 vec.push(Self::get_variant_default(ty));
125 return Ok(());
126 };
127 let r = Variant::xml_decode_variant_value(stream, context, &key)?;
128 vec.push(r);
129 Ok(())
130 },
131 context,
132 )?;
133 Ok(Self::Array(Box::new(
134 Array::new(ty, vec).map_err(Error::decoding)?,
135 )))
136 } else if key == "Matrix" {
137 let mut dims = Vec::new();
138 let mut elems = Vec::new();
139 stream.iter_children(
140 |key, stream, context| match key.as_str() {
141 "Dimensions" => {
142 dims = Vec::<i32>::decode(stream, context)?;
143 Ok(())
144 }
145 "Elements" => stream.iter_children_include_empty(
146 |key, stream, context| {
147 let Some(stream) = stream else {
148 let ty =
149 VariantScalarTypeId::from_xml_name(&key).ok_or_else(|| {
150 Error::decoding(format!("Invalid variant contents: {key}"))
151 })?;
152 elems.push(Self::get_variant_default(ty));
153 return Ok(());
154 };
155 let r = Variant::xml_decode_variant_value(stream, context, &key)?;
156 elems.push(r);
157 Ok(())
158 },
159 context,
160 ),
161 r => Err(Error::decoding(format!(
162 "Invalid field in Matrix content: {r}"
163 ))),
164 },
165 context,
166 )?;
167 let scalar_type = elems
169 .first()
170 .and_then(|v| v.scalar_type_id())
171 .unwrap_or(VariantScalarTypeId::Int32);
172 Ok(Self::Array(Box::new(
173 Array::new_multi(
174 scalar_type,
175 elems,
176 dims.into_iter()
177 .map(|d| d.try_into())
178 .collect::<Result<Vec<_>, _>>()
179 .map_err(|_| {
180 Error::decoding("Invalid array dimensions, must all be non-negative")
181 })?,
182 )
183 .map_err(Error::decoding)?,
184 )))
185 } else {
186 Ok(match key {
187 "Boolean" => Self::Boolean(XmlDecodable::decode(stream, context)?),
188 "SByte" => Self::SByte(XmlDecodable::decode(stream, context)?),
189 "Byte" => Self::Byte(XmlDecodable::decode(stream, context)?),
190 "Int16" => Self::Int16(XmlDecodable::decode(stream, context)?),
191 "UInt16" => Self::UInt16(XmlDecodable::decode(stream, context)?),
192 "Int32" => Self::Int32(XmlDecodable::decode(stream, context)?),
193 "UInt32" => Self::UInt32(XmlDecodable::decode(stream, context)?),
194 "Int64" => Self::Int64(XmlDecodable::decode(stream, context)?),
195 "UInt64" => Self::UInt64(XmlDecodable::decode(stream, context)?),
196 "Float" => Self::Float(XmlDecodable::decode(stream, context)?),
197 "Double" => Self::Double(XmlDecodable::decode(stream, context)?),
198 "String" => Self::String(XmlDecodable::decode(stream, context)?),
199 "DateTime" => Self::DateTime(XmlDecodable::decode(stream, context)?),
200 "Guid" => Self::Guid(XmlDecodable::decode(stream, context)?),
201 "ByteString" => Self::ByteString(XmlDecodable::decode(stream, context)?),
202 "XmlElement" => Self::XmlElement(XmlDecodable::decode(stream, context)?),
203 "NodeId" => Self::NodeId(XmlDecodable::decode(stream, context)?),
204 "ExpandedNodeId" => Self::ExpandedNodeId(XmlDecodable::decode(stream, context)?),
205 "StatusCode" => Self::StatusCode(XmlDecodable::decode(stream, context)?),
206 "QualifiedName" => Self::QualifiedName(XmlDecodable::decode(stream, context)?),
207 "LocalizedText" => Self::LocalizedText(XmlDecodable::decode(stream, context)?),
208 "ExtensionObject" => Self::ExtensionObject(XmlDecodable::decode(stream, context)?),
209 "DataValue" => Self::DataValue(XmlDecodable::decode(stream, context)?),
210 "Variant" => Self::Variant(XmlDecodable::decode(stream, context)?),
211 "DiagnosticInfo" => Self::DiagnosticInfo(XmlDecodable::decode(stream, context)?),
212 r => return Err(Error::decoding(format!("Invalid variant type {r}"))),
213 })
214 }
215 }
216}
217
218impl XmlEncodable for Variant {
219 fn encode(
220 &self,
221 stream: &mut XmlStreamWriter<&mut dyn std::io::Write>,
222 ctx: &Context<'_>,
223 ) -> EncodingResult<()> {
224 match self {
225 Variant::Empty => return Ok(()),
226 Variant::Boolean(v) => stream.encode_child(bool::TAG, v, ctx)?,
227 Variant::SByte(v) => stream.encode_child(i8::TAG, v, ctx)?,
228 Variant::Byte(v) => stream.encode_child(u8::TAG, v, ctx)?,
229 Variant::Int16(v) => stream.encode_child(i16::TAG, v, ctx)?,
230 Variant::UInt16(v) => stream.encode_child(u16::TAG, v, ctx)?,
231 Variant::Int32(v) => stream.encode_child(i32::TAG, v, ctx)?,
232 Variant::UInt32(v) => stream.encode_child(u32::TAG, v, ctx)?,
233 Variant::Int64(v) => stream.encode_child(i64::TAG, v, ctx)?,
234 Variant::UInt64(v) => stream.encode_child(u64::TAG, v, ctx)?,
235 Variant::Float(v) => stream.encode_child(f32::TAG, v, ctx)?,
236 Variant::Double(v) => stream.encode_child(f64::TAG, v, ctx)?,
237 Variant::String(v) => stream.encode_child(UAString::TAG, v, ctx)?,
238 Variant::DateTime(v) => stream.encode_child(DateTime::TAG, v, ctx)?,
239 Variant::Guid(v) => stream.encode_child(Guid::TAG, v, ctx)?,
240 Variant::StatusCode(v) => stream.encode_child(StatusCode::TAG, v, ctx)?,
241 Variant::ByteString(v) => stream.encode_child(ByteString::TAG, v, ctx)?,
242 Variant::XmlElement(v) => stream.encode_child(crate::XmlElement::TAG, v, ctx)?,
243 Variant::QualifiedName(v) => stream.encode_child(QualifiedName::TAG, v, ctx)?,
244 Variant::LocalizedText(v) => stream.encode_child(LocalizedText::TAG, v, ctx)?,
245 Variant::NodeId(v) => stream.encode_child(NodeId::TAG, v, ctx)?,
246 Variant::ExpandedNodeId(v) => stream.encode_child(ExpandedNodeId::TAG, v, ctx)?,
247 Variant::ExtensionObject(v) => stream.encode_child(ExtensionObject::TAG, v, ctx)?,
248 Variant::Variant(v) => stream.encode_child(Variant::TAG, v, ctx)?,
249 Variant::DataValue(v) => stream.encode_child(DataValue::TAG, v, ctx)?,
250 Variant::DiagnosticInfo(v) => stream.encode_child(DiagnosticInfo::TAG, v, ctx)?,
251 Variant::Array(v) => {
252 let xml_name = v.value_type.xml_name();
253 if let Some(dims) = v.dimensions.as_ref() {
254 if dims.len() > 1 {
255 stream.write_start("Matrix")?;
256 let dims: Vec<_> = dims.iter().map(|d| *d as i32).collect();
260 stream.encode_child("Dimensions", &dims, ctx)?;
261
262 stream.write_start("Elements")?;
263 for item in &v.values {
264 item.encode(stream, ctx)?;
265 }
266 stream.write_end("Elements")?;
267 stream.write_end("Matrix")?;
268 return Ok(());
269 }
270 }
271 let tag_name = format!("ListOf{xml_name}");
272 stream.write_start(&tag_name)?;
273 for item in &v.values {
274 item.encode(stream, ctx)?;
275 }
276 stream.write_end(&tag_name)?;
277 }
278 }
279
280 Ok(())
281 }
282}
283
284impl XmlDecodable for Variant {
285 fn decode(
286 stream: &mut XmlStreamReader<&mut dyn std::io::Read>,
287 context: &Context<'_>,
288 ) -> Result<Self, Error> {
289 stream
290 .get_first_child(
291 |key, stream, ctx| Self::xml_decode_variant_value(stream, ctx, &key),
292 context,
293 )
294 .map(|v| v.unwrap_or(Variant::Empty))
295 }
296}