ps_uuid/methods/
gen_v6.rs1use crate::{UuidConstructionError, STATE, UUID};
2use std::time::SystemTime;
3
4impl UUID {
5 pub fn gen_v6() -> Result<Self, UuidConstructionError> {
14 let mut guard = STATE.lock();
15
16 let (timestamp, clock_seq) = guard.next(SystemTime::now());
17 let node_id = guard.node_id;
18
19 drop(guard);
20
21 Self::new_v6(timestamp, clock_seq, *node_id)
22 }
23}
24
25#[cfg(test)]
26mod tests {
27 #![allow(clippy::expect_used)]
28 use super::*;
29 use std::{
30 collections::HashSet,
31 sync::{Arc, Mutex},
32 thread,
33 };
34
35 const fn check_version(bytes: &[u8; 16]) -> u8 {
37 bytes[6] >> 4
38 }
39
40 const fn check_variant(bytes: &[u8; 16]) -> u8 {
42 bytes[8] >> 6
43 }
44
45 #[test]
46 fn gen_v6_produces_valid_rfc4122_id() {
47 let uuid = UUID::gen_v6().expect("generation must succeed");
48 let bytes = uuid.as_bytes();
49
50 assert_eq!(
51 check_version(bytes),
52 0b0110,
53 "high-order nibble of byte 6 must equal version 6"
54 );
55 assert_eq!(
56 check_variant(bytes),
57 0b10,
58 "high-order two bits of byte 8 must equal the RFC 4122 variant"
59 );
60 }
61
62 #[test]
64 fn gen_v6_is_unique() {
65 const N: usize = 10_000;
66
67 let mut set = HashSet::with_capacity(N);
68
69 for _ in 0..N {
70 let id = UUID::gen_v6().expect("generation must succeed").to_string();
71 assert!(
72 set.insert(id),
73 "duplicate UUID generated – monotonicity/clock-seq buggy?"
74 );
75 }
76 }
77
78 #[test]
81 fn gen_v6_thread_safety_and_uniqueness() {
82 const THREADS: usize = 8;
83 const PER_THREAD: usize = 2_000;
84
85 let global: Arc<Mutex<HashSet<UUID>>> =
86 Arc::new(Mutex::new(HashSet::with_capacity(THREADS * PER_THREAD)));
87
88 let mut handles = Vec::with_capacity(THREADS);
89 for _ in 0..THREADS {
90 let global = Arc::clone(&global);
91 handles.push(thread::spawn(move || {
92 for _ in 0..PER_THREAD {
93 let id = UUID::gen_v6().expect("generation should succeed");
94 let mut guard = global.lock().expect("state mutex should not be poisoned");
95 assert!(guard.insert(id), "duplicate across threads");
96 drop(guard);
97 }
98 }));
99 }
100
101 for h in handles {
102 h.join().expect("thread panicked");
103 }
104 }
105}