ps_uuid/methods/from_parts_v6.rs
1use crate::UUID;
2
3// ────────────────────────────────────────────────────────────────────────────
4// v6 constructor from individual wire-format fields
5// ────────────────────────────────────────────────────────────────────────────
6
7impl UUID {
8 /// Builds an RFC-4122 *Version 6* (time-ordered) UUID from its
9 /// constituent fields.
10 ///
11 /// Timestamp layout (big-endian, network order):
12 /// - `time_high` – most-significant 32 bits of the 60-bit timestamp
13 /// - `time_mid` – next 16 bits of the timestamp
14 /// - `time_low` – least-significant 12 bits of the timestamp
15 ///
16 /// Remaining fields:
17 /// - `clock_seq` – 14-bit clock sequence (high-to-low order)
18 /// - `node_id` – 48-bit node identifier (usually a MAC address)
19 ///
20 /// The function performs all bit manipulation internally, then calls
21 /// `.with_version(6)` to patch in the *version* nibble (0b0110) and
22 /// the RFC-4122 variant bits (0b10xxxxxx). It never fails.
23 #[inline]
24 #[must_use]
25 pub fn from_parts_v6(
26 time_high: u32,
27 time_mid: u16,
28 time_low: u16,
29 clock_seq: u16,
30 node_id: [u8; 6],
31 ) -> Self {
32 let mut uuid = Self::nil();
33
34 // Timestamp ---------------------------------------------------------
35 uuid.bytes[0..4].copy_from_slice(&time_high.to_be_bytes());
36 uuid.bytes[4..6].copy_from_slice(&time_mid.to_be_bytes());
37 uuid.bytes[6..8].copy_from_slice(&time_low.to_be_bytes());
38
39 // Clock sequence ----------------------------------------------------
40 uuid.bytes[8..10].copy_from_slice(&clock_seq.to_be_bytes());
41
42 // Node identifier ---------------------------------------------------
43 uuid.bytes[10..16].copy_from_slice(&node_id);
44
45 // Insert version + variant bits -------------------------------------
46 uuid.with_version(6)
47 }
48}
49
50#[cfg(test)]
51mod tests {
52 use crate::{Variant, UUID};
53
54 #[test]
55 fn builds_correct_static_example() {
56 // Timestamp: 0x0123456789abcdef
57 // high 32 → 0x01234567
58 // mid 16 → 0x89ab
59 // low 12 → 0xcdef
60 // Clock-seq: 0x1234
61 // Node ID : 00-01-02-03-04-05
62 let uuid = UUID::from_parts_v6(
63 0x0123_4567,
64 0x89ab,
65 0xcdef,
66 0x1234,
67 [0x00, 0x01, 0x02, 0x03, 0x04, 0x05],
68 );
69 let b = uuid.as_bytes();
70
71 // time_high (bytes 0-3)
72 assert_eq!(&b[0..4], &[0x01, 0x23, 0x45, 0x67]);
73 // time_mid (bytes 4-5)
74 assert_eq!(&b[4..6], &[0x89, 0xab]);
75
76 // time_low & version (bytes 6-7)
77 // original 0xcd ef → version nibble patched ⇒ 0x6d ef
78 assert_eq!(b[6] & 0x0F, 0x0D);
79 assert_eq!(b[6] >> 4, 0x6);
80 assert_eq!(b[7], 0xEF);
81
82 // clock_seq & variant (bytes 8-9)
83 // original 0x12 34 → variant patch ⇒ 0x92 34
84 assert_eq!(b[9], 0x34);
85 assert_eq!(b[8] & 0x3F, 0x12);
86 assert_eq!(b[8] >> 6, 0b10);
87
88 // node_id (bytes 10-15)
89 assert_eq!(&b[10..16], &[0x00, 0x01, 0x02, 0x03, 0x04, 0x05]);
90
91 // High-level helpers
92 assert_eq!(uuid.get_version(), Some(6));
93 assert_eq!(uuid.get_variant(), Variant::OSF);
94 }
95
96 #[test]
97 fn nil_timestamp_yields_valid_uuid() {
98 let uuid = UUID::from_parts_v6(0, 0, 0, 0, [0; 6]);
99 assert_eq!(uuid.get_version(), Some(6));
100 assert_eq!(uuid.get_variant(), Variant::OSF);
101
102 // Only version & variant bits should be non-zero.
103 let mut expected = [0u8; 16];
104 expected[6] = 0x60; // version 6 nibble
105 expected[8] = 0x80; // variant 10xxxxxx
106 assert_eq!(uuid.as_bytes(), &expected);
107 }
108
109 #[test]
110 fn byte_order_is_big_endian() {
111 let uuid = UUID::from_parts_v6(1, 1, 1, 1, [0; 6]);
112 let b = uuid.as_bytes();
113
114 // Each field must appear in network order.
115 assert_eq!(&b[0..4], &[0x00, 0x00, 0x00, 0x01]); // time_high
116 assert_eq!(&b[4..6], &[0x00, 0x01]); // time_mid
117 assert_eq!(b[6], 0x60); // version nibble
118 assert_eq!(b[7], 0x01); // low byte of time_low
119 assert_eq!(b[9], 0x01); // low byte of clock_seq
120 }
121}