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 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] {
242 &self.bytes
243 }
244
245 #[cfg(feature = "experimental")]
246 pub fn resize(&mut self, new_capacity: usize, value: u8) {
247 unimplemented!(
248 "this is insecure and must find a way on how to handle this in a more secure fashion"
249 );
250 self.bytes.resize(new_capacity, value);
251 }
252
253 #[cfg(feature = "experimental")]
268 pub fn try_push(&mut self, value: u8) {
269 self.bytes.push(value);
270 }
271}
272
273impl Index<usize> for ByteArray {
276 type Output = u8;
277
278 fn index(&self, index: usize) -> &Self::Output {
282 &self.bytes[index]
283 }
284}
285
286impl IndexMut<usize> for ByteArray {
287 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
291 &mut self.bytes[index]
292 }
293}
294
295impl AsRef<[u8]> for ByteArray {
296 fn as_ref(&self) -> &[u8] {
297 self.as_bytes()
298 }
299}
300
301impl AsMut<[u8]> for ByteArray {
302 fn as_mut(&mut self) -> &mut [u8] {
303 &mut self.bytes
304 }
305}
306
307#[cfg(test)]
308mod tests {
309 use super::*;
310 use alloc::vec;
311 use core::str::FromStr;
312
313 #[test]
314 fn test_hex_string_constructor() {
315 let b1: ByteArray = "0xfe81eabd5".parse().unwrap();
316
317 assert_eq!(b1.len(), 5);
318 assert_eq!(b1.bytes, vec![0x0f, 0xe8, 0x1e, 0xab, 0xd5]);
319 }
320
321 #[test]
322 fn test_ba_with_capacity() {
323 let arr = ByteArray::with_capacity(10);
324
325 assert_eq!(arr.bytes.capacity(), 10);
326 assert!(ByteArray::try_from(arr).is_ok());
327 }
328
329 #[test]
330 fn test_with_hex() {
331 let arr = ByteArray::from_hex("ffabc");
332
333 assert_eq!(arr.unwrap().bytes, vec![0x0f, 0xfa, 0xbc]);
334 }
335
336 #[test]
337 fn test_with_bin_less_than_8() {
338 let arr = ByteArray::from_bin("1101111").unwrap();
339 assert_eq!(arr.bytes, vec![0x6f]);
340 }
341
342 #[test]
343 fn test_with_bin_more_than_8() {
344 let arr = ByteArray::from_bin("110111010110111").unwrap();
345 assert_eq!(arr.bytes, vec![0x6e, 0xb7]);
346 }
347
348 #[test]
349 fn test_equality_derives() {
350 let arr: ByteArray = "0xffab12345ffaf".parse().unwrap();
351 let arr_2 = ByteArray::from_hex("ffab12345ffafdeadbeef").unwrap();
352 let arr_3 = arr.clone();
353
354 assert_ne!(arr.bytes, arr_2.bytes);
355 assert_eq!(arr.bytes, arr_3.bytes);
356 }
357
358 #[test]
359 fn test_init_zeros() {
360 let arr = ByteArray::init_zeros(8);
361
362 assert_eq!(arr.bytes, [0u8, 0, 0, 0, 0, 0, 0, 0]);
363 }
364
365 #[test]
366 fn test_init_value() {
367 let arr = ByteArray::init_value(254, 8);
368
369 assert_eq!(arr.bytes, [254, 254, 254, 254, 254, 254, 254, 254]);
370 }
371
372 #[test]
373 fn test_mutable_idx_accessor() {
374 let mut arr: ByteArray = "0xffab1245".parse().unwrap();
375
376 arr[3] = 0xbe;
377 arr[1] = 0xfa;
378
379 assert_eq!(arr.bytes, ByteArray::from_str("0xfffa12be").unwrap().bytes);
380 }
381
382 #[test]
383 fn test_fill_zeros() {
384 let arr = ByteArray::default().fill_zeros();
385 assert!(arr.as_bytes().is_empty());
386
387 let arr = ByteArray::with_capacity(5).fill_zeros();
388 assert_eq!(arr.as_bytes(), [0u8, 0, 0, 0, 0]);
389
390 let arr = ByteArray::with_capacity(7).fill_zeros();
391
392 assert_eq!(arr.as_bytes(), [0u8, 0, 0, 0, 0, 0, 0])
393 }
394
395 #[test]
396 fn test_fill_with() {
397 let arr = ByteArray::default().fill_zeros();
398 assert!(arr.as_bytes().is_empty());
399
400 let arr = ByteArray::with_capacity(5).fill_with(126);
401 assert_eq!(arr.as_bytes(), [126u8, 126, 126, 126, 126]);
402
403 let arr = ByteArray::with_capacity(7).fill_with(5);
404
405 assert_eq!(arr.as_bytes(), [5u8, 5, 5, 5, 5, 5, 5]);
406 }
407
408 #[test]
409 #[cfg(feature = "experimental")]
410 fn test_push_element() {
411 let mut arr: ByteArray = vec![1, 2].into();
412
413 arr.try_push(0xab);
414
415 assert_eq!(arr.as_bytes(), [1, 2, 0xab]);
416 }
417
418 #[test]
419 fn test_hex_with_underscores() {
420 let arr = ByteArray::from_hex("de_ad_be_ef").unwrap();
421 assert_eq!(arr.as_bytes(), [0xde, 0xad, 0xbe, 0xef]);
422 }
423
424 #[test]
425 fn test_bin_with_underscores() {
426 let arr = ByteArray::from_bin("1010_0101").unwrap();
427 assert_eq!(arr.as_bytes(), [0xa5]);
428 }
429
430 #[test]
431 fn test_bin_with_underscores_odd_length() {
432 let arr = ByteArray::from_bin("110_1111").unwrap();
433 assert_eq!(arr.as_bytes(), [0x6f]);
434 }
435
436 #[test]
437 #[should_panic]
438 fn test_as_mut_empty() {
439 let mut bytes = ByteArray::default();
440
441 let mut_ref = bytes.as_mut();
442
443 mut_ref[0] = 0x00;
444 }
445
446 #[test]
447 fn test_as_ref() {
448 let bytes: ByteArray = "0x01_02_03_04_05_06_07_08".parse().unwrap();
449 let bytes_ref = bytes.as_ref();
450
451 assert_eq!(bytes.as_bytes(), bytes_ref);
452 }
453
454 #[test]
455 fn test_as_mut() {
456 let mut bytes: ByteArray = "0x01_02_03_04_05_06_07_08".parse().unwrap();
457
458 let mut_ref = bytes.as_mut();
459
460 mut_ref[0] = 0xFF;
461 mut_ref[5] = 0xab;
462 mut_ref[7] = 0x1a;
463
464 assert_eq!(
465 bytes.as_bytes(),
466 [0xff, 0x02, 0x03, 0x04, 0x05, 0xab, 0x07, 0x1a]
467 )
468 }
469}