ps_uuid/methods/
new_v7.rs1use std::time::Duration;
2
3use crate::UUID;
4
5impl UUID {
6 #[must_use]
27 pub fn new_v7(timestamp: Duration, random_bytes: [u8; 8]) -> Self {
28 let mut uuid = Self::nil();
29
30 uuid.bytes[0..6].copy_from_slice(×tamp.as_millis().to_be_bytes()[10..16]);
32
33 let nanos = (timestamp.subsec_nanos() % 1_000_000).to_be_bytes();
35
36 uuid.bytes[6] = 0x70 | nanos[1];
38
39 uuid.bytes[7] = nanos[2];
41
42 uuid.bytes[8..].copy_from_slice(&random_bytes);
44
45 uuid.with_version(7)
47 }
48}
49
50#[cfg(test)]
54mod tests {
55 use super::*;
56 use std::time::Duration;
57
58 const fn version(b: &[u8; 16]) -> u8 {
60 b[6] >> 4
61 }
62 const fn variant(b: &[u8; 16]) -> u8 {
63 b[8] >> 6
64 }
65
66 #[test]
67 fn version_and_variant_are_correct() {
68 let uuid = UUID::new_v7(Duration::from_nanos(0), [0; 8]);
69 let bytes = uuid.as_bytes();
70 assert_eq!(version(bytes), 0b0111, "version must be 7");
71 assert_eq!(variant(bytes), 0b10, "variant must be RFC-4122");
72 }
73
74 #[test]
75 fn timestamp_is_encoded_big_endian() {
76 let ms = 0x0123_4567_89ABu64;
78 let dur = Duration::from_millis(ms);
79 let uuid = UUID::new_v7(dur, [0; 8]);
80 let b = uuid.as_bytes();
81
82 assert_eq!(
83 &b[0..6],
84 &[0x01, 0x23, 0x45, 0x67, 0x89, 0xAB],
85 "48-bit millisecond timestamp must be big-endian"
86 );
87 }
88
89 #[test]
90 fn extra_timestamp_bits_are_encoded() {
91 let dur = Duration::from_millis(123) + Duration::from_nanos(987_654);
93 let uuid = UUID::new_v7(dur, [0; 8]);
94 let b = uuid.as_bytes();
95
96 let nanos = (987_654u32).to_be_bytes();
97
98 assert_eq!(b[6] & 0x0F, nanos[1]);
100 assert_eq!(b[7], nanos[2]);
101 }
102
103 #[test]
104 fn random_payload_is_inserted_verbatim() {
105 let rnd = [0x81, 2, 3, 4, 5, 6, 7, 8];
106 let uuid = UUID::new_v7(Duration::from_secs(0), rnd);
107 assert_eq!(&uuid.as_bytes()[8..16], &rnd);
108 }
109
110 #[test]
111 fn identical_input_is_deterministic() {
112 let ts = Duration::from_secs(42);
113 let rnd = [9, 8, 7, 6, 5, 4, 3, 2];
114
115 let a = UUID::new_v7(ts, rnd);
116 let b = UUID::new_v7(ts, rnd);
117
118 assert_eq!(a.bytes, b.bytes, "same input must yield same UUID");
119 }
120
121 #[test]
122 fn different_random_payloads_differ() {
123 let ts = Duration::from_secs(1);
124 let a = UUID::new_v7(ts, [0; 8]);
125 let b = UUID::new_v7(ts, [1; 8]);
126 assert_ne!(a.bytes, b.bytes, "different random bytes must change UUID");
127 }
128}