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