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