opcua_types/
byte_string.rs1use std::{
8 convert::TryFrom,
9 io::{Read, Write},
10};
11
12use base64::{engine::general_purpose::STANDARD, Engine};
13
14use crate::{
15 encoding::{process_decode_io_result, process_encode_io_result, write_i32, EncodingResult},
16 read_i32, DecodingOptions, Error, Guid, OutOfRange, SimpleBinaryDecodable,
17 SimpleBinaryEncodable, UaNullable,
18};
19
20#[derive(Eq, PartialEq, Debug, Clone, Hash)]
22pub struct ByteString {
23 pub value: Option<Vec<u8>>,
25}
26
27impl AsRef<[u8]> for ByteString {
28 fn as_ref(&self) -> &[u8] {
29 match self.value.as_ref() {
30 Some(v) => v.as_slice(),
31 None => &[],
32 }
33 }
34}
35
36impl PartialEq<&[u8]> for ByteString {
37 fn eq(&self, other: &&[u8]) -> bool {
38 self.as_ref() == *other
39 }
40}
41
42impl PartialEq<[u8]> for ByteString {
43 fn eq(&self, other: &[u8]) -> bool {
44 self.as_ref() == other
45 }
46}
47
48impl UaNullable for ByteString {
49 fn is_ua_null(&self) -> bool {
50 self.is_null()
51 }
52}
53
54#[cfg(feature = "json")]
55mod json {
56 use std::io::{Read, Write};
57
58 use crate::{json::*, Error};
59
60 use super::ByteString;
61
62 impl JsonEncodable for ByteString {
63 fn encode(
64 &self,
65 stream: &mut JsonStreamWriter<&mut dyn Write>,
66 _ctx: &crate::json::Context<'_>,
67 ) -> crate::EncodingResult<()> {
68 if self.value.is_some() {
69 stream.string_value(&self.as_base64())?;
70 } else {
71 stream.null_value()?;
72 }
73 Ok(())
74 }
75 }
76
77 impl JsonDecodable for ByteString {
78 fn decode(
79 stream: &mut JsonStreamReader<&mut dyn Read>,
80 _ctx: &Context<'_>,
81 ) -> crate::EncodingResult<Self> {
82 match stream.peek()? {
83 ValueType::String => Ok(Self::from_base64_ignore_whitespace(stream.next_string()?)
84 .ok_or_else(|| Error::decoding("Cannot decode base64 bytestring"))?),
85 _ => {
86 stream.next_null()?;
87 Ok(Self::null())
88 }
89 }
90 }
91 }
92}
93
94#[cfg(feature = "xml")]
95mod xml {
96 use crate::xml::*;
97 use std::io::{Read, Write};
98
99 use super::ByteString;
100
101 impl XmlType for ByteString {
102 const TAG: &'static str = "ByteString";
103 }
104
105 impl XmlEncodable for ByteString {
106 fn encode(
107 &self,
108 writer: &mut XmlStreamWriter<&mut dyn Write>,
109 _context: &Context<'_>,
110 ) -> EncodingResult<()> {
111 if self.value.is_some() {
112 writer.write_text(&self.as_base64())?;
113 }
114 Ok(())
115 }
116 }
117
118 impl XmlDecodable for ByteString {
119 fn decode(
120 read: &mut XmlStreamReader<&mut dyn Read>,
121 _context: &Context<'_>,
122 ) -> Result<Self, Error> {
123 let s = read.consume_as_text()?;
124 if s.is_empty() {
125 Ok(ByteString::null())
126 } else {
127 Ok(ByteString::from_base64_ignore_whitespace(s)
128 .ok_or_else(|| Error::decoding("Cannot decode base64 bytestring"))?)
129 }
130 }
131 }
132}
133
134impl SimpleBinaryEncodable for ByteString {
135 fn byte_len(&self) -> usize {
136 4 + match &self.value {
138 Some(v) => v.len(),
139 None => 0,
140 }
141 }
142
143 fn encode<S: Write + ?Sized>(&self, stream: &mut S) -> EncodingResult<()> {
144 if let Some(value) = &self.value {
146 write_i32(stream, value.len() as i32)?;
147 process_encode_io_result(stream.write_all(value))
148 } else {
149 write_i32(stream, -1)
150 }
151 }
152}
153
154impl SimpleBinaryDecodable for ByteString {
155 fn decode<S: Read + ?Sized>(
156 stream: &mut S,
157 decoding_options: &DecodingOptions,
158 ) -> EncodingResult<Self> {
159 let len = read_i32(stream)?;
160 if len == -1 {
162 Ok(ByteString::null())
163 } else if len < -1 {
164 Err(Error::decoding(format!(
165 "ByteString buf length is a negative number {len}"
166 )))
167 } else if len as usize > decoding_options.max_byte_string_length {
168 Err(Error::decoding(format!(
169 "ByteString length {} exceeds decoding limit {}",
170 len, decoding_options.max_byte_string_length
171 )))
172 } else {
173 let mut buf: Vec<u8> = vec![0u8; len as usize];
175 process_decode_io_result(stream.read_exact(&mut buf))?;
176 Ok(ByteString { value: Some(buf) })
177 }
178 }
179}
180
181impl<'a, T> From<&'a T> for ByteString
182where
183 T: AsRef<[u8]> + ?Sized,
184{
185 fn from(value: &'a T) -> Self {
186 Self::from(value.as_ref().to_vec())
187 }
188}
189
190impl From<Vec<u8>> for ByteString {
191 fn from(value: Vec<u8>) -> Self {
192 ByteString { value: Some(value) }
194 }
195}
196
197impl From<Guid> for ByteString {
198 fn from(value: Guid) -> Self {
199 ByteString::from(value.as_bytes().to_vec())
200 }
201}
202
203impl TryFrom<&ByteString> for Guid {
204 type Error = ();
205
206 fn try_from(value: &ByteString) -> Result<Self, Self::Error> {
207 if value.is_null_or_empty() {
208 Err(())
209 } else {
210 let bytes = value.as_ref();
211 if bytes.len() != 16 {
212 Err(())
213 } else {
214 let mut guid = [0u8; 16];
215 guid.copy_from_slice(bytes);
216 Ok(Guid::from_bytes(guid))
217 }
218 }
219 }
220}
221
222impl From<ByteString> for String {
223 fn from(value: ByteString) -> Self {
224 value.as_base64()
225 }
226}
227
228impl Default for ByteString {
229 fn default() -> Self {
230 ByteString::null()
231 }
232}
233
234impl ByteString {
235 pub fn null() -> ByteString {
237 ByteString { value: None }
238 }
239
240 pub fn is_null(&self) -> bool {
242 self.value.is_none()
243 }
244
245 pub fn is_empty(&self) -> bool {
247 if let Some(v) = &self.value {
248 v.is_empty()
249 } else {
250 false
251 }
252 }
253
254 pub fn is_null_or_empty(&self) -> bool {
256 self.is_null() || self.is_empty()
257 }
258
259 pub fn from_base64(data: &str) -> Option<ByteString> {
261 if let Ok(bytes) = STANDARD.decode(data) {
262 Some(Self::from(bytes))
263 } else {
264 None
265 }
266 }
267
268 pub fn from_base64_ignore_whitespace(mut data: String) -> Option<ByteString> {
270 data.retain(|c| !c.is_whitespace());
271 if let Ok(bytes) = STANDARD.decode(&data) {
272 Some(Self::from(bytes))
273 } else {
274 None
275 }
276 }
277
278 pub fn as_base64(&self) -> String {
280 if let Some(ref value) = self.value {
282 STANDARD.encode(value)
283 } else {
284 STANDARD.encode("")
285 }
286 }
287
288 pub fn substring(&self, min: usize, max: usize) -> Result<ByteString, OutOfRange> {
293 if let Some(ref v) = self.value {
294 if min >= v.len() {
295 Err(OutOfRange)
296 } else {
297 let max = if max >= v.len() { v.len() - 1 } else { max };
298 let v = v[min..=max].to_vec();
299 Ok(ByteString::from(v))
300 }
301 } else {
302 Err(OutOfRange)
303 }
304 }
305
306 pub fn len(&self) -> usize {
308 if let Some(ref v) = self.value {
309 v.len()
310 } else {
311 0
312 }
313 }
314}
315
316#[test]
317fn bytestring_null() {
318 let v = ByteString::null();
319 assert!(v.is_null());
320}
321
322#[test]
323fn bytestring_empty() {
324 let v = ByteString::from(&[]);
325 assert!(!v.is_null());
326 assert!(v.is_null_or_empty());
327 assert!(v.is_empty());
328}
329
330#[test]
331fn bytestring_bytes() {
332 let a = [0x1u8, 0x2u8, 0x3u8, 0x4u8];
333 let v = ByteString::from(&a);
334 assert!(!v.is_null());
335 assert!(!v.is_empty());
336 assert_eq!(v.value.as_ref().unwrap(), &a);
337}
338
339#[test]
340fn bytestring_substring() {
341 let a = [0x1u8, 0x2u8, 0x3u8, 0x4u8];
342 let v = ByteString::from(&a);
343 let v2 = v.substring(2, 10000).unwrap();
344 let a2 = v2.value.as_ref().unwrap().as_slice();
345 assert_eq!(a2, &a[2..]);
346
347 let v2 = v.substring(2, 2).unwrap();
348 let a2 = v2.value.as_ref().unwrap().as_slice();
349 assert_eq!(a2, &a[2..3]);
350
351 let v2 = v.substring(0, 2000).unwrap();
352 assert_eq!(v, v2);
353 assert_eq!(v2.value.as_ref().unwrap(), &a);
354
355 assert!(v.substring(4, 10000).is_err());
356 assert!(ByteString::null().substring(0, 0).is_err());
357}