opcua_types/
json.rs

1//! Enabled with the "json" feature.
2//!
3//! Core utilities for JSON encoding and decoding from OPC-UA JSON.
4
5use std::io::{Cursor, Read, Write};
6
7pub use crate::Context;
8use struson::writer::JsonNumberError;
9pub use struson::{
10    json_path,
11    reader::{JsonReader, JsonStreamReader, ValueType},
12    writer::{JsonStreamWriter, JsonWriter},
13};
14
15use crate::{EncodingResult, Error, UaNullable};
16
17/// Trait for OPC-UA json encoding.
18pub trait JsonEncodable: UaNullable {
19    #[allow(unused)]
20    /// Write the type to the provided JSON writer.
21    fn encode(
22        &self,
23        stream: &mut JsonStreamWriter<&mut dyn Write>,
24        ctx: &crate::Context<'_>,
25    ) -> EncodingResult<()>;
26}
27
28impl From<struson::reader::ReaderError> for Error {
29    fn from(value: struson::reader::ReaderError) -> Self {
30        Self::decoding(value)
31    }
32}
33
34impl From<JsonNumberError> for Error {
35    fn from(value: JsonNumberError) -> Self {
36        Self::encoding(value)
37    }
38}
39
40impl From<struson::reader::TransferError> for Error {
41    fn from(value: struson::reader::TransferError) -> Self {
42        Self::decoding(value)
43    }
44}
45
46/// Trait for decoding a type from a JSON stream.
47pub trait JsonDecodable: Sized {
48    #[allow(unused)]
49    /// Decode Self from a JSON stream.
50    fn decode(
51        stream: &mut JsonStreamReader<&mut dyn Read>,
52        ctx: &Context<'_>,
53    ) -> EncodingResult<Self>;
54}
55
56impl<T> JsonEncodable for Option<T>
57where
58    T: JsonEncodable,
59{
60    fn encode(
61        &self,
62        stream: &mut JsonStreamWriter<&mut dyn Write>,
63        ctx: &crate::Context<'_>,
64    ) -> EncodingResult<()> {
65        match self {
66            Some(s) => s.encode(stream, ctx),
67            None => Ok(stream.null_value()?),
68        }
69    }
70}
71
72impl<T> JsonDecodable for Option<T>
73where
74    T: JsonDecodable,
75{
76    fn decode(
77        stream: &mut JsonStreamReader<&mut dyn Read>,
78        ctx: &Context<'_>,
79    ) -> EncodingResult<Self> {
80        match stream.peek()? {
81            ValueType::Null => {
82                stream.next_null()?;
83                Ok(None)
84            }
85            _ => Ok(Some(T::decode(stream, ctx)?)),
86        }
87    }
88}
89
90impl<T> JsonEncodable for Vec<T>
91where
92    T: JsonEncodable,
93{
94    fn encode(
95        &self,
96        stream: &mut JsonStreamWriter<&mut dyn Write>,
97        ctx: &crate::Context<'_>,
98    ) -> EncodingResult<()> {
99        stream.begin_array()?;
100        for elem in self {
101            elem.encode(stream, ctx)?;
102        }
103        stream.end_array()?;
104        Ok(())
105    }
106}
107
108impl<T> JsonDecodable for Vec<T>
109where
110    T: JsonDecodable,
111{
112    fn decode(
113        stream: &mut JsonStreamReader<&mut dyn Read>,
114        ctx: &Context<'_>,
115    ) -> EncodingResult<Self> {
116        if stream.peek()? == ValueType::Null {
117            stream.next_null()?;
118            return Ok(Vec::new());
119        }
120
121        let mut res = Vec::new();
122        stream.begin_array()?;
123        while stream.has_next()? {
124            res.push(T::decode(stream, ctx)?);
125        }
126        stream.end_array()?;
127
128        Ok(res)
129    }
130}
131
132impl<T> JsonEncodable for Box<T>
133where
134    T: JsonEncodable,
135{
136    fn encode(
137        &self,
138        stream: &mut JsonStreamWriter<&mut dyn Write>,
139        ctx: &crate::Context<'_>,
140    ) -> EncodingResult<()> {
141        T::encode(self, stream, ctx)
142    }
143}
144
145impl<T> JsonDecodable for Box<T>
146where
147    T: JsonDecodable,
148{
149    fn decode(
150        stream: &mut JsonStreamReader<&mut dyn Read>,
151        ctx: &Context<'_>,
152    ) -> EncodingResult<Self> {
153        Ok(Box::new(T::decode(stream, ctx)?))
154    }
155}
156
157const VALUE_INFINITY: &str = "Infinity";
158const VALUE_NEG_INFINITY: &str = "-Infinity";
159const VALUE_NAN: &str = "NaN";
160
161macro_rules! json_enc_float {
162    ($t:ty) => {
163        impl JsonEncodable for $t {
164            fn encode(
165                &self,
166                stream: &mut JsonStreamWriter<&mut dyn Write>,
167                _ctx: &crate::Context<'_>,
168            ) -> EncodingResult<()> {
169                if self.is_infinite() {
170                    if self.is_sign_positive() {
171                        stream.string_value(VALUE_INFINITY)?;
172                    } else {
173                        stream.string_value(VALUE_NEG_INFINITY)?;
174                    }
175                } else if self.is_nan() {
176                    stream.string_value(VALUE_NAN)?;
177                } else {
178                    stream.fp_number_value(*self)?;
179                }
180
181                Ok(())
182            }
183        }
184
185        impl JsonDecodable for $t {
186            fn decode(
187                stream: &mut JsonStreamReader<&mut dyn Read>,
188                _ctx: &Context<'_>,
189            ) -> EncodingResult<Self> {
190                if stream.peek()? == ValueType::String {
191                    let v = stream.next_str()?;
192                    match v {
193                        VALUE_INFINITY => Ok(Self::INFINITY),
194                        VALUE_NEG_INFINITY => Ok(Self::NEG_INFINITY),
195                        VALUE_NAN => Ok(Self::NAN),
196                        // Not technically spec, but to optimize interoperability, try to
197                        // parse the number as a float
198                        r => Ok(r.parse()?),
199                    }
200                } else {
201                    Ok(stream.next_number()??)
202                }
203            }
204        }
205    };
206}
207
208macro_rules! json_enc_number {
209    ($t:ty) => {
210        impl JsonEncodable for $t {
211            fn encode(
212                &self,
213                stream: &mut JsonStreamWriter<&mut dyn Write>,
214                _ctx: &crate::Context<'_>,
215            ) -> EncodingResult<()> {
216                stream.number_value(*self)?;
217                Ok(())
218            }
219        }
220
221        impl JsonDecodable for $t {
222            fn decode(
223                stream: &mut JsonStreamReader<&mut dyn Read>,
224                _ctx: &Context<'_>,
225            ) -> EncodingResult<Self> {
226                Ok(stream.next_number()??)
227            }
228        }
229    };
230}
231
232json_enc_number!(u8);
233json_enc_number!(u16);
234json_enc_number!(u32);
235json_enc_number!(u64);
236json_enc_number!(i8);
237json_enc_number!(i16);
238json_enc_number!(i32);
239json_enc_number!(i64);
240json_enc_float!(f32);
241json_enc_float!(f64);
242
243impl JsonEncodable for String {
244    fn encode(
245        &self,
246        stream: &mut JsonStreamWriter<&mut dyn Write>,
247        _ctx: &crate::Context<'_>,
248    ) -> EncodingResult<()> {
249        stream.string_value(self.as_str())?;
250        Ok(())
251    }
252}
253
254impl JsonDecodable for String {
255    fn decode(
256        stream: &mut JsonStreamReader<&mut dyn Read>,
257        _ctx: &Context<'_>,
258    ) -> EncodingResult<Self> {
259        Ok(stream.next_string()?)
260    }
261}
262
263impl JsonEncodable for bool {
264    fn encode(
265        &self,
266        stream: &mut JsonStreamWriter<&mut dyn Write>,
267        _ctx: &crate::Context<'_>,
268    ) -> EncodingResult<()> {
269        stream.bool_value(*self)?;
270        Ok(())
271    }
272}
273
274impl JsonDecodable for bool {
275    fn decode(
276        stream: &mut JsonStreamReader<&mut dyn Read>,
277        _ctx: &Context<'_>,
278    ) -> EncodingResult<Self> {
279        Ok(stream.next_bool()?)
280    }
281}
282
283/// Utility method used in unions to consume a JSON value from the stream,
284/// and return it as a vector that can be parsed later.
285pub fn consume_raw_value(
286    r: &mut JsonStreamReader<&mut dyn std::io::Read>,
287) -> EncodingResult<Vec<u8>> {
288    let mut res = Vec::new();
289    let cursor = Cursor::new(&mut res);
290    let mut writer = JsonStreamWriter::new(cursor);
291    r.transfer_to(&mut writer)?;
292    writer.finish_document()?;
293    Ok(res)
294}
295
296/// Utility method to write a stream of raw JSON bytes to the stream.
297pub fn write_raw_value(
298    data: &[u8],
299    r: &mut JsonStreamWriter<&mut dyn std::io::Write>,
300) -> EncodingResult<()> {
301    let cursor = Cursor::new(data);
302    let mut reader = JsonStreamReader::new(cursor);
303    reader.transfer_to(r)?;
304    Ok(())
305}