Skip to main content

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}