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