opcua_types/variant/
json.rs

1//! Utilities for JSON encoding variants.
2
3use std::io::{Cursor, Read};
4
5use crate::{
6    json::*, ByteString, DataValue, DateTime, DiagnosticInfo, EncodingResult, Error,
7    ExpandedNodeId, ExtensionObject, Guid, LocalizedText, NodeId, QualifiedName, StatusCode,
8    UAString, Variant, VariantScalarTypeId, XmlElement,
9};
10
11impl Variant {
12    /// JSON serialize the value of a variant using OPC-UA JSON encoding.
13    ///
14    /// Note that this serializes just the _value_. To include the type ID,
15    /// use [`JsonEncodable::encode`].
16    pub fn serialize_variant_value(
17        &self,
18        stream: &mut JsonStreamWriter<&mut dyn std::io::Write>,
19        ctx: &crate::Context<'_>,
20    ) -> crate::EncodingResult<()> {
21        match self {
22            Variant::Empty => stream.null_value()?,
23            Variant::Boolean(v) => JsonEncodable::encode(v, stream, ctx)?,
24            Variant::SByte(v) => JsonEncodable::encode(v, stream, ctx)?,
25            Variant::Byte(v) => JsonEncodable::encode(v, stream, ctx)?,
26            Variant::Int16(v) => JsonEncodable::encode(v, stream, ctx)?,
27            Variant::UInt16(v) => JsonEncodable::encode(v, stream, ctx)?,
28            Variant::Int32(v) => JsonEncodable::encode(v, stream, ctx)?,
29            Variant::UInt32(v) => JsonEncodable::encode(v, stream, ctx)?,
30            Variant::Int64(v) => JsonEncodable::encode(v, stream, ctx)?,
31            Variant::UInt64(v) => JsonEncodable::encode(v, stream, ctx)?,
32            Variant::Float(v) => JsonEncodable::encode(v, stream, ctx)?,
33            Variant::Double(v) => JsonEncodable::encode(v, stream, ctx)?,
34            Variant::String(v) => JsonEncodable::encode(v, stream, ctx)?,
35            Variant::DateTime(v) => JsonEncodable::encode(v, stream, ctx)?,
36            Variant::Guid(v) => JsonEncodable::encode(v, stream, ctx)?,
37            Variant::StatusCode(v) => JsonEncodable::encode(v, stream, ctx)?,
38            Variant::ByteString(v) => JsonEncodable::encode(v, stream, ctx)?,
39            Variant::XmlElement(v) => JsonEncodable::encode(v, stream, ctx)?,
40            Variant::QualifiedName(v) => JsonEncodable::encode(v, stream, ctx)?,
41            Variant::LocalizedText(v) => JsonEncodable::encode(v, stream, ctx)?,
42            Variant::NodeId(v) => JsonEncodable::encode(v, stream, ctx)?,
43            Variant::ExpandedNodeId(v) => JsonEncodable::encode(v, stream, ctx)?,
44            Variant::ExtensionObject(v) => JsonEncodable::encode(v, stream, ctx)?,
45            Variant::Variant(v) => JsonEncodable::encode(v, stream, ctx)?,
46            Variant::DataValue(v) => JsonEncodable::encode(v, stream, ctx)?,
47            Variant::DiagnosticInfo(v) => JsonEncodable::encode(v, stream, ctx)?,
48            Variant::Array(array) => {
49                // Shouldn't really happen, but there's a reasonable fallback.
50                stream.begin_array()?;
51                for v in &array.values {
52                    v.serialize_variant_value(stream, ctx)?;
53                }
54                stream.end_array()?;
55            }
56        }
57
58        Ok(())
59    }
60}
61
62impl JsonEncodable for Variant {
63    fn encode(
64        &self,
65        stream: &mut JsonStreamWriter<&mut dyn std::io::Write>,
66        ctx: &crate::Context<'_>,
67    ) -> crate::EncodingResult<()> {
68        let type_id = match self.type_id() {
69            crate::VariantTypeId::Empty => {
70                stream.null_value()?;
71                return Ok(());
72            }
73            crate::VariantTypeId::Scalar(s) => s,
74            crate::VariantTypeId::Array(s, _) => s,
75        };
76
77        stream.begin_object()?;
78
79        stream.name("Type")?;
80        stream.number_value(type_id as u32)?;
81
82        if let Variant::Array(a) = self {
83            if let Some(dims) = a.dimensions.as_ref() {
84                if dims.len() > 1 {
85                    stream.name("Dimensions")?;
86                    JsonEncodable::encode(dims, stream, ctx)?;
87                }
88            }
89            stream.name("Body")?;
90            stream.begin_array()?;
91            for v in &a.values {
92                v.serialize_variant_value(stream, ctx)?;
93            }
94            stream.end_array()?;
95        } else {
96            stream.name("Body")?;
97            self.serialize_variant_value(stream, ctx)?;
98        }
99        stream.end_object()?;
100
101        Ok(())
102    }
103}
104
105enum VariantOrArray {
106    Single(Variant),
107    Array(Vec<Variant>),
108}
109
110impl JsonDecodable for Variant {
111    fn decode(
112        stream: &mut JsonStreamReader<&mut dyn std::io::Read>,
113        ctx: &Context<'_>,
114    ) -> EncodingResult<Self> {
115        if stream.peek()? == ValueType::Null {
116            stream.next_null()?;
117            return Ok(Self::Empty);
118        }
119
120        stream.begin_object()?;
121
122        fn dec_body<T>(
123            stream: &mut JsonStreamReader<&mut dyn std::io::Read>,
124            ctx: &Context<'_>,
125        ) -> EncodingResult<VariantOrArray>
126        where
127            T: Into<Variant> + JsonDecodable + Default,
128        {
129            match stream.peek()? {
130                ValueType::Array => {
131                    let mut res = Vec::new();
132                    stream.begin_array()?;
133                    while stream.has_next()? {
134                        res.push(T::decode(stream, ctx)?.into());
135                    }
136                    stream.end_array()?;
137                    Ok(VariantOrArray::Array(res))
138                }
139                ValueType::Null => Ok(VariantOrArray::Single(T::default().into())),
140                _ => Ok(VariantOrArray::Single(T::decode(stream, ctx)?.into())),
141            }
142        }
143
144        fn dec_body_dyn(
145            stream: &mut JsonStreamReader<&mut dyn std::io::Read>,
146            ctx: &Context<'_>,
147            type_id: VariantScalarTypeId,
148        ) -> EncodingResult<VariantOrArray> {
149            match type_id {
150                VariantScalarTypeId::Boolean => dec_body::<bool>(stream, ctx),
151                VariantScalarTypeId::SByte => dec_body::<i8>(stream, ctx),
152                VariantScalarTypeId::Byte => dec_body::<u8>(stream, ctx),
153                VariantScalarTypeId::Int16 => dec_body::<i16>(stream, ctx),
154                VariantScalarTypeId::UInt16 => dec_body::<u16>(stream, ctx),
155                VariantScalarTypeId::Int32 => dec_body::<i32>(stream, ctx),
156                VariantScalarTypeId::UInt32 => dec_body::<u32>(stream, ctx),
157                VariantScalarTypeId::Int64 => dec_body::<i64>(stream, ctx),
158                VariantScalarTypeId::UInt64 => dec_body::<u64>(stream, ctx),
159                VariantScalarTypeId::Float => dec_body::<f32>(stream, ctx),
160                VariantScalarTypeId::Double => dec_body::<f64>(stream, ctx),
161                VariantScalarTypeId::String => dec_body::<UAString>(stream, ctx),
162                VariantScalarTypeId::DateTime => dec_body::<DateTime>(stream, ctx),
163                VariantScalarTypeId::Guid => dec_body::<Guid>(stream, ctx),
164                VariantScalarTypeId::ByteString => dec_body::<ByteString>(stream, ctx),
165                VariantScalarTypeId::XmlElement => dec_body::<XmlElement>(stream, ctx),
166                VariantScalarTypeId::NodeId => dec_body::<NodeId>(stream, ctx),
167                VariantScalarTypeId::ExpandedNodeId => dec_body::<ExpandedNodeId>(stream, ctx),
168                VariantScalarTypeId::StatusCode => dec_body::<StatusCode>(stream, ctx),
169                VariantScalarTypeId::QualifiedName => dec_body::<QualifiedName>(stream, ctx),
170                VariantScalarTypeId::LocalizedText => dec_body::<LocalizedText>(stream, ctx),
171                VariantScalarTypeId::ExtensionObject => dec_body::<ExtensionObject>(stream, ctx),
172                VariantScalarTypeId::DataValue => dec_body::<DataValue>(stream, ctx),
173                VariantScalarTypeId::Variant => {
174                    let v = dec_body::<Variant>(stream, ctx)?;
175                    // Only place where Into isn't sufficient. Add a layer of indirection
176                    // to Single variants.
177                    match v {
178                        VariantOrArray::Single(variant) => {
179                            Ok(VariantOrArray::Single(Variant::Variant(Box::new(variant))))
180                        }
181                        VariantOrArray::Array(vec) => Ok(VariantOrArray::Array(vec)),
182                    }
183                }
184                VariantScalarTypeId::DiagnosticInfo => dec_body::<DiagnosticInfo>(stream, ctx),
185            }
186        }
187
188        let mut type_id = None;
189        let mut value = None;
190        let mut dimensions: Option<Vec<u32>> = None;
191        let mut raw_value = None;
192        while stream.has_next()? {
193            match stream.next_name()? {
194                "Type" => {
195                    let ty: u32 = stream.next_number()??;
196                    if ty != 0 {
197                        type_id = Some(VariantScalarTypeId::try_from(ty).map_err(|_| {
198                            Error::decoding(format!("Unexpected variant type: {ty}"))
199                        })?);
200                    }
201                }
202                "Body" => {
203                    if let Some(type_id) = type_id {
204                        value = Some(dec_body_dyn(stream, ctx, type_id)?);
205                    } else {
206                        raw_value = Some(consume_raw_value(stream)?);
207                    }
208                }
209                "Dimensions" => {
210                    dimensions = JsonDecodable::decode(stream, ctx)?;
211                }
212                _ => {
213                    stream.skip_value()?;
214                }
215            }
216        }
217
218        let Some(type_id) = type_id else {
219            stream.end_object()?;
220            return Ok(Variant::Empty);
221        };
222
223        if let Some(raw_value) = raw_value {
224            let mut cursor = Cursor::new(raw_value);
225            let mut inner_stream = JsonStreamReader::new(&mut cursor as &mut dyn Read);
226            value = Some(dec_body_dyn(&mut inner_stream, ctx, type_id)?);
227        }
228
229        let value = value.unwrap_or_else(|| {
230            VariantOrArray::Single(match type_id {
231                VariantScalarTypeId::Boolean => Variant::from(bool::default()),
232                VariantScalarTypeId::SByte => Variant::from(i8::default()),
233                VariantScalarTypeId::Byte => Variant::from(u8::default()),
234                VariantScalarTypeId::Int16 => Variant::from(i16::default()),
235                VariantScalarTypeId::UInt16 => Variant::from(u16::default()),
236                VariantScalarTypeId::Int32 => Variant::from(i32::default()),
237                VariantScalarTypeId::UInt32 => Variant::from(u32::default()),
238                VariantScalarTypeId::Int64 => Variant::from(i64::default()),
239                VariantScalarTypeId::UInt64 => Variant::from(u64::default()),
240                VariantScalarTypeId::Float => Variant::from(f32::default()),
241                VariantScalarTypeId::Double => Variant::from(f64::default()),
242                VariantScalarTypeId::String => Variant::from(UAString::default()),
243                VariantScalarTypeId::DateTime => Variant::from(DateTime::default()),
244                VariantScalarTypeId::Guid => Variant::from(Guid::default()),
245                VariantScalarTypeId::ByteString => Variant::from(ByteString::default()),
246                VariantScalarTypeId::XmlElement => Variant::from(XmlElement::default()),
247                VariantScalarTypeId::NodeId => Variant::from(NodeId::default()),
248                VariantScalarTypeId::ExpandedNodeId => Variant::from(ExpandedNodeId::default()),
249                VariantScalarTypeId::StatusCode => Variant::from(StatusCode::default()),
250                VariantScalarTypeId::QualifiedName => Variant::from(QualifiedName::default()),
251                VariantScalarTypeId::LocalizedText => Variant::from(LocalizedText::default()),
252                VariantScalarTypeId::ExtensionObject => Variant::from(ExtensionObject::default()),
253                VariantScalarTypeId::DataValue => Variant::from(DataValue::default()),
254                VariantScalarTypeId::Variant => Variant::Variant(Box::default()),
255                VariantScalarTypeId::DiagnosticInfo => Variant::from(DiagnosticInfo::default()),
256            })
257        });
258
259        let variant = match (value, dimensions) {
260            (VariantOrArray::Single(variant), None) => variant,
261            (VariantOrArray::Single(_), Some(_)) => {
262                return Err(Error::decoding(
263                    "Unexpected dimensions for scalar variant value during json decoding",
264                ));
265            }
266            (VariantOrArray::Array(vec), d) => Variant::Array(Box::new(crate::Array {
267                value_type: type_id,
268                values: vec,
269                dimensions: d,
270            })),
271        };
272
273        stream.end_object()?;
274
275        Ok(variant)
276    }
277}