opcua_types/
extension_object.rs1use std::{
8 error::Error,
9 fmt,
10 io::{Cursor, Read, Write},
11};
12
13use crate::{
14 byte_string::ByteString, encoding::*, node_id::NodeId, node_ids::ObjectId,
15 status_codes::StatusCode, string::XmlElement,
16};
17
18#[derive(Debug)]
19pub struct ExtensionObjectError;
20
21impl fmt::Display for ExtensionObjectError {
22 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23 write!(f, "ExtensionObjectError")
24 }
25}
26
27impl Error for ExtensionObjectError {}
28
29#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
31pub enum ExtensionObjectEncoding {
32 None,
34 ByteString(ByteString),
36 XmlElement(XmlElement),
38}
39
40#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
42pub struct ExtensionObject {
43 pub node_id: NodeId,
44 pub body: ExtensionObjectEncoding,
45}
46
47impl BinaryEncoder<ExtensionObject> for ExtensionObject {
48 fn byte_len(&self) -> usize {
49 let mut size = self.node_id.byte_len();
50 size += match self.body {
51 ExtensionObjectEncoding::None => 1,
52 ExtensionObjectEncoding::ByteString(ref value) => {
53 1 + value.byte_len()
55 }
56 ExtensionObjectEncoding::XmlElement(ref value) => {
57 1 + value.byte_len()
59 }
60 };
61 size
62 }
63
64 fn encode<S: Write>(&self, stream: &mut S) -> EncodingResult<usize> {
65 let mut size = 0;
66 size += self.node_id.encode(stream)?;
67 match self.body {
68 ExtensionObjectEncoding::None => {
69 size += write_u8(stream, 0x0)?;
70 }
71 ExtensionObjectEncoding::ByteString(ref value) => {
72 size += write_u8(stream, 0x1)?;
74 size += value.encode(stream)?;
75 }
76 ExtensionObjectEncoding::XmlElement(ref value) => {
77 size += write_u8(stream, 0x2)?;
79 size += value.encode(stream)?;
80 }
81 }
82 assert_eq!(size, self.byte_len());
83 Ok(size)
84 }
85
86 fn decode<S: Read>(stream: &mut S, decoding_options: &DecodingOptions) -> EncodingResult<Self> {
87 let node_id = NodeId::decode(stream, decoding_options)?;
88 let encoding_type = u8::decode(stream, decoding_options)?;
89 let body = match encoding_type {
90 0x0 => ExtensionObjectEncoding::None,
91 0x1 => {
92 ExtensionObjectEncoding::ByteString(ByteString::decode(stream, decoding_options)?)
93 }
94 0x2 => {
95 ExtensionObjectEncoding::XmlElement(XmlElement::decode(stream, decoding_options)?)
96 }
97 _ => {
98 error!("Invalid encoding type {} in stream", encoding_type);
99 return Err(StatusCode::BadDecodingError);
100 }
101 };
102 Ok(ExtensionObject { node_id, body })
103 }
104}
105
106impl ExtensionObject {
107 pub fn null() -> ExtensionObject {
109 ExtensionObject {
110 node_id: NodeId::null(),
111 body: ExtensionObjectEncoding::None,
112 }
113 }
114
115 pub fn is_null(&self) -> bool {
117 self.node_id.is_null()
118 }
119
120 pub fn is_empty(&self) -> bool {
122 self.is_null() || matches!(self.body, ExtensionObjectEncoding::None)
123 }
124
125 pub fn object_id(&self) -> Result<ObjectId, ExtensionObjectError> {
128 self.node_id
129 .as_object_id()
130 .map_err(|_| ExtensionObjectError)
131 }
132
133 pub fn from_encodable<N, T>(node_id: N, encodable: &T) -> ExtensionObject
136 where
137 N: Into<NodeId>,
138 T: BinaryEncoder<T>,
139 {
140 let mut stream = Cursor::new(vec![0u8; encodable.byte_len()]);
142 let _ = encodable.encode(&mut stream);
143 ExtensionObject {
144 node_id: node_id.into(),
145 body: ExtensionObjectEncoding::ByteString(ByteString::from(stream.into_inner())),
146 }
147 }
148
149 pub fn decode_inner<T>(&self, decoding_options: &DecodingOptions) -> EncodingResult<T>
153 where
154 T: BinaryEncoder<T>,
155 {
156 match self.body {
157 ExtensionObjectEncoding::ByteString(ref byte_string) => {
158 if let Some(ref value) = byte_string.value {
159 let mut stream = Cursor::new(value);
161 T::decode(&mut stream, decoding_options)
162 } else {
163 Err(StatusCode::BadDecodingError)
164 }
165 }
166 _ => {
167 error!("decode_inner called on an unsupported ExtensionObject type");
168 Err(StatusCode::BadDecodingError)
169 }
170 }
171 }
172}