1use std::sync::atomic::{AtomicU64, Ordering};
2use uuid::Uuid;
3
4pub struct UuidGenerator {
28 namespace: Uuid,
29 counter: AtomicU64,
30}
31
32impl UuidGenerator {
51 pub fn new(namespace: Uuid) -> Self {
63 Self {
64 namespace,
65 counter: AtomicU64::new(0),
66 }
67 }
68
69 pub fn next(&self) -> Uuid {
78 let counter = self.counter.fetch_add(1, Ordering::SeqCst);
79 let name = counter.to_string();
80 Uuid::new_v5(&self.namespace, name.as_bytes())
82 }
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88 use std::collections::HashSet;
89 use std::sync::{Arc, Barrier};
90 use std::thread;
91
92 fn create_test_namespace() -> Uuid {
94 Uuid::parse_str("6ba7b810-9dad-11d1-80b4-00c04fd430c8").unwrap()
95 }
96
97 #[test]
98 fn test_uuid_generator_creation() {
99 let namespace = create_test_namespace();
100 let generator = UuidGenerator::new(namespace);
101
102 assert_eq!(generator.namespace, namespace);
103 assert_eq!(generator.counter.load(Ordering::SeqCst), 0);
104 }
105
106 #[test]
107 fn test_uuid_generator_next() {
108 let generator = UuidGenerator::new(create_test_namespace());
109
110 let uuid1 = generator.next();
112 assert_eq!(generator.counter.load(Ordering::SeqCst), 1);
113
114 let uuid2 = generator.next();
116 assert_eq!(generator.counter.load(Ordering::SeqCst), 2);
117
118 assert_ne!(uuid1, uuid2);
120
121 assert_eq!(uuid1.get_version(), Some(uuid::Version::Sha1));
123 assert_eq!(uuid2.get_version(), Some(uuid::Version::Sha1));
124 }
125
126 #[test]
127 fn test_uuid_generator_deterministic() {
128 let namespace = create_test_namespace();
130 let generator1 = UuidGenerator::new(namespace);
131 let generator2 = UuidGenerator::new(namespace);
132
133 assert_eq!(generator1.next(), generator2.next());
135 assert_eq!(generator1.next(), generator2.next());
136 }
137
138 #[test]
139 fn test_uuid_generator_different_namespaces() {
140 let namespace1 = Uuid::parse_str("6ba7b810-9dad-11d1-80b4-00c04fd430c8").unwrap();
142 let namespace2 = Uuid::parse_str("6ba7b811-9dad-11d1-80b4-00c04fd430c8").unwrap();
143
144 let generator1 = UuidGenerator::new(namespace1);
145 let generator2 = UuidGenerator::new(namespace2);
146
147 assert_ne!(generator1.next(), generator2.next());
149 assert_ne!(generator1.next(), generator2.next());
150 }
151
152 #[test]
153 fn test_uuid_generator_sequential() {
154 let generator = UuidGenerator::new(create_test_namespace());
155 let mut uuids = Vec::new();
156
157 for _ in 0..100 {
159 uuids.push(generator.next());
160 }
161
162 let unique_uuids: HashSet<_> = uuids.iter().collect();
164 assert_eq!(unique_uuids.len(), 100);
165
166 assert_eq!(generator.counter.load(Ordering::SeqCst), 100);
168 }
169
170 #[test]
171 fn test_uuid_generator_thread_safety() {
172 let generator = Arc::new(UuidGenerator::new(create_test_namespace()));
173 let num_threads = 10;
174 let uuids_per_thread = 100;
175 let total_uuids = num_threads * uuids_per_thread;
176
177 let barrier = Arc::new(Barrier::new(num_threads));
179
180 let all_uuids = Arc::new(std::sync::Mutex::new(Vec::with_capacity(total_uuids)));
182
183 let mut handles = vec![];
184
185 for _ in 0..num_threads {
186 let thread_generator = Arc::clone(&generator);
187 let thread_barrier = Arc::clone(&barrier);
188 let thread_uuids = Arc::clone(&all_uuids);
189
190 let handle = thread::spawn(move || {
191 thread_barrier.wait(); let mut local_uuids = Vec::with_capacity(uuids_per_thread);
194 for _ in 0..uuids_per_thread {
195 local_uuids.push(thread_generator.next());
196 }
197
198 let mut all = thread_uuids.lock().unwrap();
200 all.extend(local_uuids);
201 });
202
203 handles.push(handle);
204 }
205
206 for handle in handles {
208 handle.join().unwrap();
209 }
210
211 let all_uuids = all_uuids.lock().unwrap();
213 let unique_uuids: HashSet<_> = all_uuids.iter().collect();
214
215 assert_eq!(
216 unique_uuids.len(),
217 total_uuids,
218 "All generated UUIDs should be unique"
219 );
220
221 assert_eq!(
223 generator.counter.load(Ordering::SeqCst),
224 total_uuids as u64,
225 "Counter should match the total number of generated UUIDs"
226 );
227 }
228
229 #[test]
230 fn test_uuid_generator_with_initial_counter() {
231 let namespace = create_test_namespace();
233 let initial_counter = 1000;
234
235 let mut generator = UuidGenerator::new(namespace);
236 generator.counter = AtomicU64::new(initial_counter);
237
238 let _ = generator.next();
240
241 assert_eq!(
243 generator.counter.load(Ordering::SeqCst),
244 initial_counter + 1
245 );
246
247 let mut generator2 = UuidGenerator::new(namespace);
249 generator2.counter = AtomicU64::new(initial_counter + 1);
250
251 assert_eq!(generator.next(), generator2.next());
253 }
254}