Skip to main content

ps_uuid/implementations/ops/
bitwise.rs

1//! Bitwise operator implementations for UUID.
2//!
3//! This module provides implementations for:
4//!
5//! | Operator | Trait | Description |
6//! |----------|-------|-------------|
7//! | `&` | [`BitAnd`] | Bitwise AND |
8//! | `\|` | [`BitOr`] | Bitwise OR |
9//! | `^` | [`BitXor`] | Bitwise XOR |
10//! | `!` | [`Not`] | Bitwise NOT (complement) |
11//!
12//! # Supported Operand Combinations
13//!
14//! Binary operators (`&`, `|`, `^`) support:
15//!
16//! - `UUID op UUID` and ref variants
17//! - `UUID op T` where `T: IntOperand` (all integer types)
18//! - `T op UUID` where `T: IntOperand`
19//! - Compound assignment: `UUID op= UUID`, `UUID op= T`
20//!
21//! Unary NOT (`!`) supports:
22//!
23//! - `!UUID`
24//! - `!&UUID`
25//!
26//! # Examples
27//!
28//! ```
29//! use ps_uuid::UUID;
30//!
31//! // Bitwise AND - useful for masking
32//! let uuid = UUID::from(0b1010_1010u128);
33//! let mask = UUID::from(0b1111_0000u128);
34//! assert_eq!(u128::from(uuid & mask), 0b1010_0000);
35//!
36//! // Bitwise OR - useful for setting bits
37//! let uuid = UUID::from(0b1010_0000u128);
38//! let bits = 0b0000_1010u32;
39//! assert_eq!(u128::from(uuid | bits), 0b1010_1010);
40//!
41//! // Bitwise XOR - useful for toggling bits
42//! let uuid = UUID::from(0b1010_1010u128);
43//! assert_eq!(u128::from(uuid ^ 0b1111_1111u32), 0b0101_0101);
44//!
45//! // Bitwise NOT - inverts all bits
46//! let uuid = UUID::nil();
47//! assert_eq!(!uuid, UUID::max());
48//! assert_eq!(!UUID::max(), UUID::nil());
49//! ```
50
51use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not};
52
53use crate::UUID;
54
55use super::int_operand::IntOperand;
56use super::{
57    impl_binop_uuid_uuid, impl_int_op_uuid_commutative, impl_ref_lhs_uuid, impl_uuid_op_int,
58};
59
60// ============================================================================
61// UUID op UUID Implementations
62// ============================================================================
63
64impl_binop_uuid_uuid!(BitAnd, bitand, BitAndAssign, bitand_assign, u128::bitand);
65impl_binop_uuid_uuid!(BitOr, bitor, BitOrAssign, bitor_assign, u128::bitor);
66impl_binop_uuid_uuid!(BitXor, bitxor, BitXorAssign, bitxor_assign, u128::bitxor);
67
68impl_ref_lhs_uuid!(BitAnd, bitand);
69impl_ref_lhs_uuid!(BitOr, bitor);
70impl_ref_lhs_uuid!(BitXor, bitxor);
71
72// ============================================================================
73// UUID op T Implementations (where T: IntOperand)
74// ============================================================================
75
76impl_uuid_op_int!(BitAnd, bitand, BitAndAssign, bitand_assign, u128::bitand);
77impl_uuid_op_int!(BitOr, bitor, BitOrAssign, bitor_assign, u128::bitor);
78impl_uuid_op_int!(BitXor, bitxor, BitXorAssign, bitxor_assign, u128::bitxor);
79
80// ============================================================================
81// T op UUID Implementations (where T: IntOperand)
82// ============================================================================
83
84// All bitwise operations are commutative
85impl_int_op_uuid_commutative!(
86    BitAnd, bitand, u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
87);
88impl_int_op_uuid_commutative!(
89    BitOr, bitor, u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
90);
91impl_int_op_uuid_commutative!(
92    BitXor, bitxor, u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
93);
94
95// ============================================================================
96// Bitwise NOT
97// ============================================================================
98
99impl Not for UUID {
100    type Output = Self;
101
102    #[inline]
103    fn not(self) -> Self::Output {
104        Self::from_u128(!self.to_u128())
105    }
106}
107
108impl Not for &UUID {
109    type Output = UUID;
110
111    #[inline]
112    fn not(self) -> Self::Output {
113        UUID::from_u128(!self.to_u128())
114    }
115}
116
117// ============================================================================
118// Tests
119// ============================================================================
120
121#[cfg(test)]
122mod tests {
123    #![allow(clippy::op_ref)]
124
125    use super::*;
126
127    // -------------------------------------------------------------------------
128    // Bitwise AND tests
129    // -------------------------------------------------------------------------
130
131    #[test]
132    fn bitand_uuid_uuid() {
133        let a = UUID::from(0b1010_1010u128);
134        let b = UUID::from(0b1100_1100u128);
135        assert_eq!(u128::from(a & b), 0b1000_1000);
136    }
137
138    #[test]
139    fn bitand_uuid_ref_uuid() {
140        let a = UUID::from(0b1010_1010u128);
141        let b = UUID::from(0b1100_1100u128);
142        assert_eq!(u128::from(a & &b), 0b1000_1000);
143    }
144
145    #[test]
146    fn bitand_ref_uuid_uuid() {
147        let a = UUID::from(0b1010_1010u128);
148        let b = UUID::from(0b1100_1100u128);
149        assert_eq!(u128::from(&a & b), 0b1000_1000);
150    }
151
152    #[test]
153    fn bitand_ref_uuid_ref_uuid() {
154        let a = UUID::from(0b1010_1010u128);
155        let b = UUID::from(0b1100_1100u128);
156        assert_eq!(u128::from(&a & &b), 0b1000_1000);
157    }
158
159    #[test]
160    fn bitand_uuid_int() {
161        let uuid = UUID::from(0b1010_1010u128);
162        assert_eq!(u128::from(uuid & 0b1100_1100u8), 0b1000_1000);
163        assert_eq!(u128::from(uuid & 0b1100_1100u16), 0b1000_1000);
164        assert_eq!(u128::from(uuid & 0b1100_1100u32), 0b1000_1000);
165        assert_eq!(u128::from(uuid & 0b1100_1100u64), 0b1000_1000);
166        assert_eq!(u128::from(uuid & 0b1100_1100u128), 0b1000_1000);
167    }
168
169    #[test]
170    fn bitand_int_uuid() {
171        let uuid = UUID::from(0b1010_1010u128);
172        assert_eq!(u128::from(0b1100_1100u32 & uuid), 0b1000_1000);
173    }
174
175    #[test]
176    fn bitand_int_ref_uuid() {
177        let uuid = UUID::from(0b1010_1010u128);
178        assert_eq!(u128::from(0b1100_1100u32 & &uuid), 0b1000_1000);
179    }
180
181    #[test]
182    fn bitand_ref_int_uuid() {
183        let uuid = UUID::from(0b1010_1010u128);
184        let n = 0b1100_1100u32;
185        assert_eq!(u128::from(&n & uuid), 0b1000_1000);
186    }
187
188    #[test]
189    fn bitand_ref_int_ref_uuid() {
190        let uuid = UUID::from(0b1010_1010u128);
191        let n = 0b1100_1100u32;
192        assert_eq!(u128::from(&n & &uuid), 0b1000_1000);
193    }
194
195    #[test]
196    fn bitand_assign() {
197        let mut uuid = UUID::from(0b1010_1010u128);
198        uuid &= 0b1100_1100u32;
199        assert_eq!(u128::from(uuid), 0b1000_1000);
200    }
201
202    #[test]
203    fn bitand_assign_uuid() {
204        let mut uuid = UUID::from(0b1010_1010u128);
205        uuid &= UUID::from(0b1100_1100u128);
206        assert_eq!(u128::from(uuid), 0b1000_1000);
207    }
208
209    #[test]
210    #[allow(clippy::erasing_op)]
211    fn bitand_with_zero() {
212        let uuid = UUID::max();
213        assert_eq!(uuid & 0u32, UUID::nil());
214        assert_eq!(uuid & UUID::nil(), UUID::nil());
215    }
216
217    #[test]
218    fn bitand_with_max() {
219        let uuid = UUID::from(0b1010_1010u128);
220        assert_eq!(uuid & UUID::max(), uuid);
221    }
222
223    // -------------------------------------------------------------------------
224    // Bitwise OR tests
225    // -------------------------------------------------------------------------
226
227    #[test]
228    fn bitor_uuid_uuid() {
229        let a = UUID::from(0b1010_0000u128);
230        let b = UUID::from(0b0000_1010u128);
231        assert_eq!(u128::from(a | b), 0b1010_1010);
232    }
233
234    #[test]
235    fn bitor_uuid_int() {
236        let uuid = UUID::from(0b1010_0000u128);
237        assert_eq!(u128::from(uuid | 0b0000_1010u32), 0b1010_1010);
238    }
239
240    #[test]
241    fn bitor_int_uuid() {
242        let uuid = UUID::from(0b1010_0000u128);
243        assert_eq!(u128::from(0b0000_1010u32 | uuid), 0b1010_1010);
244    }
245
246    #[test]
247    fn bitor_assign() {
248        let mut uuid = UUID::from(0b1010_0000u128);
249        uuid |= 0b0000_1010u32;
250        assert_eq!(u128::from(uuid), 0b1010_1010);
251    }
252
253    #[test]
254    fn bitor_with_zero() {
255        let uuid = UUID::from(0b1010_1010u128);
256        assert_eq!(uuid | 0u32, uuid);
257        assert_eq!(uuid | UUID::nil(), uuid);
258    }
259
260    #[test]
261    fn bitor_with_max() {
262        let uuid = UUID::from(0b1010_1010u128);
263        assert_eq!(uuid | UUID::max(), UUID::max());
264    }
265
266    // -------------------------------------------------------------------------
267    // Bitwise XOR tests
268    // -------------------------------------------------------------------------
269
270    #[test]
271    fn bitxor_uuid_uuid() {
272        let a = UUID::from(0b1010_1010u128);
273        let b = UUID::from(0b1100_1100u128);
274        assert_eq!(u128::from(a ^ b), 0b0110_0110);
275    }
276
277    #[test]
278    fn bitxor_uuid_int() {
279        let uuid = UUID::from(0b1010_1010u128);
280        assert_eq!(u128::from(uuid ^ 0b1111_1111u32), 0b0101_0101);
281    }
282
283    #[test]
284    fn bitxor_int_uuid() {
285        let uuid = UUID::from(0b1010_1010u128);
286        assert_eq!(u128::from(0b1111_1111u32 ^ uuid), 0b0101_0101);
287    }
288
289    #[test]
290    fn bitxor_assign() {
291        let mut uuid = UUID::from(0b1010_1010u128);
292        uuid ^= 0b1111_1111u32;
293        assert_eq!(u128::from(uuid), 0b0101_0101);
294    }
295
296    #[test]
297    fn bitxor_with_zero() {
298        let uuid = UUID::from(0b1010_1010u128);
299        assert_eq!(uuid ^ 0u32, uuid);
300        assert_eq!(uuid ^ UUID::nil(), uuid);
301    }
302
303    #[test]
304    fn bitxor_with_self() {
305        let uuid = UUID::from(0b1010_1010u128);
306        assert_eq!(uuid ^ uuid, UUID::nil());
307    }
308
309    #[test]
310    fn bitxor_with_max() {
311        let uuid = UUID::from(0b1010_1010u128);
312        // XOR with all 1s is equivalent to NOT
313        assert_eq!(uuid ^ UUID::max(), !uuid);
314    }
315
316    // -------------------------------------------------------------------------
317    // Bitwise NOT tests
318    // -------------------------------------------------------------------------
319
320    #[test]
321    fn not_uuid() {
322        let uuid = UUID::nil();
323        assert_eq!(!uuid, UUID::max());
324    }
325
326    #[test]
327    fn not_ref_uuid() {
328        let uuid = UUID::nil();
329        assert_eq!(!&uuid, UUID::max());
330    }
331
332    #[test]
333    fn not_max() {
334        assert_eq!(!UUID::max(), UUID::nil());
335    }
336
337    #[test]
338    fn not_involution() {
339        // NOT(NOT(x)) == x
340        let uuid = UUID::from(0x0123_4567_89ab_cdef_u128);
341        assert_eq!(!!uuid, uuid);
342    }
343
344    #[test]
345    fn not_pattern() {
346        let uuid = UUID::from(0b1010_1010u128);
347        assert_eq!(u128::from(!uuid) & 0xFF, 0b0101_0101);
348    }
349
350    // -------------------------------------------------------------------------
351    // De Morgan's laws
352    // -------------------------------------------------------------------------
353
354    #[test]
355    fn de_morgan_and() {
356        // !(a & b) == !a | !b
357        let a = UUID::from(0b1010_1010u128);
358        let b = UUID::from(0b1100_1100u128);
359        assert_eq!(!(a & b), !a | !b);
360    }
361
362    #[test]
363    fn de_morgan_or() {
364        // !(a | b) == !a & !b
365        let a = UUID::from(0b1010_1010u128);
366        let b = UUID::from(0b1100_1100u128);
367        assert_eq!(!(a | b), !a & !b);
368    }
369
370    // -------------------------------------------------------------------------
371    // Negative integer operand tests
372    // -------------------------------------------------------------------------
373
374    #[test]
375    fn bitand_with_negative_int() {
376        // -1i8 sign-extends to all 1s
377        let uuid = UUID::from(0b1010_1010u128);
378        assert_eq!(uuid & (-1i8), uuid); // AND with all 1s is identity
379    }
380
381    #[test]
382    fn bitor_with_negative_int() {
383        // -1i8 sign-extends to all 1s
384        let uuid = UUID::from(0b1010_1010u128);
385        assert_eq!(uuid | (-1i8), UUID::max()); // OR with all 1s is all 1s
386    }
387
388    #[test]
389    fn bitxor_with_negative_int() {
390        // -1i8 sign-extends to all 1s
391        let uuid = UUID::from(0b1010_1010u128);
392        assert_eq!(uuid ^ (-1i8), !uuid); // XOR with all 1s is NOT
393    }
394
395    // -------------------------------------------------------------------------
396    // All reference variant tests
397    // -------------------------------------------------------------------------
398
399    #[test]
400    fn all_reference_variants_bitand() {
401        let a = UUID::from(0b1010u128);
402        let b = UUID::from(0b1100u128);
403        let n = 0b1100u32;
404        let expected = UUID::from(0b1000u128);
405
406        // UUID op UUID variants
407        assert_eq!(a & b, expected);
408        assert_eq!(a & &b, expected);
409        assert_eq!(&a & b, expected);
410        assert_eq!(&a & &b, expected);
411
412        // UUID op T variants
413        assert_eq!(a & n, expected);
414        assert_eq!(&a & n, expected);
415        assert_eq!(a & &n, expected);
416        assert_eq!(&a & &n, expected);
417
418        // T op UUID variants
419        assert_eq!(n & a, expected);
420        assert_eq!(n & &a, expected);
421        assert_eq!(&n & a, expected);
422        assert_eq!(&n & &a, expected);
423    }
424}