ps_uuid/methods/from_parts_v1.rs
1use crate::UUID;
2
3impl UUID {
4 /// Build a RFC 4122 version-1 (time-based) UUID from its
5 /// individual wire-format fields.
6 ///
7 /// Arguments must already be laid out exactly as described in
8 /// RFC 4122 ยง4.1 (big-endian/network order):
9 ///
10 /// - `time_low`: 32 least-significant bits of the 60-bit timestamp
11 /// - `time_mid`: next 16 bits of the timestamp
12 /// - `time_hi`: next 12 bits of the timestamp (upper 4 bits will be overwritten with the version by `with_version`)
13 /// - `clock_seq`: 14-bit clock sequence; the two variant control bits are set by `with_version`
14 /// - `node_id`: 48-bit IEEE 802 MAC address (or random host id)
15 ///
16 /// The function never fails; all bit fiddling is guaranteed to be
17 /// valid by construction. The returned value satisfies
18 /// `uuid.version() == Version::Time` and
19 /// `uuid.variant() == Variant::OSF`.
20 #[inline]
21 #[must_use]
22 pub fn from_parts_v1(
23 time_low: u32,
24 time_mid: u16,
25 time_hi: u16,
26 clock_seq: u16,
27 node_id: [u8; 6],
28 ) -> Self {
29 let mut uuid = Self::nil();
30
31 // Timestamp ---------------------------------------------------------
32 uuid.bytes[0..4].copy_from_slice(&time_low.to_be_bytes());
33 uuid.bytes[4..6].copy_from_slice(&time_mid.to_be_bytes());
34 uuid.bytes[6..8].copy_from_slice(&time_hi.to_be_bytes());
35
36 // Clock sequence ----------------------------------------------------
37 uuid.bytes[8..10].copy_from_slice(&clock_seq.to_be_bytes());
38
39 // Node id (48 bits) -------------------------------------------------
40 uuid.bytes[10..16].copy_from_slice(&node_id);
41
42 // Insert version + variant bits -------------------------------------
43 uuid.with_version(1)
44 }
45}
46
47#[cfg(test)]
48mod tests {
49 use crate::{Variant, UUID};
50
51 #[test]
52 fn builds_correct_static_example() {
53 // Timestamp: 0x0123456789abcdef
54 // Clock-seq: 0x1234
55 // Node id : 00-01-02-03-04-05
56 let uuid = UUID::from_parts_v1(
57 0x0123_4567,
58 0x89ab,
59 0xcdef,
60 0x1234,
61 [0x00, 0x01, 0x02, 0x03, 0x04, 0x05],
62 );
63 let b = uuid.as_bytes();
64
65 // Raw fields -----------------------------------------------------------
66 assert_eq!(&b[0..4], &[0x01, 0x23, 0x45, 0x67]); // time_low
67 assert_eq!(&b[4..6], &[0x89, 0xab]); // time_mid
68
69 // time_hi: original 0xcd ef => after version patch => 0x1d ef
70 assert_eq!(b[6] & 0x0f, 0x0d);
71 assert_eq!(b[6] >> 4, 0x1); // version = 1
72 assert_eq!(b[7], 0xef);
73
74 // clock_seq: original 0x12 34 => variant patch => 0x92 34
75 assert_eq!(b[9], 0x34);
76 assert_eq!(b[8] & 0x3f, 0x12); // low 6 bits stay
77 assert_eq!(b[8] >> 6, 0b10); // variant OSF
78
79 // node id
80 assert_eq!(&b[10..16], &[0x00, 0x01, 0x02, 0x03, 0x04, 0x05]);
81
82 // High-level helpers ---------------------------------------------------
83 assert_eq!(uuid.get_version(), Some(1));
84 assert_eq!(uuid.get_variant(), Variant::OSF);
85 }
86
87 #[test]
88 fn nil_timestamp_yields_valid_uuid() {
89 let uuid = UUID::from_parts_v1(0, 0, 0, 0, [0; 6]);
90 assert_eq!(uuid.get_version(), Some(1));
91 assert_eq!(uuid.get_variant(), Variant::OSF);
92 // Only version & variant bits should be non-zero.
93 let mut except = [0u8; 16];
94 except[6] = 0x10; // version 1 nibble
95 except[8] = 0x80; // variant 10xx_xxxx
96 assert_eq!(uuid.as_bytes(), &except);
97 }
98
99 #[test]
100 fn byte_order_is_big_endian() {
101 let uuid = UUID::from_parts_v1(1, 1, 1, 1, [0; 6]);
102 let b = uuid.as_bytes();
103 // Each field must appear in network order.
104 assert_eq!(&b[0..4], &[0x00, 0x00, 0x00, 0x01]);
105 assert_eq!(&b[4..6], &[0x00, 0x01]);
106 assert_eq!(b[6], 0x01 << 4);
107 assert_eq!(b[7], 0x01);
108 assert_eq!(b[9], 0x01);
109 }
110}