byte_array_ops/byte_array/
ops.rs1use crate::byte_array::model::ByteArray;
2use core::cmp::max;
3use core::mem;
4use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not};
5
6#[doc(hidden)]
7pub(super) struct InternalOps;
8
9impl InternalOps {
10 fn base_op(
22 lhs: ByteArray,
23 rhs: ByteArray,
24 byte_op: impl Fn(u8, u8) -> u8,
25 identity: u8,
26 ) -> ByteArray {
27 let max_arr_size = max(lhs.len(), rhs.len());
29 let mut res = ByteArray::with_capacity(max_arr_size).fill_with(identity);
30
31 let first_offset = max_arr_size - lhs.len();
33 let second_offset = max_arr_size - rhs.len();
34
35 for i in 0..lhs.len() {
36 res[first_offset + i] = byte_op(res[first_offset + i], lhs[i]);
37 }
38
39 for i in 0..rhs.len() {
40 res[second_offset + i] = byte_op(res[second_offset + i], rhs[i]);
41 }
42
43 res
44 }
45
46 #[inline]
47 fn xor_op(lhs: ByteArray, rhs: ByteArray) -> ByteArray {
48 Self::base_op(lhs, rhs, |x, y| x ^ y, 0x00)
49 }
50
51 #[inline]
52 fn and_op(lhs: ByteArray, rhs: ByteArray) -> ByteArray {
53 Self::base_op(lhs, rhs, |x, y| x & y, 0xFF)
54 }
55
56 #[inline]
57 fn or_op(lhs: ByteArray, rhs: ByteArray) -> ByteArray {
58 Self::base_op(lhs, rhs, |x, y| x | y, 0x00)
59 }
60}
61
62impl BitXor for ByteArray {
63 type Output = Self;
64
65 fn bitxor(self, rhs: Self) -> Self::Output {
66 InternalOps::xor_op(self, rhs)
67 }
68}
69
70impl BitXorAssign for ByteArray {
71 fn bitxor_assign(&mut self, rhs: Self) {
72 *self = InternalOps::xor_op(mem::take(self), rhs);
73 }
74}
75
76impl BitAnd for ByteArray {
77 type Output = Self;
78
79 fn bitand(self, rhs: Self) -> Self::Output {
80 InternalOps::and_op(self, rhs)
81 }
82}
83
84impl BitAndAssign for ByteArray {
85 fn bitand_assign(&mut self, rhs: Self) {
86 *self = InternalOps::and_op(mem::take(self), rhs)
87 }
88}
89
90impl BitOr for ByteArray {
91 type Output = Self;
92
93 fn bitor(self, rhs: Self) -> Self::Output {
94 InternalOps::or_op(self, rhs)
95 }
96}
97
98impl BitOrAssign for ByteArray {
99 fn bitor_assign(&mut self, rhs: Self) {
100 *self = InternalOps::or_op(mem::take(self), rhs)
101 }
102}
103
104impl Not for ByteArray {
105 type Output = Self;
106
107 fn not(self) -> Self::Output {
108 ByteArray {
109 bytes: self.bytes.iter().map(|&b| !b).collect(),
110 }
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117
118 #[test]
119 fn test_xor_simple() {
120 let b1: ByteArray = [0xAA, 0xBB, 0xCC].into();
121 let b2 = ByteArray::from([0x55, 0x44, 0x33]);
122 let b3 = b2 ^ b1;
123
124 assert_eq!(b3.len(), 3);
125 assert_eq!(b3[0], 0xAA ^ 0x55);
126 assert_eq!(b3[1], 0xBB ^ 0x44);
127 assert_eq!(b3[2], 0xCC ^ 0x33);
128 }
129
130 #[test]
131 fn test_xor_unequal_length() {
132 let b1: ByteArray = [0xAA, 0xBB].into();
133 let b2 = ByteArray::from([0x11, 0x22, 0x33]);
134 let res = b1 ^ b2;
135
136 assert_eq!(res.len(), 3);
137 assert_eq!(res[0], 0x11);
138 assert_eq!(res[1], 0xAA ^ 0x22);
139 assert_eq!(res[2], 0xBB ^ 0x33);
140 }
141
142 #[test]
143 fn test_xor_single_byte_right_aligned() {
144 let b1 = ByteArray::from([0x12, 0x35, 0x56]);
145 let b2 = ByteArray::from(0xFF);
146 let res = b1 ^ b2;
147
148 assert_eq!(res.len(), 3);
149 assert_eq!(res[0], 0x12);
150 assert_eq!(res[1], 0x35);
151 assert_eq!(res[2], 0xFF ^ 0x56);
152 }
153
154 #[test]
155 fn test_xor_assign() {
156 let mut b1: ByteArray = [0xAA, 0xBB, 0xCC].into();
157 let b2 = ByteArray::from([0x55, 0x44, 0x33]);
158 b1 ^= b2;
159
160 assert_eq!(b1.len(), 3);
161 assert_eq!(b1[0], 0xAA ^ 0x55);
162 assert_eq!(b1[1], 0xBB ^ 0x44);
163 assert_eq!(b1[2], 0xCC ^ 0x33);
164 }
165
166 #[test]
167 fn test_and_simple() {
168 let b1: ByteArray = [0xFF, 0xAA, 0x55].into();
169 let b2 = ByteArray::from([0x0F, 0xF0, 0x33]);
170 let res = b1 & b2;
171
172 assert_eq!(res.len(), 3);
173 assert_eq!(res[0], 0xFF & 0x0F);
174 assert_eq!(res[1], 0xAA & 0xF0);
175 assert_eq!(res[2], 0x55 & 0x33);
176 }
177
178 #[test]
179 fn test_and_unequal_length() {
180 let b1: ByteArray = [0xAA, 0xBB].into();
181 let b2 = ByteArray::from([0x11, 0x22, 0x33]);
182 let res = b1 & b2;
183
184 assert_eq!(res.len(), 3);
185 assert_eq!(res[0], 0xFF & 0x11);
186 assert_eq!(res[1], 0xAA & 0x22);
187 assert_eq!(res[2], 0xBB & 0x33);
188 }
189
190 #[test]
191 fn test_and_single_byte() {
192 let b1 = ByteArray::from([0xFF, 0xAA, 0x55]);
193 let b2 = ByteArray::from(0x0F);
194 let res = b1 & b2;
195
196 assert_eq!(res.len(), 3);
197 assert_eq!(res[0], 0xFF);
198 assert_eq!(res[1], 0xFF & 0xAA);
199 assert_eq!(res[2], 0x55 & 0x0F);
200 }
201
202 #[test]
203 fn test_and_assign() {
204 let mut b1: ByteArray = [0xFF, 0xAA, 0x55].into();
205 let b2 = ByteArray::from([0x0F, 0xF0, 0x33]);
206 b1 &= b2;
207
208 assert_eq!(b1.len(), 3);
209 assert_eq!(b1[0], 0xFF & 0x0F);
210 assert_eq!(b1[1], 0xAA & 0xF0);
211 assert_eq!(b1[2], 0x55 & 0x33);
212 }
213
214 #[test]
215 fn test_or_simple() {
216 let b1: ByteArray = [0x0F, 0xAA, 0x55].into();
217 let b2 = ByteArray::from([0xF0, 0x55, 0xAA]);
218 let res = b1 | b2;
219
220 assert_eq!(res.len(), 3);
221 assert_eq!(res[0], 0x0F | 0xF0);
222 assert_eq!(res[1], 0xAA | 0x55);
223 assert_eq!(res[2], 0x55 | 0xAA);
224 }
225
226 #[test]
227 fn test_or_unequal_length() {
228 let b1: ByteArray = [0xAA, 0xBB].into();
229 let b2 = ByteArray::from([0x11, 0x22, 0x33]);
230 let res = b1 | b2;
231
232 assert_eq!(res.len(), 3);
233 assert_eq!(res[0], 0x00 | 0x11);
234 assert_eq!(res[1], 0xAA | 0x22);
235 assert_eq!(res[2], 0xBB | 0x33);
236 }
237
238 #[test]
239 fn test_or_single_byte() {
240 let b1 = ByteArray::from([0x10, 0x20, 0x30]);
241 let b2 = ByteArray::from(0x0F);
242 let res = b1 | b2;
243
244 assert_eq!(res.len(), 3);
245 assert_eq!(res[0], 0x10);
246 assert_eq!(res[1], 0x20);
247 assert_eq!(res[2], 0x30 | 0x0F);
248 }
249
250 #[test]
251 fn test_or_assign() {
252 let mut b1: ByteArray = [0x0F, 0xAA, 0x55].into();
253 let b2 = ByteArray::from([0xF0, 0x55, 0xAA]);
254 b1 |= b2;
255
256 assert_eq!(b1.len(), 3);
257 assert_eq!(b1[0], 0x0F | 0xF0);
258 assert_eq!(b1[1], 0xAA | 0x55);
259 assert_eq!(b1[2], 0x55 | 0xAA);
260 }
261
262 #[test]
263 fn test_not_simple() {
264 let b1: ByteArray = [0xFF, 0x00, 0xAA].into();
265 let res = !b1;
266
267 assert_eq!(res.len(), 3);
268 assert_eq!(res[0], !0xFF);
269 assert_eq!(res[1], !0x00);
270 assert_eq!(res[2], !0xAA);
271 }
272
273 #[test]
274 fn test_not_all_ones() {
275 let b1: ByteArray = [0xFF, 0xFF, 0xFF].into();
276 let res = !b1;
277
278 assert_eq!(res.len(), 3);
279 assert_eq!(res.as_bytes(), [0x00, 0x00, 0x00]);
280 }
281
282 #[test]
283 fn test_not_all_zeros() {
284 let b1: ByteArray = [0x00, 0x00, 0x00].into();
285 let res = !b1;
286
287 assert_eq!(res.len(), 3);
288 assert_eq!(res.as_bytes(), [0xFF, 0xFF, 0xFF]);
289 }
290
291 #[test]
292 fn test_not_single_byte() {
293 let b1 = ByteArray::from(0x55);
294 let res = !b1;
295
296 assert_eq!(res.len(), 1);
297 assert_eq!(res[0], 0xAA);
298 }
299
300 #[test]
301 fn test_combined_operations() {
302 let b1: ByteArray = [0xFF, 0x00].into();
303 let b2: ByteArray = [0xF0, 0x0F].into();
304 let b3: ByteArray = [0x55, 0xAA].into();
305
306 let res = (b1 ^ b2) & b3;
307
308 assert_eq!(res.len(), 2);
309 assert_eq!(res[0], (0xFF ^ 0xF0) & 0x55);
310 assert_eq!(res[1], (0x00 ^ 0x0F) & 0xAA);
311 }
312
313 #[test]
314 fn test_chained_xor_assign() {
315 let mut b1: ByteArray = [0xFF, 0xFF].into();
316 let b2: ByteArray = [0x0F, 0xF0].into();
317 let b3: ByteArray = [0x11, 0x22].into();
318
319 b1 ^= b2;
320 b1 ^= b3;
321
322 assert_eq!(b1[0], 0xFF ^ 0x0F ^ 0x11);
323 assert_eq!(b1[1], 0xFF ^ 0xF0 ^ 0x22);
324 }
325}