opcua_types/type_loader/
fallback.rs

1//! Implementation of a type loader that simply extracts the raw binary data.
2
3use crate::{
4    BinaryEncodable, ByteString, Error, ExpandedMessageInfo, ExpandedNodeId, NodeId, UaNullable,
5};
6
7use super::TypeLoader;
8
9/// Type loader that accepts any type, and simply returns one of
10/// [ByteStringBody], [JsonBody], or [XmlBody]
11pub struct FallbackTypeLoader;
12
13impl TypeLoader for FallbackTypeLoader {
14    #[cfg(feature = "xml")]
15    fn load_from_xml(
16        &self,
17        node_id: &crate::NodeId,
18        stream: &mut crate::xml::XmlStreamReader<&mut dyn std::io::Read>,
19        _ctx: &super::Context<'_>,
20        name: &str,
21    ) -> Option<crate::EncodingResult<Box<dyn crate::DynEncodable>>> {
22        let raw = match stream.consume_raw() {
23            Ok(v) => v,
24            Err(e) => return Some(Err(e.into())),
25        };
26        Some(Ok(Box::new(XmlBody {
27            raw,
28            encoding_id: node_id.clone(),
29            tag_name: name.to_owned(),
30        })))
31    }
32
33    #[cfg(feature = "json")]
34    fn load_from_json(
35        &self,
36        node_id: &crate::NodeId,
37        stream: &mut crate::json::JsonStreamReader<&mut dyn std::io::Read>,
38        _ctx: &super::Context<'_>,
39    ) -> Option<crate::EncodingResult<Box<dyn crate::DynEncodable>>> {
40        use crate::json::consume_raw_value;
41
42        let raw = match consume_raw_value(stream) {
43            Ok(v) => v,
44            Err(e) => return Some(Err(e)),
45        };
46        Some(Ok(Box::new(JsonBody {
47            raw,
48            encoding_id: node_id.clone(),
49        })))
50    }
51
52    fn load_from_binary(
53        &self,
54        node_id: &NodeId,
55        stream: &mut dyn std::io::Read,
56        _ctx: &super::Context<'_>,
57        length: Option<usize>,
58    ) -> Option<crate::EncodingResult<Box<dyn crate::DynEncodable>>> {
59        // If the length is unknown, there really isn't a lot we can do.
60        let length = length?;
61        let mut buf = vec![0u8; length];
62        if let Err(e) = stream.read_exact(&mut buf) {
63            return Some(Err(e.into()));
64        }
65        Some(Ok(Box::new(ByteStringBody {
66            raw: ByteString::from(buf),
67            encoding_id: node_id.clone(),
68        })))
69    }
70
71    fn priority(&self) -> super::TypeLoaderPriority {
72        super::TypeLoaderPriority::Fallback
73    }
74}
75
76/// A fallback value for an [ExtensionObject](crate::ExtensionObject) body
77/// originally encoded as a [ByteString].
78#[derive(Debug, PartialEq, Clone)]
79pub struct ByteStringBody {
80    raw: ByteString,
81    encoding_id: NodeId,
82}
83
84impl ByteStringBody {
85    /// Create a new ByteStringBody with the given raw data and encoding ID.
86    pub fn new(raw: ByteString, encoding_id: NodeId) -> Self {
87        Self { raw, encoding_id }
88    }
89
90    /// Get the raw XML body as a sequence of bytes.
91    pub fn raw_body(&self) -> &ByteString {
92        &self.raw
93    }
94
95    /// Consume the ByteStringBody and return the raw body as a sequence of bytes.
96    pub fn into_raw(self) -> ByteString {
97        self.raw
98    }
99
100    /// Get the encoding ID of this object.
101    pub fn encoding_id(&self) -> &NodeId {
102        &self.encoding_id
103    }
104}
105
106impl BinaryEncodable for ByteStringBody {
107    fn byte_len(&self, _ctx: &crate::Context<'_>) -> usize {
108        self.raw.len()
109    }
110
111    fn encode<S: std::io::Write + ?Sized>(
112        &self,
113        stream: &mut S,
114        _ctx: &super::Context<'_>,
115    ) -> crate::EncodingResult<()> {
116        Ok(stream.write_all(self.raw.as_ref())?)
117    }
118
119    fn override_encoding(&self) -> Option<crate::BuiltInDataEncoding> {
120        Some(crate::BuiltInDataEncoding::Binary)
121    }
122}
123
124// We always just return the raw node ID here. There really isn't much alternative. In practice what we need to
125// do is just serialize the value back in its raw form, which may or may not be possible.
126impl ExpandedMessageInfo for ByteStringBody {
127    fn full_data_type_id(&self) -> crate::ExpandedNodeId {
128        ExpandedNodeId::new(self.encoding_id.clone())
129    }
130
131    fn full_json_type_id(&self) -> ExpandedNodeId {
132        ExpandedNodeId::new(self.encoding_id.clone())
133    }
134
135    fn full_type_id(&self) -> ExpandedNodeId {
136        ExpandedNodeId::new(self.encoding_id.clone())
137    }
138
139    fn full_xml_type_id(&self) -> ExpandedNodeId {
140        ExpandedNodeId::new(self.encoding_id.clone())
141    }
142}
143
144impl UaNullable for ByteStringBody {
145    fn is_ua_null(&self) -> bool {
146        self.raw.is_null()
147    }
148}
149
150/// A fallback value for an [ExtensionObject](crate::ExtensionObject) body
151/// originally encoded as a JSON object.
152#[derive(Debug, PartialEq, Clone)]
153pub struct JsonBody {
154    raw: Vec<u8>,
155    encoding_id: NodeId,
156}
157
158impl JsonBody {
159    /// Create a new JsonBody with the given raw data and encoding ID.
160    pub fn new(raw: Vec<u8>, encoding_id: NodeId) -> Self {
161        Self { raw, encoding_id }
162    }
163
164    /// Get the raw XML body as a sequence of bytes.
165    pub fn raw_body(&self) -> &[u8] {
166        &self.raw
167    }
168
169    /// Consume the JsonBody and return the raw body as a sequence of bytes.
170    pub fn into_raw(self) -> Vec<u8> {
171        self.raw
172    }
173
174    /// Get the encoding ID of this object.
175    pub fn encoding_id(&self) -> &NodeId {
176        &self.encoding_id
177    }
178}
179
180impl BinaryEncodable for JsonBody {
181    fn byte_len(&self, _ctx: &crate::Context<'_>) -> usize {
182        0
183    }
184
185    fn encode<S: std::io::Write + ?Sized>(
186        &self,
187        _stream: &mut S,
188        _ctx: &super::Context<'_>,
189    ) -> crate::EncodingResult<()> {
190        // This just isn't supported by the standard.
191        Err(Error::encoding(
192            "Cannot encode a raw json body as a binary ExtensionObject body",
193        ))
194    }
195
196    fn override_encoding(&self) -> Option<crate::BuiltInDataEncoding> {
197        Some(crate::BuiltInDataEncoding::JSON)
198    }
199}
200
201impl ExpandedMessageInfo for JsonBody {
202    fn full_data_type_id(&self) -> crate::ExpandedNodeId {
203        ExpandedNodeId::new(self.encoding_id.clone())
204    }
205
206    fn full_json_type_id(&self) -> ExpandedNodeId {
207        ExpandedNodeId::new(self.encoding_id.clone())
208    }
209
210    fn full_type_id(&self) -> ExpandedNodeId {
211        ExpandedNodeId::new(self.encoding_id.clone())
212    }
213
214    fn full_xml_type_id(&self) -> ExpandedNodeId {
215        ExpandedNodeId::new(self.encoding_id.clone())
216    }
217}
218
219impl UaNullable for JsonBody {
220    fn is_ua_null(&self) -> bool {
221        self.raw.is_empty()
222    }
223}
224
225/// A fallback value for an [ExtensionObject](crate::ExtensionObject) body
226/// originally encoded as an XML structure.
227#[derive(Debug, PartialEq, Clone)]
228pub struct XmlBody {
229    raw: Vec<u8>,
230    encoding_id: NodeId,
231    tag_name: String,
232}
233
234impl XmlBody {
235    /// Create a new XmlBody with the given raw data and encoding ID.
236    pub fn new(raw: Vec<u8>, encoding_id: NodeId, tag_name: String) -> Self {
237        Self {
238            raw,
239            encoding_id,
240            tag_name,
241        }
242    }
243
244    /// Get the raw XML body as a sequence of bytes.
245    pub fn raw_body(&self) -> &[u8] {
246        &self.raw
247    }
248
249    /// Consume the XmlBody and return the raw body as a sequence of bytes.
250    pub fn into_raw(self) -> Vec<u8> {
251        self.raw
252    }
253
254    /// Get the encoding ID of this object.
255    pub fn encoding_id(&self) -> &NodeId {
256        &self.encoding_id
257    }
258}
259
260impl BinaryEncodable for XmlBody {
261    fn byte_len(&self, _ctx: &crate::Context<'_>) -> usize {
262        self.raw.len()
263    }
264
265    fn encode<S: std::io::Write + ?Sized>(
266        &self,
267        stream: &mut S,
268        _ctx: &super::Context<'_>,
269    ) -> crate::EncodingResult<()> {
270        stream.write_all(&self.raw)?;
271        Ok(())
272    }
273
274    fn override_encoding(&self) -> Option<crate::BuiltInDataEncoding> {
275        Some(crate::BuiltInDataEncoding::XML)
276    }
277}
278
279impl ExpandedMessageInfo for XmlBody {
280    fn full_data_type_id(&self) -> crate::ExpandedNodeId {
281        ExpandedNodeId::new(self.encoding_id.clone())
282    }
283
284    fn full_json_type_id(&self) -> ExpandedNodeId {
285        ExpandedNodeId::new(self.encoding_id.clone())
286    }
287
288    fn full_type_id(&self) -> ExpandedNodeId {
289        ExpandedNodeId::new(self.encoding_id.clone())
290    }
291
292    fn full_xml_type_id(&self) -> ExpandedNodeId {
293        ExpandedNodeId::new(self.encoding_id.clone())
294    }
295}
296
297impl UaNullable for XmlBody {
298    fn is_ua_null(&self) -> bool {
299        self.raw.is_empty()
300    }
301}
302
303#[cfg(feature = "json")]
304mod json {
305    use crate::json::*;
306
307    use super::{ByteStringBody, JsonBody, XmlBody};
308
309    impl JsonEncodable for ByteStringBody {
310        fn encode(
311            &self,
312            stream: &mut struson::writer::JsonStreamWriter<&mut dyn std::io::Write>,
313            _ctx: &crate::Context<'_>,
314        ) -> crate::EncodingResult<()> {
315            stream.string_value(&self.raw.as_base64())?;
316            Ok(())
317        }
318    }
319
320    impl JsonEncodable for JsonBody {
321        fn encode(
322            &self,
323            stream: &mut JsonStreamWriter<&mut dyn std::io::Write>,
324            _ctx: &crate::Context<'_>,
325        ) -> crate::EncodingResult<()> {
326            write_raw_value(&self.raw, stream)?;
327            Ok(())
328        }
329    }
330
331    impl JsonEncodable for XmlBody {
332        fn encode(
333            &self,
334            stream: &mut JsonStreamWriter<&mut dyn std::io::Write>,
335            _ctx: &crate::Context<'_>,
336        ) -> crate::EncodingResult<()> {
337            stream.string_value(&String::from_utf8_lossy(&self.raw))?;
338            Ok(())
339        }
340    }
341}
342
343#[cfg(feature = "xml")]
344mod xml {
345    use crate::{
346        xml::{XmlEncodable, XmlType},
347        Error,
348    };
349
350    use super::{ByteStringBody, JsonBody, XmlBody};
351
352    impl XmlType for ByteStringBody {
353        const TAG: &'static str = "ByteString";
354    }
355
356    impl XmlEncodable for ByteStringBody {
357        fn encode(
358            &self,
359            writer: &mut opcua_xml::XmlStreamWriter<&mut dyn std::io::Write>,
360            _context: &crate::Context<'_>,
361        ) -> crate::EncodingResult<()> {
362            writer.write_text(&self.raw.as_base64())?;
363            Ok(())
364        }
365    }
366
367    impl XmlType for JsonBody {
368        const TAG: &'static str = "JsonElement"; // Just need something here, as a placeholder.
369    }
370
371    impl XmlEncodable for JsonBody {
372        fn encode(
373            &self,
374            _writer: &mut opcua_xml::XmlStreamWriter<&mut dyn std::io::Write>,
375            _context: &crate::Context<'_>,
376        ) -> crate::EncodingResult<()> {
377            // This just isn't supported by the standard.
378            Err(Error::encoding(
379                "Cannot encode a raw json body as an XML ExtensionObject body",
380            ))
381        }
382    }
383
384    impl XmlType for XmlBody {
385        const TAG: &'static str = "XmlElement";
386        fn tag(&self) -> &str {
387            &self.tag_name
388        }
389    }
390
391    impl XmlEncodable for XmlBody {
392        fn encode(
393            &self,
394            writer: &mut opcua_xml::XmlStreamWriter<&mut dyn std::io::Write>,
395            _context: &crate::Context<'_>,
396        ) -> crate::EncodingResult<()> {
397            writer.write_raw(&self.raw)?;
398            Ok(())
399        }
400    }
401}