ps_uuid/methods/
new_v4.rs1use rand::RngCore;
2
3use crate::UUID;
4
5impl UUID {
6 #[must_use]
8 pub fn new_v4<R: RngCore + ?Sized>(rng: &mut R) -> Self {
9 let mut uuid = Self::nil();
10
11 rng.fill_bytes(&mut uuid.bytes);
12
13 uuid.with_version(4)
14 }
15}
16
17#[cfg(test)]
18mod tests {
19 use std::collections::HashSet;
20
21 use rand::{rngs::StdRng, SeedableRng};
22
23 use crate::UUID;
24
25 #[test]
26 fn version_and_variant_are_set() {
27 let mut rng = StdRng::seed_from_u64(42);
28 for _ in 0..100 {
29 let uuid = UUID::new_v4(&mut rng);
30 assert_eq!(uuid.bytes[6] >> 4, 0b0100, "Version must be 4");
32 assert_eq!(
34 uuid.bytes[8] & 0b1100_0000,
35 0b1000_0000,
36 "Variant must be RFC 4122"
37 );
38 }
39 }
40
41 #[test]
42 fn produces_unique_uuids() {
43 let mut rng = StdRng::seed_from_u64(12345);
44 let mut set = HashSet::new();
45 for _ in 0..1000 {
46 let uuid = UUID::new_v4(&mut rng);
47 assert!(set.insert(uuid.bytes), "Duplicate UUID generated!");
48 }
49 }
50
51 #[test]
52 fn all_other_bits_are_random() {
53 let mut rng = StdRng::seed_from_u64(98765);
54 let mut seen = [0u8; 16];
55 let mut seen_inv = [0xFFu8; 16];
56
57 for _ in 0..1000 {
58 let uuid = UUID::new_v4(&mut rng);
59 for i in 0..16 {
60 seen[i] |= uuid.bytes[i];
61 seen_inv[i] &= uuid.bytes[i];
62 }
63 }
64
65 assert_ne!(
67 seen[6] & 0x0F,
68 0,
69 "At least one lower bit in byte 6 should be 1"
70 );
71 assert_ne!(
72 seen_inv[6] & 0x0F,
73 0x0F,
74 "At least one lower bit in byte 6 should be 0"
75 );
76 assert_ne!(
78 seen[8] & 0x3F,
79 0,
80 "At least one lower bit in byte 8 should be 1"
81 );
82 assert_ne!(
83 seen_inv[8] & 0x3F,
84 0x3F,
85 "At least one lower bit in byte 8 should be 0"
86 );
87 for i in 0..16 {
89 if i == 6 {
90 assert_eq!(seen[6] & 0xF0, 0x40, "Version bits must be set to 4");
92 } else if i == 8 {
93 assert_eq!(seen[8] & 0xC0, 0x80, "Variant bits must be set to RFC 4122");
95 } else {
96 assert_ne!(seen[i], 0, "At least one bit in byte {i} should be 1");
97 assert_ne!(
98 seen_inv[i], 0xFF,
99 "At least one bit in byte {i} should be 0"
100 );
101 }
102 }
103 }
104
105 #[test]
106 fn version_and_variant_methods_report_correctly() {
107 let mut rng = StdRng::seed_from_u64(5555);
108 let uuid = UUID::new_v4(&mut rng);
109 assert_eq!(uuid.get_version(), Some(4));
110 }
112
113 #[test]
114 fn deterministic_with_seeded_rng() {
115 let mut rng1 = StdRng::seed_from_u64(1);
116 let mut rng2 = StdRng::seed_from_u64(1);
117
118 let uuid1 = UUID::new_v4(&mut rng1);
119 let uuid2 = UUID::new_v4(&mut rng2);
120
121 assert_eq!(
122 uuid1.bytes, uuid2.bytes,
123 "Same seed should produce same UUID"
124 );
125 }
126}