ps_uuid/methods/
gen_v1.rs1use crate::{UuidConstructionError, STATE, UUID};
2use std::time::SystemTime;
3
4impl UUID {
5 pub fn gen_v1() -> Result<Self, UuidConstructionError> {
13 let mut guard = STATE.lock();
14
15 let (timestamp, clock_seq) = guard.next(SystemTime::now());
16 let node_id = guard.node_id;
17
18 drop(guard);
19
20 Self::new_v1(timestamp, clock_seq, *node_id)
21 }
22}
23
24#[cfg(test)]
25mod tests {
26 #![allow(clippy::expect_used)]
27 use std::{
28 collections::HashSet,
29 sync::{Arc, Mutex},
30 thread,
31 };
32
33 use crate::UUID;
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_v1_produces_valid_rfc4122_id() {
47 let uuid = UUID::gen_v1().expect("generation must succeed");
48 let bytes = uuid.as_bytes();
49
50 assert_eq!(
51 check_version(bytes),
52 0b0001,
53 "high-order nibble of byte 6 must equal version 1"
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_v1_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_v1().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_v1_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_v1().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}