use std::sync::atomic::{AtomicU64, Ordering};
pub const PREFIX: &str = "chatcmpl-";
static COUNTER: AtomicU64 = AtomicU64::new(0);
fn process_stamp() -> u64 {
use std::sync::OnceLock;
static STAMP: OnceLock<u64> = OnceLock::new();
*STAMP.get_or_init(|| {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_nanos() as u64)
.unwrap_or(0)
})
}
pub fn next_request_id() -> String {
let n = COUNTER.fetch_add(1, Ordering::Relaxed);
format!(
"{PREFIX}{:012x}{:06x}",
process_stamp() & 0xffff_ffff_ffff,
n
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ids_are_unique_and_prefixed() {
let a = next_request_id();
let b = next_request_id();
assert_ne!(a, b);
assert!(a.starts_with(PREFIX), "{a}");
assert!(b.starts_with(PREFIX), "{b}");
}
#[test]
fn ids_are_stable_width_for_the_first_million_requests() {
let first = next_request_id();
for _ in 0..64 {
assert_eq!(next_request_id().len(), first.len());
}
}
#[test]
fn ids_are_unique_across_threads() {
let handles: Vec<_> = (0..8)
.map(|_| std::thread::spawn(|| (0..64).map(|_| next_request_id()).collect::<Vec<_>>()))
.collect();
let mut seen = std::collections::BTreeSet::new();
for h in handles {
for id in h.join().unwrap() {
assert!(seen.insert(id.clone()), "duplicate id {id}");
}
}
}
}