1use super::common::Utils;
4use crate::core::errors::ByteArrayError;
5use crate::core::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 pub fn fill_zeros(self) -> Self {
57 if self.bytes.capacity() == 0 {
58 self
59 } else {
60 ByteArray {
61 bytes: vec![0u8; self.bytes.capacity()],
62 }
63 }
64 }
65
66 pub fn fill_with(self, value: u8) -> Self {
94 if self.bytes.capacity() == 0 {
95 self
96 } else {
97 ByteArray {
98 bytes: vec![value; self.bytes.capacity()],
99 }
100 }
101 }
102
103 pub fn from_hex(hex_str: &str) -> Result<Self, ByteArrayError> {
113 if hex_str.is_empty() {
114 return Err(ByteArrayError::EmptyInput);
115 }
116
117 let bytes: Vec<u8> = hex_str.bytes().filter(|&b| b != b'_').collect();
119
120 if let Some(&invalid) = bytes.iter().find(|&&b| !b.is_ascii_hexdigit()) {
122 return Err(InvalidHexChar(invalid as char));
123 }
124
125 let hex_count = bytes.len();
126 let byte_count = hex_count / 2 + hex_count % 2;
127 let mut ret = ByteArray::with_capacity(byte_count);
128
129 let mut start = 0;
130
131 if hex_count % 2 == 1 {
133 ret.bytes
134 .push(Utils::hex_char_to_nibble_unchecked(bytes[0]));
135 start = 1;
136 }
137
138 for i in (start..hex_count).step_by(2) {
140 let byte_val = Utils::hex_char_to_nibble_unchecked(bytes[i]) << 4
141 | Utils::hex_char_to_nibble_unchecked(bytes[i + 1]);
142 ret.bytes.push(byte_val);
143 }
144
145 Ok(ret)
146 }
147
148 pub fn from_bin(bin_str: &str) -> Result<Self, ByteArrayError> {
158 if bin_str.is_empty() {
159 return Err(ByteArrayError::EmptyInput);
160 }
161
162 let bytes: Vec<u8> = bin_str.bytes().filter(|&b| b != b'_').collect();
164
165 if let Some(&invalid) = bytes.iter().find(|&&b| b != b'0' && b != b'1') {
167 return Err(InvalidBinaryChar(invalid as char));
168 }
169
170 let bit_count = bytes.len();
171 let byte_count = bit_count.div_ceil(8);
172 let mut ret = ByteArray::with_capacity(byte_count);
173
174 let rem = bit_count % 8;
175
176 let start = if rem != 0 {
178 let mut byte = 0u8;
179 #[allow(clippy::needless_range_loop)] for i in 0..rem {
181 let bit_value = bytes[i] - b'0';
182 byte |= bit_value << (rem - 1 - i);
183 }
184 ret.bytes.push(byte);
185 rem
186 } else {
187 0
188 };
189
190 for i in (start..bit_count).step_by(8) {
192 let mut byte = 0u8;
193
194 for j in 0..8 {
195 let bit_value = bytes[i + j] - b'0';
196 byte |= bit_value << (7 - j);
197 }
198
199 ret.bytes.push(byte);
200 }
201
202 Ok(ret)
203 }
204
205 pub fn init_zeros(count: usize) -> Self {
209 ByteArray {
210 bytes: vec![0u8; count],
211 }
212 }
213
214 pub fn init_value(value: u8, count: usize) -> Self {
218 ByteArray {
219 bytes: vec![value; count],
220 }
221 }
222
223 pub fn as_bytes(&self) -> &[u8] {
253 &self.bytes
254 }
255
256 #[cfg(feature = "experimental")]
257 pub fn resize(&mut self, new_capacity: usize, value: u8) {
258 unimplemented!(
259 "this is insecure and must find a way on how to handle this in a more secure fashion"
260 );
261 self.bytes.resize(new_capacity, value);
262 }
263
264 #[cfg(feature = "experimental")]
279 pub fn try_push(&mut self, value: u8) {
280 self.bytes.push(value);
281 }
282}
283
284impl Index<usize> for ByteArray {
287 type Output = u8;
288
289 fn index(&self, index: usize) -> &Self::Output {
293 &self.bytes[index]
294 }
295}
296
297impl IndexMut<usize> for ByteArray {
298 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
302 &mut self.bytes[index]
303 }
304}
305
306impl AsRef<[u8]> for ByteArray {
307 fn as_ref(&self) -> &[u8] {
308 self.as_bytes()
309 }
310}
311
312impl AsMut<[u8]> for ByteArray {
313 fn as_mut(&mut self) -> &mut [u8] {
314 &mut self.bytes
315 }
316}
317
318#[cfg(test)]
319mod tests {
320 use super::*;
321 use alloc::vec;
322 use core::str::FromStr;
323
324 #[test]
325 fn test_hex_string_constructor() {
326 let b1: ByteArray = "0xfe81eabd5".parse().unwrap();
327
328 assert_eq!(b1.len(), 5);
329 assert_eq!(b1.bytes, vec![0x0f, 0xe8, 0x1e, 0xab, 0xd5]);
330 }
331
332 #[test]
333 fn test_ba_with_capacity() {
334 let arr = ByteArray::with_capacity(10);
335
336 assert_eq!(arr.bytes.capacity(), 10);
337 assert!(ByteArray::try_from(arr).is_ok());
338 }
339
340 #[test]
341 fn test_with_hex() {
342 let arr = ByteArray::from_hex("ffabc");
343
344 assert_eq!(arr.unwrap().bytes, vec![0x0f, 0xfa, 0xbc]);
345 }
346
347 #[test]
348 fn test_with_bin_less_than_8() {
349 let arr = ByteArray::from_bin("1101111").unwrap();
350 assert_eq!(arr.bytes, vec![0x6f]);
351 }
352
353 #[test]
354 fn test_with_bin_more_than_8() {
355 let arr = ByteArray::from_bin("110111010110111").unwrap();
356 assert_eq!(arr.bytes, vec![0x6e, 0xb7]);
357 }
358
359 #[test]
360 fn test_equality_derives() {
361 let arr: ByteArray = "0xffab12345ffaf".parse().unwrap();
362 let arr_2 = ByteArray::from_hex("ffab12345ffafdeadbeef").unwrap();
363 let arr_3 = arr.clone();
364
365 assert_ne!(arr.bytes, arr_2.bytes);
366 assert_eq!(arr.bytes, arr_3.bytes);
367 }
368
369 #[test]
370 fn test_init_zeros() {
371 let arr = ByteArray::init_zeros(8);
372
373 assert_eq!(arr.bytes, [0u8, 0, 0, 0, 0, 0, 0, 0]);
374 }
375
376 #[test]
377 fn test_init_value() {
378 let arr = ByteArray::init_value(254, 8);
379
380 assert_eq!(arr.bytes, [254, 254, 254, 254, 254, 254, 254, 254]);
381 }
382
383 #[test]
384 fn test_mutable_idx_accessor() {
385 let mut arr: ByteArray = "0xffab1245".parse().unwrap();
386
387 arr[3] = 0xbe;
388 arr[1] = 0xfa;
389
390 assert_eq!(arr.bytes, ByteArray::from_str("0xfffa12be").unwrap().bytes);
391 }
392
393 #[test]
394 fn test_fill_zeros() {
395 let arr = ByteArray::default().fill_zeros();
396 assert!(arr.as_bytes().is_empty());
397
398 let arr = ByteArray::with_capacity(5).fill_zeros();
399 assert_eq!(arr.as_bytes(), [0u8, 0, 0, 0, 0]);
400
401 let arr = ByteArray::with_capacity(7).fill_zeros();
402
403 assert_eq!(arr.as_bytes(), [0u8, 0, 0, 0, 0, 0, 0])
404 }
405
406 #[test]
407 fn test_fill_with() {
408 let arr = ByteArray::default().fill_zeros();
409 assert!(arr.as_bytes().is_empty());
410
411 let arr = ByteArray::with_capacity(5).fill_with(126);
412 assert_eq!(arr.as_bytes(), [126u8, 126, 126, 126, 126]);
413
414 let arr = ByteArray::with_capacity(7).fill_with(5);
415
416 assert_eq!(arr.as_bytes(), [5u8, 5, 5, 5, 5, 5, 5]);
417 }
418
419 #[test]
420 #[cfg(feature = "experimental")]
421 fn test_push_element() {
422 let mut arr: ByteArray = vec![1, 2].into();
423
424 arr.try_push(0xab);
425
426 assert_eq!(arr.as_bytes(), [1, 2, 0xab]);
427 }
428
429 #[test]
430 fn test_hex_with_underscores() {
431 let arr = ByteArray::from_hex("de_ad_be_ef").unwrap();
432 assert_eq!(arr.as_bytes(), [0xde, 0xad, 0xbe, 0xef]);
433 }
434
435 #[test]
436 fn test_bin_with_underscores() {
437 let arr = ByteArray::from_bin("1010_0101").unwrap();
438 assert_eq!(arr.as_bytes(), [0xa5]);
439 }
440
441 #[test]
442 fn test_bin_with_underscores_odd_length() {
443 let arr = ByteArray::from_bin("110_1111").unwrap();
444 assert_eq!(arr.as_bytes(), [0x6f]);
445 }
446
447 #[test]
448 #[should_panic]
449 fn test_as_mut_empty() {
450 let mut bytes = ByteArray::default();
451
452 let mut_ref = bytes.as_mut();
453
454 mut_ref[0] = 0x00;
455 }
456
457 #[test]
458 fn test_as_ref() {
459 let bytes: ByteArray = "0x01_02_03_04_05_06_07_08".parse().unwrap();
460 let bytes_ref = bytes.as_ref();
461
462 assert_eq!(bytes.as_bytes(), bytes_ref);
463 }
464
465 #[test]
466 fn test_as_mut() {
467 let mut bytes: ByteArray = "0x01_02_03_04_05_06_07_08".parse().unwrap();
468
469 let mut_ref = bytes.as_mut();
470
471 mut_ref[0] = 0xFF;
472 mut_ref[5] = 0xab;
473 mut_ref[7] = 0x1a;
474
475 assert_eq!(
476 bytes.as_bytes(),
477 [0xff, 0x02, 0x03, 0x04, 0x05, 0xab, 0x07, 0x1a]
478 )
479 }
480}