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 self.value.is_none() {
146 write_i32(stream, -1)
147 } else {
148 let value = self.value.as_ref().unwrap();
149 write_i32(stream, value.len() as i32)?;
150 process_encode_io_result(stream.write_all(value))
151 }
152 }
153}
154
155impl SimpleBinaryDecodable for ByteString {
156 fn decode<S: Read + ?Sized>(
157 stream: &mut S,
158 decoding_options: &DecodingOptions,
159 ) -> EncodingResult<Self> {
160 let len = read_i32(stream)?;
161 if len == -1 {
163 Ok(ByteString::null())
164 } else if len < -1 {
165 Err(Error::decoding(format!(
166 "ByteString buf length is a negative number {len}"
167 )))
168 } else if len as usize > decoding_options.max_byte_string_length {
169 Err(Error::decoding(format!(
170 "ByteString length {} exceeds decoding limit {}",
171 len, decoding_options.max_byte_string_length
172 )))
173 } else {
174 let mut buf: Vec<u8> = vec![0u8; len as usize];
176 process_decode_io_result(stream.read_exact(&mut buf))?;
177 Ok(ByteString { value: Some(buf) })
178 }
179 }
180}
181
182impl<'a, T> From<&'a T> for ByteString
183where
184 T: AsRef<[u8]> + ?Sized,
185{
186 fn from(value: &'a T) -> Self {
187 Self::from(value.as_ref().to_vec())
188 }
189}
190
191impl From<Vec<u8>> for ByteString {
192 fn from(value: Vec<u8>) -> Self {
193 ByteString { value: Some(value) }
195 }
196}
197
198impl From<Guid> for ByteString {
199 fn from(value: Guid) -> Self {
200 ByteString::from(value.as_bytes().to_vec())
201 }
202}
203
204impl TryFrom<&ByteString> for Guid {
205 type Error = ();
206
207 fn try_from(value: &ByteString) -> Result<Self, Self::Error> {
208 if value.is_null_or_empty() {
209 Err(())
210 } else {
211 let bytes = value.as_ref();
212 if bytes.len() != 16 {
213 Err(())
214 } else {
215 let mut guid = [0u8; 16];
216 guid.copy_from_slice(bytes);
217 Ok(Guid::from_bytes(guid))
218 }
219 }
220 }
221}
222
223impl From<ByteString> for String {
224 fn from(value: ByteString) -> Self {
225 value.as_base64()
226 }
227}
228
229impl Default for ByteString {
230 fn default() -> Self {
231 ByteString::null()
232 }
233}
234
235impl ByteString {
236 pub fn null() -> ByteString {
238 ByteString { value: None }
239 }
240
241 pub fn is_null(&self) -> bool {
243 self.value.is_none()
244 }
245
246 pub fn is_empty(&self) -> bool {
248 if let Some(v) = &self.value {
249 v.is_empty()
250 } else {
251 false
252 }
253 }
254
255 pub fn is_null_or_empty(&self) -> bool {
257 self.is_null() || self.is_empty()
258 }
259
260 pub fn from_base64(data: &str) -> Option<ByteString> {
262 if let Ok(bytes) = STANDARD.decode(data) {
263 Some(Self::from(bytes))
264 } else {
265 None
266 }
267 }
268
269 pub fn from_base64_ignore_whitespace(mut data: String) -> Option<ByteString> {
271 data.retain(|c| !c.is_whitespace());
272 if let Ok(bytes) = STANDARD.decode(&data) {
273 Some(Self::from(bytes))
274 } else {
275 None
276 }
277 }
278
279 pub fn as_base64(&self) -> String {
281 if let Some(ref value) = self.value {
283 STANDARD.encode(value)
284 } else {
285 STANDARD.encode("")
286 }
287 }
288
289 pub fn substring(&self, min: usize, max: usize) -> Result<ByteString, OutOfRange> {
294 if let Some(ref v) = self.value {
295 if min >= v.len() {
296 Err(OutOfRange)
297 } else {
298 let max = if max >= v.len() { v.len() - 1 } else { max };
299 let v = v[min..=max].to_vec();
300 Ok(ByteString::from(v))
301 }
302 } else {
303 Err(OutOfRange)
304 }
305 }
306
307 pub fn len(&self) -> usize {
309 if let Some(ref v) = self.value {
310 v.len()
311 } else {
312 0
313 }
314 }
315}
316
317#[test]
318fn bytestring_null() {
319 let v = ByteString::null();
320 assert!(v.is_null());
321}
322
323#[test]
324fn bytestring_empty() {
325 let v = ByteString::from(&[]);
326 assert!(!v.is_null());
327 assert!(v.is_null_or_empty());
328 assert!(v.is_empty());
329}
330
331#[test]
332fn bytestring_bytes() {
333 let a = [0x1u8, 0x2u8, 0x3u8, 0x4u8];
334 let v = ByteString::from(&a);
335 assert!(!v.is_null());
336 assert!(!v.is_empty());
337 assert_eq!(v.value.as_ref().unwrap(), &a);
338}
339
340#[test]
341fn bytestring_substring() {
342 let a = [0x1u8, 0x2u8, 0x3u8, 0x4u8];
343 let v = ByteString::from(&a);
344 let v2 = v.substring(2, 10000).unwrap();
345 let a2 = v2.value.as_ref().unwrap().as_slice();
346 assert_eq!(a2, &a[2..]);
347
348 let v2 = v.substring(2, 2).unwrap();
349 let a2 = v2.value.as_ref().unwrap().as_slice();
350 assert_eq!(a2, &a[2..3]);
351
352 let v2 = v.substring(0, 2000).unwrap();
353 assert_eq!(v, v2);
354 assert_eq!(v2.value.as_ref().unwrap(), &a);
355
356 assert!(v.substring(4, 10000).is_err());
357 assert!(ByteString::null().substring(0, 0).is_err());
358}