Skip to main content

ps_uuid/implementations/ops/
index.rs

1//! Index operator implementations for UUID.
2//!
3//! This module provides implementations for:
4//!
5//! | Trait | Description |
6//! |-------|-------------|
7//! | [`Index`] | Immutable byte access via `uuid[i]` |
8//! | [`IndexMut`] | Mutable byte access via `uuid[i]` |
9//!
10//! # Byte Order
11//!
12//! UUID uses **big-endian** byte order:
13//!
14//! - `uuid[0]` is the **most significant** byte
15//! - `uuid[15]` is the **least significant** byte
16//!
17//! # Supported Index Types
18//!
19//! Single element access:
20//! - `usize` - Access a single byte
21//!
22//! Range access:
23//! - `Range<usize>` (`a..b`) - Exclusive range
24//! - `RangeFrom<usize>` (`a..`) - From index to end
25//! - `RangeTo<usize>` (`..b`) - From start to index
26//! - `RangeFull` (`..`) - All bytes
27//! - `RangeInclusive<usize>` (`a..=b`) - Inclusive range
28//! - `RangeToInclusive<usize>` (`..=b`) - From start to index (inclusive)
29//!
30//! # Panics
31//!
32//! Indexing operations will panic if the index is out of bounds (>= 16 for
33//! single access, or if the range exceeds the bounds).
34//!
35//! # Examples
36//!
37//! ```
38//! use ps_uuid::UUID;
39//!
40//! let uuid = UUID::from(0xFF00_0000_0000_0000_0000_0000_0000_00FFu128);
41//!
42//! // Single byte access (big-endian)
43//! assert_eq!(uuid[0], 0xFF);   // Most significant byte
44//! assert_eq!(uuid[15], 0xFF);  // Least significant byte
45//! assert_eq!(uuid[1], 0x00);
46//!
47//! // Range access
48//! assert_eq!(&uuid[0..2], &[0xFF, 0x00]);
49//! assert_eq!(&uuid[14..], &[0x00, 0xFF]);
50//!
51//! // Mutable access
52//! let mut uuid = UUID::nil();
53//! uuid[0] = 0xAB;
54//! uuid[15] = 0xCD;
55//! assert_eq!(uuid[0], 0xAB);
56//! assert_eq!(uuid[15], 0xCD);
57//!
58//! // Mutable range access
59//! let mut uuid = UUID::nil();
60//! uuid[0..4].copy_from_slice(&[0x01, 0x02, 0x03, 0x04]);
61//! assert_eq!(&uuid[0..4], &[0x01, 0x02, 0x03, 0x04]);
62//! ```
63
64use core::ops::{
65    Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive,
66};
67
68use crate::UUID;
69
70// ============================================================================
71// Single Element Indexing
72// ============================================================================
73
74impl Index<usize> for UUID {
75    type Output = u8;
76
77    #[inline]
78    fn index(&self, index: usize) -> &Self::Output {
79        &self.as_bytes()[index]
80    }
81}
82
83impl IndexMut<usize> for UUID {
84    #[inline]
85    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
86        &mut self.as_mut_bytes()[index]
87    }
88}
89
90// ============================================================================
91// Range Indexing: Range<usize> (a..b)
92// ============================================================================
93
94impl Index<Range<usize>> for UUID {
95    type Output = [u8];
96
97    #[inline]
98    fn index(&self, index: Range<usize>) -> &Self::Output {
99        &self.as_bytes()[index]
100    }
101}
102
103impl IndexMut<Range<usize>> for UUID {
104    #[inline]
105    fn index_mut(&mut self, index: Range<usize>) -> &mut Self::Output {
106        &mut self.as_mut_bytes()[index]
107    }
108}
109
110// ============================================================================
111// Range Indexing: RangeFrom<usize> (a..)
112// ============================================================================
113
114impl Index<RangeFrom<usize>> for UUID {
115    type Output = [u8];
116
117    #[inline]
118    fn index(&self, index: RangeFrom<usize>) -> &Self::Output {
119        &self.as_bytes()[index]
120    }
121}
122
123impl IndexMut<RangeFrom<usize>> for UUID {
124    #[inline]
125    fn index_mut(&mut self, index: RangeFrom<usize>) -> &mut Self::Output {
126        &mut self.as_mut_bytes()[index]
127    }
128}
129
130// ============================================================================
131// Range Indexing: RangeTo<usize> (..b)
132// ============================================================================
133
134impl Index<RangeTo<usize>> for UUID {
135    type Output = [u8];
136
137    #[inline]
138    fn index(&self, index: RangeTo<usize>) -> &Self::Output {
139        &self.as_bytes()[index]
140    }
141}
142
143impl IndexMut<RangeTo<usize>> for UUID {
144    #[inline]
145    fn index_mut(&mut self, index: RangeTo<usize>) -> &mut Self::Output {
146        &mut self.as_mut_bytes()[index]
147    }
148}
149
150// ============================================================================
151// Range Indexing: RangeFull (..)
152// ============================================================================
153
154impl Index<RangeFull> for UUID {
155    type Output = [u8];
156
157    #[inline]
158    fn index(&self, _index: RangeFull) -> &Self::Output {
159        self.as_bytes()
160    }
161}
162
163impl IndexMut<RangeFull> for UUID {
164    #[inline]
165    fn index_mut(&mut self, _index: RangeFull) -> &mut Self::Output {
166        self.as_mut_bytes()
167    }
168}
169
170// ============================================================================
171// Range Indexing: RangeInclusive<usize> (a..=b)
172// ============================================================================
173
174impl Index<RangeInclusive<usize>> for UUID {
175    type Output = [u8];
176
177    #[inline]
178    fn index(&self, index: RangeInclusive<usize>) -> &Self::Output {
179        &self.as_bytes()[index]
180    }
181}
182
183impl IndexMut<RangeInclusive<usize>> for UUID {
184    #[inline]
185    fn index_mut(&mut self, index: RangeInclusive<usize>) -> &mut Self::Output {
186        &mut self.as_mut_bytes()[index]
187    }
188}
189
190// ============================================================================
191// Range Indexing: RangeToInclusive<usize> (..=b)
192// ============================================================================
193
194impl Index<RangeToInclusive<usize>> for UUID {
195    type Output = [u8];
196
197    #[inline]
198    fn index(&self, index: RangeToInclusive<usize>) -> &Self::Output {
199        &self.as_bytes()[index]
200    }
201}
202
203impl IndexMut<RangeToInclusive<usize>> for UUID {
204    #[inline]
205    fn index_mut(&mut self, index: RangeToInclusive<usize>) -> &mut Self::Output {
206        &mut self.as_mut_bytes()[index]
207    }
208}
209
210// ============================================================================
211// Tests
212// ============================================================================
213
214#[cfg(test)]
215mod tests {
216    use super::*;
217
218    // -------------------------------------------------------------------------
219    // Single element access tests
220    // -------------------------------------------------------------------------
221
222    #[test]
223    fn index_first_byte() {
224        let uuid = UUID::from(0xFF00_0000_0000_0000_0000_0000_0000_0000u128);
225        assert_eq!(uuid[0], 0xFF);
226    }
227
228    #[test]
229    fn index_last_byte() {
230        let uuid = UUID::from(0x0000_0000_0000_0000_0000_0000_0000_00FFu128);
231        assert_eq!(uuid[15], 0xFF);
232    }
233
234    #[test]
235    fn index_middle_bytes() {
236        let uuid = UUID::from(0x0000_0000_0000_00FF_FF00_0000_0000_0000u128);
237        assert_eq!(uuid[7], 0xFF);
238        assert_eq!(uuid[8], 0xFF);
239    }
240
241    #[test]
242    fn index_all_bytes() {
243        let uuid = UUID::from(0x0011_2233_4455_6677_8899_aabb_ccdd_eeffu128);
244        assert_eq!(uuid[0], 0x00);
245        assert_eq!(uuid[1], 0x11);
246        assert_eq!(uuid[2], 0x22);
247        assert_eq!(uuid[3], 0x33);
248        assert_eq!(uuid[4], 0x44);
249        assert_eq!(uuid[5], 0x55);
250        assert_eq!(uuid[6], 0x66);
251        assert_eq!(uuid[7], 0x77);
252        assert_eq!(uuid[8], 0x88);
253        assert_eq!(uuid[9], 0x99);
254        assert_eq!(uuid[10], 0xaa);
255        assert_eq!(uuid[11], 0xbb);
256        assert_eq!(uuid[12], 0xcc);
257        assert_eq!(uuid[13], 0xdd);
258        assert_eq!(uuid[14], 0xee);
259        assert_eq!(uuid[15], 0xff);
260    }
261
262    #[test]
263    fn index_nil() {
264        let uuid = UUID::nil();
265        for i in 0..16 {
266            assert_eq!(uuid[i], 0);
267        }
268    }
269
270    #[test]
271    fn index_max() {
272        let uuid = UUID::max();
273        for i in 0..16 {
274            assert_eq!(uuid[i], 0xFF);
275        }
276    }
277
278    #[test]
279    #[should_panic(expected = "index out of bounds")]
280    fn index_out_of_bounds() {
281        let uuid = UUID::nil();
282        let _ = uuid[16];
283    }
284
285    // -------------------------------------------------------------------------
286    // Mutable single element access tests
287    // -------------------------------------------------------------------------
288
289    #[test]
290    fn index_mut_first_byte() {
291        let mut uuid = UUID::nil();
292        uuid[0] = 0xAB;
293        assert_eq!(uuid[0], 0xAB);
294        assert_eq!(uuid.as_bytes()[0], 0xAB);
295    }
296
297    #[test]
298    fn index_mut_last_byte() {
299        let mut uuid = UUID::nil();
300        uuid[15] = 0xCD;
301        assert_eq!(uuid[15], 0xCD);
302        assert_eq!(uuid.as_bytes()[15], 0xCD);
303    }
304
305    #[test]
306    #[allow(clippy::cast_possible_truncation)]
307    fn index_mut_all_bytes() {
308        let mut uuid = UUID::nil();
309        for i in 0..16 {
310            uuid[i] = i as u8;
311        }
312        for i in 0..16 {
313            assert_eq!(uuid[i], i as u8);
314        }
315    }
316
317    #[test]
318    #[should_panic(expected = "index out of bounds")]
319    fn index_mut_out_of_bounds() {
320        let mut uuid = UUID::nil();
321        uuid[16] = 0xFF;
322    }
323
324    // -------------------------------------------------------------------------
325    // Range indexing tests: Range<usize> (a..b)
326    // -------------------------------------------------------------------------
327
328    #[test]
329    fn index_range() {
330        let uuid = UUID::from(0x0102_0304_0506_0708_090a_0b0c_0d0e_0f10u128);
331        assert_eq!(&uuid[0..4], &[0x01, 0x02, 0x03, 0x04]);
332        assert_eq!(&uuid[4..8], &[0x05, 0x06, 0x07, 0x08]);
333        assert_eq!(&uuid[12..16], &[0x0d, 0x0e, 0x0f, 0x10]);
334    }
335
336    #[test]
337    fn index_range_empty() {
338        let uuid = UUID::nil();
339        assert_eq!(&uuid[0..0], &[] as &[u8]);
340        assert_eq!(&uuid[8..8], &[] as &[u8]);
341    }
342
343    #[test]
344    fn index_range_full() {
345        let uuid = UUID::from(0x0102_0304_0506_0708_090a_0b0c_0d0e_0f10u128);
346        assert_eq!(uuid[0..16].len(), 16);
347    }
348
349    #[test]
350    fn index_mut_range() {
351        let mut uuid = UUID::nil();
352        uuid[0..4].copy_from_slice(&[0x01, 0x02, 0x03, 0x04]);
353        assert_eq!(&uuid[0..4], &[0x01, 0x02, 0x03, 0x04]);
354        assert_eq!(&uuid[4..16], &[0; 12]);
355    }
356
357    // -------------------------------------------------------------------------
358    // Range indexing tests: RangeFrom<usize> (a..)
359    // -------------------------------------------------------------------------
360
361    #[test]
362    fn index_range_from() {
363        let uuid = UUID::from(0x0102_0304_0506_0708_090a_0b0c_0d0e_0f10u128);
364        assert_eq!(&uuid[14..], &[0x0f, 0x10]);
365        assert_eq!(&uuid[0..].len(), &16);
366    }
367
368    #[test]
369    fn index_mut_range_from() {
370        let mut uuid = UUID::nil();
371        uuid[14..].copy_from_slice(&[0xAB, 0xCD]);
372        assert_eq!(&uuid[14..], &[0xAB, 0xCD]);
373    }
374
375    // -------------------------------------------------------------------------
376    // Range indexing tests: RangeTo<usize> (..b)
377    // -------------------------------------------------------------------------
378
379    #[test]
380    fn index_range_to() {
381        let uuid = UUID::from(0x0102_0304_0506_0708_090a_0b0c_0d0e_0f10u128);
382        assert_eq!(&uuid[..2], &[0x01, 0x02]);
383        assert_eq!(&uuid[..16].len(), &16);
384    }
385
386    #[test]
387    fn index_mut_range_to() {
388        let mut uuid = UUID::nil();
389        uuid[..2].copy_from_slice(&[0xAB, 0xCD]);
390        assert_eq!(&uuid[..2], &[0xAB, 0xCD]);
391    }
392
393    // -------------------------------------------------------------------------
394    // Range indexing tests: RangeFull (..)
395    // -------------------------------------------------------------------------
396
397    #[test]
398    fn index_range_full_slice() {
399        let uuid = UUID::from(0x0102_0304_0506_0708_090a_0b0c_0d0e_0f10u128);
400        assert_eq!(&uuid[..], uuid.as_bytes().as_slice());
401    }
402
403    #[test]
404    #[allow(clippy::cast_possible_truncation)]
405    fn index_mut_range_full() {
406        let mut uuid = UUID::nil();
407        uuid[..].copy_from_slice(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
408        for i in 0..16 {
409            assert_eq!(uuid[i], (i + 1) as u8);
410        }
411    }
412
413    // -------------------------------------------------------------------------
414    // Range indexing tests: RangeInclusive<usize> (a..=b)
415    // -------------------------------------------------------------------------
416
417    #[test]
418    fn index_range_inclusive() {
419        let uuid = UUID::from(0x0102_0304_0506_0708_090a_0b0c_0d0e_0f10u128);
420        assert_eq!(&uuid[0..=3], &[0x01, 0x02, 0x03, 0x04]);
421        assert_eq!(&uuid[14..=15], &[0x0f, 0x10]);
422    }
423
424    #[test]
425    fn index_mut_range_inclusive() {
426        let mut uuid = UUID::nil();
427        uuid[0..=3].copy_from_slice(&[0x01, 0x02, 0x03, 0x04]);
428        assert_eq!(&uuid[0..=3], &[0x01, 0x02, 0x03, 0x04]);
429    }
430
431    // -------------------------------------------------------------------------
432    // Range indexing tests: RangeToInclusive<usize> (..=b)
433    // -------------------------------------------------------------------------
434
435    #[test]
436    fn index_range_to_inclusive() {
437        let uuid = UUID::from(0x0102_0304_0506_0708_090a_0b0c_0d0e_0f10u128);
438        assert_eq!(&uuid[..=1], &[0x01, 0x02]);
439        assert_eq!(&uuid[..=15].len(), &16);
440    }
441
442    #[test]
443    fn index_mut_range_to_inclusive() {
444        let mut uuid = UUID::nil();
445        uuid[..=1].copy_from_slice(&[0xAB, 0xCD]);
446        assert_eq!(&uuid[..=1], &[0xAB, 0xCD]);
447    }
448
449    // -------------------------------------------------------------------------
450    // Big-endian byte order verification
451    // -------------------------------------------------------------------------
452
453    #[test]
454    fn big_endian_byte_order() {
455        // UUID stores bytes in big-endian order
456        // The value 0x0123456789ABCDEF should have:
457        // - bytes[0..8] = 00 00 00 00 00 00 00 00 (high bytes)
458        // - bytes[8..16] = 01 23 45 67 89 AB CD EF (low bytes)
459        let uuid = UUID::from(0x0123_4567_89AB_CDEFu128);
460
461        // First 8 bytes are zero (high bits)
462        for i in 0..8 {
463            assert_eq!(uuid[i], 0x00, "byte {i} should be 0");
464        }
465
466        // Last 8 bytes contain the value
467        assert_eq!(uuid[8], 0x01);
468        assert_eq!(uuid[9], 0x23);
469        assert_eq!(uuid[10], 0x45);
470        assert_eq!(uuid[11], 0x67);
471        assert_eq!(uuid[12], 0x89);
472        assert_eq!(uuid[13], 0xAB);
473        assert_eq!(uuid[14], 0xCD);
474        assert_eq!(uuid[15], 0xEF);
475    }
476
477    // -------------------------------------------------------------------------
478    // Consistency with as_bytes()
479    // -------------------------------------------------------------------------
480
481    #[test]
482    fn index_consistent_with_as_bytes() {
483        let uuid = UUID::from(0x0123_4567_89AB_CDEF_FEDC_BA98_7654_3210u128);
484        let bytes = uuid.as_bytes();
485
486        for i in 0..16 {
487            assert_eq!(uuid[i], bytes[i], "index[{i}] differs from as_bytes()[{i}]");
488        }
489    }
490
491    #[test]
492    fn index_range_consistent_with_as_bytes() {
493        let uuid = UUID::from(0x0123_4567_89AB_CDEF_FEDC_BA98_7654_3210u128);
494        let bytes = uuid.as_bytes();
495
496        assert_eq!(&uuid[0..8], &bytes[0..8]);
497        assert_eq!(&uuid[8..16], &bytes[8..16]);
498        assert_eq!(&uuid[..], bytes.as_slice());
499    }
500}