1use super::common::Utils;
4use crate::errors::ByteArrayError;
5use crate::errors::ByteArrayError::{InvalidBinaryChar, InvalidHexChar};
6use alloc::vec;
7use alloc::vec::Vec;
8use core::cmp::PartialEq;
9use core::ops::{Index, IndexMut};
10
11#[derive(Default, PartialEq, Eq, Clone)] pub struct ByteArray {
14 pub(crate) bytes: Vec<u8>,
15}
16
17impl ByteArray {
18 pub fn new() -> Self {
21 ByteArray { bytes: vec![] }
22 }
23
24 pub fn with_capacity(size_in_bytes: usize) -> Self {
26 Self {
27 bytes: Vec::with_capacity(size_in_bytes),
28 }
29 }
30
31 #[deprecated(
57 since = "0.3.3",
58 note = "This will be renamed to with_zeros at a future version"
59 )]
60 pub fn fill_zeros(self) -> Self {
61 if self.bytes.capacity() == 0 {
62 self
63 } else {
64 ByteArray {
65 bytes: vec![0u8; self.bytes.capacity()],
66 }
67 }
68 }
69
70 #[deprecated(
98 since = "0.3.3",
99 note = "This will be renamed to with_value at a future version"
100 )]
101 pub fn fill_with(self, value: u8) -> Self {
102 if self.bytes.capacity() == 0 {
103 self
104 } else {
105 ByteArray {
106 bytes: vec![value; self.bytes.capacity()],
107 }
108 }
109 }
110
111 pub fn from_hex(hex_str: &str) -> Result<Self, ByteArrayError> {
121 if hex_str.is_empty() {
122 return Err(ByteArrayError::EmptyInput);
123 }
124
125 let bytes: Vec<u8> = hex_str.bytes().filter(|&b| b != b'_').collect();
127
128 if let Some(&invalid) = bytes.iter().find(|&&b| !b.is_ascii_hexdigit()) {
130 return Err(InvalidHexChar(invalid as char));
131 }
132
133 let hex_count = bytes.len();
134 let byte_count = hex_count / 2 + hex_count % 2;
135 let mut ret = ByteArray::with_capacity(byte_count);
136
137 let mut start = 0;
138
139 if hex_count % 2 == 1 {
141 ret.bytes
142 .push(Utils::hex_char_to_nibble_unchecked(bytes[0]));
143 start = 1;
144 }
145
146 for i in (start..hex_count).step_by(2) {
148 let byte_val = Utils::hex_char_to_nibble_unchecked(bytes[i]) << 4
149 | Utils::hex_char_to_nibble_unchecked(bytes[i + 1]);
150 ret.bytes.push(byte_val);
151 }
152
153 Ok(ret)
154 }
155
156 pub fn from_bin(bin_str: &str) -> Result<Self, ByteArrayError> {
166 if bin_str.is_empty() {
167 return Err(ByteArrayError::EmptyInput);
168 }
169
170 let bytes: Vec<u8> = bin_str.bytes().filter(|&b| b != b'_').collect();
172
173 if let Some(&invalid) = bytes.iter().find(|&&b| b != b'0' && b != b'1') {
175 return Err(InvalidBinaryChar(invalid as char));
176 }
177
178 let bit_count = bytes.len();
179 let byte_count = bit_count.div_ceil(8);
180 let mut ret = ByteArray::with_capacity(byte_count);
181
182 let rem = bit_count % 8;
183
184 let start = if rem != 0 {
186 let mut byte = 0u8;
187 #[allow(clippy::needless_range_loop)] for i in 0..rem {
189 let bit_value = bytes[i] - b'0';
190 byte |= bit_value << (rem - 1 - i);
191 }
192 ret.bytes.push(byte);
193 rem
194 } else {
195 0
196 };
197
198 for i in (start..bit_count).step_by(8) {
200 let mut byte = 0u8;
201
202 for j in 0..8 {
203 let bit_value = bytes[i + j] - b'0';
204 byte |= bit_value << (7 - j);
205 }
206
207 ret.bytes.push(byte);
208 }
209
210 Ok(ret)
211 }
212
213 pub fn init_zeros(count: usize) -> Self {
217 ByteArray {
218 bytes: vec![0u8; count],
219 }
220 }
221
222 pub fn init_value(value: u8, count: usize) -> Self {
226 ByteArray {
227 bytes: vec![value; count],
228 }
229 }
230
231 pub fn as_bytes(&self) -> &[u8] {
250 &self.bytes
251 }
252
253 #[cfg(feature = "experimental")]
254 pub fn resize(&mut self, new_capacity: usize, value: u8) {
255 unimplemented!(
256 "this is insecure and must find a way on how to handle this in a more secure fashion"
257 );
258 self.bytes.resize(new_capacity, value);
259 }
260
261 #[cfg(feature = "experimental")]
276 pub fn try_push(&mut self, value: u8) {
277 self.bytes.push(value);
278 }
279}
280
281impl Index<usize> for ByteArray {
284 type Output = u8;
285
286 fn index(&self, index: usize) -> &Self::Output {
290 &self.bytes[index]
291 }
292}
293
294impl IndexMut<usize> for ByteArray {
295 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
299 &mut self.bytes[index]
300 }
301}
302
303impl AsRef<[u8]> for ByteArray {
304 fn as_ref(&self) -> &[u8] {
305 self.as_bytes()
306 }
307}
308
309impl AsMut<[u8]> for ByteArray {
310 fn as_mut(&mut self) -> &mut [u8] {
311 &mut self.bytes
312 }
313}
314
315#[cfg(test)]
316mod tests {
317 use super::*;
318 use alloc::vec;
319 use core::str::FromStr;
320
321 fn is_normal<T: Sized + Send + Sync + Unpin>() {}
322
323 #[test]
324 fn test_thread_safety_autotraits() {
325 is_normal::<ByteArray>();
326 }
327
328 #[test]
329 fn test_hex_string_constructor() {
330 let b1: ByteArray = "0xfe81eabd5".parse().unwrap();
331
332 assert_eq!(b1.len(), 5);
333 assert_eq!(b1.bytes, vec![0x0f, 0xe8, 0x1e, 0xab, 0xd5]);
334 }
335
336 #[test]
337 fn test_ba_with_capacity() {
338 let arr = ByteArray::with_capacity(10);
339
340 assert_eq!(arr.bytes.capacity(), 10);
341 assert!(ByteArray::try_from(arr).is_ok());
342 }
343
344 #[test]
345 fn test_with_hex() {
346 let arr = ByteArray::from_hex("ffabc");
347
348 assert_eq!(arr.unwrap().bytes, vec![0x0f, 0xfa, 0xbc]);
349 }
350
351 #[test]
352 fn test_with_bin_less_than_8() {
353 let arr = ByteArray::from_bin("1101111").unwrap();
354 assert_eq!(arr.bytes, vec![0x6f]);
355 }
356
357 #[test]
358 fn test_with_bin_more_than_8() {
359 let arr = ByteArray::from_bin("110111010110111").unwrap();
360 assert_eq!(arr.bytes, vec![0x6e, 0xb7]);
361 }
362
363 #[test]
364 fn test_equality_derives() {
365 let arr: ByteArray = "0xffab12345ffaf".parse().unwrap();
366 let arr_2 = ByteArray::from_hex("ffab12345ffafdeadbeef").unwrap();
367 let arr_3 = arr.clone();
368
369 assert_ne!(arr.bytes, arr_2.bytes);
370 assert_eq!(arr.bytes, arr_3.bytes);
371 }
372
373 #[test]
374 fn test_init_zeros() {
375 let arr = ByteArray::init_zeros(8);
376
377 assert_eq!(arr.bytes, [0u8, 0, 0, 0, 0, 0, 0, 0]);
378 }
379
380 #[test]
381 fn test_init_value() {
382 let arr = ByteArray::init_value(254, 8);
383
384 assert_eq!(arr.bytes, [254, 254, 254, 254, 254, 254, 254, 254]);
385 }
386
387 #[test]
388 fn test_mutable_idx_accessor() {
389 let mut arr: ByteArray = "0xffab1245".parse().unwrap();
390
391 arr[3] = 0xbe;
392 arr[1] = 0xfa;
393
394 assert_eq!(arr.bytes, ByteArray::from_str("0xfffa12be").unwrap().bytes);
395 }
396
397 #[test]
398 #[allow(deprecated)]
399 fn test_fill_zeros() {
400 let arr = ByteArray::default().fill_zeros();
401 assert!(arr.as_bytes().is_empty());
402
403 let arr = ByteArray::with_capacity(5).fill_zeros();
404 assert_eq!(arr.as_bytes(), [0u8, 0, 0, 0, 0]);
405
406 let arr = ByteArray::with_capacity(7).fill_zeros();
407
408 assert_eq!(arr.as_bytes(), [0u8, 0, 0, 0, 0, 0, 0])
409 }
410
411 #[test]
412 #[allow(deprecated)]
413 fn test_fill_with() {
414 let arr = ByteArray::default().fill_zeros();
415 assert!(arr.as_bytes().is_empty());
416
417 let arr = ByteArray::with_capacity(5).fill_with(126);
418 assert_eq!(arr.as_bytes(), [126u8, 126, 126, 126, 126]);
419
420 let arr = ByteArray::with_capacity(7).fill_with(5);
421
422 assert_eq!(arr.as_bytes(), [5u8, 5, 5, 5, 5, 5, 5]);
423 }
424
425 #[test]
426 #[cfg(feature = "experimental")]
427 fn test_push_element() {
428 let mut arr: ByteArray = vec![1, 2].into();
429
430 arr.try_push(0xab);
431
432 assert_eq!(arr.as_bytes(), [1, 2, 0xab]);
433 }
434
435 #[test]
436 fn test_hex_with_underscores() {
437 let arr = ByteArray::from_hex("de_ad_be_ef").unwrap();
438 assert_eq!(arr.as_bytes(), [0xde, 0xad, 0xbe, 0xef]);
439 }
440
441 #[test]
442 fn test_bin_with_underscores() {
443 let arr = ByteArray::from_bin("1010_0101").unwrap();
444 assert_eq!(arr.as_bytes(), [0xa5]);
445 }
446
447 #[test]
448 fn test_bin_with_underscores_odd_length() {
449 let arr = ByteArray::from_bin("110_1111").unwrap();
450 assert_eq!(arr.as_bytes(), [0x6f]);
451 }
452
453 #[test]
454 #[should_panic]
455 fn test_as_mut_empty() {
456 let mut bytes = ByteArray::default();
457
458 let mut_ref = bytes.as_mut();
459
460 mut_ref[0] = 0x00;
461 }
462
463 #[test]
464 fn test_as_ref() {
465 let bytes: ByteArray = "0x01_02_03_04_05_06_07_08".parse().unwrap();
466 let bytes_ref = bytes.as_ref();
467
468 assert_eq!(bytes.as_bytes(), bytes_ref);
469 }
470
471 #[test]
472 fn test_as_mut() {
473 let mut bytes: ByteArray = "0x01_02_03_04_05_06_07_08".parse().unwrap();
474
475 let mut_ref = bytes.as_mut();
476
477 mut_ref[0] = 0xFF;
478 mut_ref[5] = 0xab;
479 mut_ref[7] = 0x1a;
480
481 assert_eq!(
482 bytes.as_bytes(),
483 [0xff, 0x02, 0x03, 0x04, 0x05, 0xab, 0x07, 0x1a]
484 )
485 }
486}