byte_array_ops/
type_conv.rs

1//! This module contains all type conversion definitions to and from [`ByteArray`]
2
3use crate::errors::ByteArrayError;
4use crate::model::ByteArray;
5use alloc::vec;
6use alloc::vec::Vec;
7use core::str::FromStr;
8
9impl<const N: usize> From<&[u8; N]> for ByteArray {
10    /// converts a byte slice into our Byte array, odd word padding is not needed here as arrays are always aligned
11    /// TODO document this as potentially expensive copy
12    fn from(value: &[u8; N]) -> Self {
13        ByteArray::from(&value[..])
14    }
15}
16
17impl From<&[u8]> for ByteArray {
18    /// converts a byte slice into our Byte array, odd word padding is not needed here as arrays are always aligned
19    /// TODO document this as potentially expensive copy
20    fn from(value: &[u8]) -> Self {
21        ByteArray {
22            bytes: value.to_vec(),
23        }
24    }
25}
26
27impl From<Vec<u8>> for ByteArray {
28    fn from(bytes: Vec<u8>) -> Self {
29        ByteArray {
30            bytes, // Zero-cost move
31        }
32    }
33}
34
35impl From<u8> for ByteArray {
36    fn from(value: u8) -> Self {
37        ByteArray { bytes: vec![value] }
38    }
39}
40
41impl FromStr for ByteArray {
42    type Err = ByteArrayError;
43    /// parses a [`&str`] as follows :
44    ///  - does it start with a format identifier with `0x`, `0b`, or `0o` then parses in hex, binary or octal respectively (case insensitive)
45    ///     - The routines for the conversion here ignore underscore `_` allowing its use as a separator for example `"0b1110_0010_0110"`
46    ///  - for all other cases defaults to `UTF-8` as encoding and parses the slice as such
47    ///
48    /// TODO add example with string slice lower than 2 chars
49    ///
50    ///
51    fn from_str(s: &str) -> Result<Self, Self::Err> {
52        if s.is_empty() {
53            return Err(ByteArrayError::EmptyInput);
54        }
55
56        if s.starts_with("0x") || s.starts_with("0X") {
57            return ByteArray::from_hex(&s[2..]);
58        }
59
60        if s.starts_with("0b") || s.starts_with("0B") {
61            return ByteArray::from_bin(&s[2..]);
62        }
63
64        if s.starts_with("0o") || s.starts_with("0O") {
65            unimplemented!()
66        }
67
68        // It's a regular UTF-8 string
69        Ok(ByteArray::from(s.as_bytes()))
70    }
71}
72
73impl<const N: usize> From<[u8; N]> for ByteArray {
74    fn from(value: [u8; N]) -> Self {
75        (&value).into()
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82
83    #[test]
84    fn test_from_slice_reference() {
85        let bytes = [0xde, 0xad, 0xbe, 0xef];
86        let bytes_slice = &bytes;
87
88        let byte_array: ByteArray = bytes_slice.into();
89
90        assert_eq!(byte_array.as_bytes(), [0xde, 0xad, 0xbe, 0xef]);
91    }
92
93    #[test]
94    fn test_from_vec() {
95        let bytes: Vec<u8> = vec![0xde, 0xad, 0xbe, 0xef];
96
97        let arr = ByteArray::from(bytes);
98
99        assert_eq!(arr.as_bytes(), &[0xde, 0xad, 0xbe, 0xef]);
100    }
101
102    #[test]
103    fn test_from_single_byte() {
104        let arr: ByteArray = 0xff.into();
105
106        assert_eq!(arr.as_bytes(), [0xff]);
107    }
108
109    #[test]
110    fn test_from_array_literal() {
111        let arr: ByteArray = [0xaa, 0xbb, 0xcc].into();
112
113        assert_eq!(arr.as_bytes(), [0xaa, 0xbb, 0xcc]);
114    }
115
116    #[test]
117    fn test_from_array_reference() {
118        let bytes = [0x01, 0x02, 0x03, 0x04];
119        let arr: ByteArray = (&bytes).into();
120
121        assert_eq!(arr.as_bytes(), [0x01, 0x02, 0x03, 0x04]);
122    }
123
124    #[test]
125    fn test_from_empty_slice() {
126        let empty: &[u8] = &[];
127        let arr: ByteArray = empty.into();
128
129        assert!(arr.is_empty());
130    }
131
132    #[test]
133    fn test_from_empty_vec() {
134        let empty: Vec<u8> = Vec::new();
135        let arr = ByteArray::from(empty);
136
137        assert!(arr.is_empty());
138    }
139
140    #[test]
141    fn test_from_str_hex() {
142        let arr: ByteArray = "0xdeadbeef".parse().unwrap();
143
144        assert_eq!(arr.as_bytes(), [0xde, 0xad, 0xbe, 0xef]);
145    }
146
147    #[test]
148    fn test_from_str_hex_uppercase() {
149        let arr: ByteArray = "0XDEADBEEF".parse().unwrap();
150
151        assert_eq!(arr.as_bytes(), [0xde, 0xad, 0xbe, 0xef]);
152    }
153
154    #[test]
155    fn test_from_str_hex_mixed_case() {
156        let arr: ByteArray = "0xDeAdBeEf".parse().unwrap();
157
158        assert_eq!(arr.as_bytes(), [0xde, 0xad, 0xbe, 0xef]);
159    }
160
161    #[test]
162    fn test_from_str_hex_odd_length() {
163        let arr: ByteArray = "0xfff".parse().unwrap();
164
165        assert_eq!(arr.as_bytes(), [0x0f, 0xff]);
166    }
167
168    #[test]
169    fn test_from_str_binary() {
170        let arr: ByteArray = "0b11011110".parse().unwrap();
171
172        assert_eq!(arr.as_bytes(), [0xde]);
173    }
174
175    #[test]
176    fn test_from_str_binary_uppercase() {
177        let arr: ByteArray = "0B11011110".parse().unwrap();
178
179        assert_eq!(arr.as_bytes(), [0xde]);
180    }
181
182    #[test]
183    fn test_from_str_utf8() {
184        let arr: ByteArray = "hello".parse().unwrap();
185
186        assert_eq!(arr.as_bytes(), b"hello");
187    }
188
189    #[test]
190    fn test_from_str_utf8_single_char() {
191        let arr: ByteArray = "A".parse().unwrap();
192
193        assert_eq!(arr.as_bytes(), b"A");
194    }
195
196    #[test]
197    fn test_from_str_empty_error() {
198        let result: Result<ByteArray, ByteArrayError> = "".parse();
199
200        assert!(result.is_err());
201        if let Err(e) = result {
202            assert!(matches!(e, ByteArrayError::EmptyInput));
203        }
204    }
205
206    #[test]
207    fn test_from_str_hex_invalid_char() {
208        let result: Result<ByteArray, ByteArrayError> = "0xgggg".parse();
209
210        assert!(result.is_err());
211    }
212
213    #[test]
214    fn test_from_str_binary_invalid_char() {
215        let result: Result<ByteArray, ByteArrayError> = "0b12345".parse();
216
217        assert!(result.is_err());
218    }
219
220    #[test]
221    fn test_from_large_array() {
222        let large: Vec<u8> = (0..1000).map(|i| (i % 256) as u8).collect();
223        let arr = ByteArray::from(large.clone());
224
225        assert_eq!(arr.len(), 1000);
226        assert_eq!(arr.as_bytes(), large.as_slice());
227    }
228}