ps_uuid/implementations/ops/neg.rs
1//! Unary negation operator implementation for UUID.
2//!
3//! This module provides the implementation for:
4//!
5//! | Operator | Trait | Semantics |
6//! |----------|-------|-----------|
7//! | `-` (unary) | [`Neg`] | Two's complement negation |
8//!
9//! # Two's Complement Negation
10//!
11//! Negation uses **two's complement** semantics, which is the standard for
12//! representing signed integers in binary. For a value `x`, `-x` is computed as
13//! `!x + 1` (bitwise NOT plus one).
14//!
15//! This means:
16//!
17//! - `-UUID::nil()` = `UUID::nil()` (0 is its own negation)
18//! - `-UUID::from(1u128)` = `UUID::max()` (equivalent to -1 in two's complement)
19//! - `-UUID::max()` = `UUID::from(1u128)` (negating -1 gives 1)
20//!
21//! # Mathematical Properties
22//!
23//! - `x + (-x) = 0` (additive inverse)
24//! - `-(-x) = x` (involution)
25//! - `-0 = 0` (zero is its own negation)
26//!
27//! # Supported Operand Combinations
28//!
29//! - `-UUID`
30//! - `-&UUID`
31//!
32//! # Examples
33//!
34//! ```
35//! use ps_uuid::UUID;
36//!
37//! // Negating 1 gives the two's complement representation of -1
38//! let one = UUID::from(1u128);
39//! assert_eq!(-one, UUID::max());
40//!
41//! // Negating max (which represents -1 in two's complement) gives 1
42//! assert_eq!(-UUID::max(), UUID::from(1u128));
43//!
44//! // Zero is its own negation
45//! assert_eq!(-UUID::nil(), UUID::nil());
46//!
47//! // Additive inverse property
48//! let uuid = UUID::from(42u128);
49//! assert_eq!(uuid + (-uuid), UUID::nil());
50//!
51//! // Double negation is identity
52//! let uuid = UUID::from(12345u128);
53//! assert_eq!(-(-uuid), uuid);
54//! ```
55
56use core::ops::Neg;
57
58use crate::UUID;
59
60// ============================================================================
61// Negation Implementations
62// ============================================================================
63
64impl Neg for UUID {
65 type Output = Self;
66
67 #[inline]
68 fn neg(self) -> Self::Output {
69 Self::from_u128(self.to_u128().wrapping_neg())
70 }
71}
72
73impl Neg for &UUID {
74 type Output = UUID;
75
76 #[inline]
77 fn neg(self) -> Self::Output {
78 UUID::from_u128(self.to_u128().wrapping_neg())
79 }
80}
81
82// ============================================================================
83// Tests
84// ============================================================================
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89
90 // -------------------------------------------------------------------------
91 // Basic negation tests
92 // -------------------------------------------------------------------------
93
94 #[test]
95 fn neg_zero() {
96 assert_eq!(-UUID::nil(), UUID::nil());
97 }
98
99 #[test]
100 fn neg_one() {
101 let one = UUID::from(1u128);
102 // -1 in two's complement is all 1s
103 assert_eq!(-one, UUID::max());
104 }
105
106 #[test]
107 fn neg_max() {
108 // max is all 1s, which represents -1 in two's complement
109 // -(-1) = 1
110 assert_eq!(-UUID::max(), UUID::from(1u128));
111 }
112
113 #[test]
114 fn neg_two() {
115 let two = UUID::from(2u128);
116 // -2 in two's complement is u128::MAX - 1
117 assert_eq!(u128::from(-two), u128::MAX - 1);
118 }
119
120 #[test]
121 fn neg_ref_uuid() {
122 let uuid = UUID::from(1u128);
123 assert_eq!(-&uuid, UUID::max());
124 }
125
126 // -------------------------------------------------------------------------
127 // Mathematical property tests
128 // -------------------------------------------------------------------------
129
130 #[test]
131 fn additive_inverse() {
132 // x + (-x) = 0
133 let values = [0u128, 1, 42, 12345, u128::MAX / 2, u128::MAX];
134 for v in values {
135 let uuid = UUID::from(v);
136 assert_eq!(
137 uuid + (-uuid),
138 UUID::nil(),
139 "additive inverse failed for {v}"
140 );
141 }
142 }
143
144 #[test]
145 fn double_negation_is_identity() {
146 // -(-x) = x
147 let values = [0u128, 1, 42, 12345, u128::MAX / 2, u128::MAX];
148 for v in values {
149 let uuid = UUID::from(v);
150 assert_eq!(-(-uuid), uuid, "double negation failed for {v}");
151 }
152 }
153
154 #[test]
155 fn negation_is_equivalent_to_not_plus_one() {
156 // -x = !x + 1
157 let values = [0u128, 1, 42, 12345, u128::MAX / 2, u128::MAX];
158 for v in values {
159 let uuid = UUID::from(v);
160 let negated = -uuid;
161 let not_plus_one = !uuid + 1u32;
162 assert_eq!(negated, not_plus_one, "neg != !x+1 for {v}");
163 }
164 }
165
166 #[test]
167 fn subtraction_via_negation() {
168 // a - b = a + (-b)
169 let a = UUID::from(100u128);
170 let b = UUID::from(30u128);
171 assert_eq!(a - b, a + (-b));
172 }
173
174 // -------------------------------------------------------------------------
175 // Two's complement representation tests
176 // -------------------------------------------------------------------------
177
178 #[test]
179 fn twos_complement_minus_one() {
180 // -1 in two's complement is represented as all 1s
181 let minus_one = -UUID::from(1u128);
182 assert_eq!(minus_one, UUID::max());
183 assert!(minus_one.as_bytes().iter().all(|&b| b == 0xFF));
184 }
185
186 #[test]
187 fn twos_complement_minus_two() {
188 // -2 in two's complement
189 let minus_two = -UUID::from(2u128);
190 assert_eq!(u128::from(minus_two), u128::MAX - 1);
191 // All bytes are 0xFF except the last byte is 0xFE
192 let bytes = minus_two.as_bytes();
193 assert!(bytes[..15].iter().all(|&b| b == 0xFF));
194 assert_eq!(bytes[15], 0xFE);
195 }
196
197 #[test]
198 fn twos_complement_high_bit() {
199 // The value 1 << 127 (high bit set) represents the minimum signed value
200 let high_bit = UUID::from(1u128 << 127);
201 // Negating it wraps back to itself (overflow)
202 assert_eq!(-high_bit, high_bit);
203 }
204
205 // -------------------------------------------------------------------------
206 // Edge case tests
207 // -------------------------------------------------------------------------
208
209 #[test]
210 fn neg_various_patterns() {
211 // Test various bit patterns
212 let patterns = [
213 0b1010_1010u128,
214 0b1111_0000u128,
215 0x0123_4567_89ab_cdef_u128,
216 (1u128 << 64) - 1, // Lower 64 bits set
217 1u128 << 64, // Only bit 64 set
218 ];
219 for v in patterns {
220 let uuid = UUID::from(v);
221 // Verify additive inverse property
222 assert_eq!(
223 uuid + (-uuid),
224 UUID::nil(),
225 "additive inverse failed for {v:#x}"
226 );
227 // Verify double negation
228 assert_eq!(-(-uuid), uuid, "double negation failed for {v:#x}");
229 }
230 }
231
232 #[test]
233 fn neg_consecutive_values() {
234 // Negations of consecutive values should differ by 1
235 for v in 0u128..100 {
236 let neg_v = -UUID::from(v);
237 let neg_v_plus_1 = -UUID::from(v + 1);
238 // -v and -(v+1) should differ by 1
239 // Note: -v - 1 = -(v+1)
240 assert_eq!(neg_v - 1u32, neg_v_plus_1);
241 }
242 }
243}