use std::process;
use std::sync::atomic::{AtomicU64, Ordering};
use std::time::{SystemTime, UNIX_EPOCH};
static COUNTER: AtomicU64 = AtomicU64::new(0);
pub fn unique_u64() -> u64 {
let pid = process::id() as u64;
let nanos = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|d| d.as_nanos() as u64)
.unwrap_or(0);
let counter = COUNTER.fetch_add(1, Ordering::Relaxed);
pid.wrapping_mul(0x9E3779B97F4A7C15)
^ nanos.wrapping_mul(0xBF58476D1CE4E5B9)
^ counter.wrapping_mul(0x94D049BB133111EB)
}
pub fn unique_name(len: usize) -> String {
const ALPHABET: &[u8] = b"0123456789ABCDEFGHJKMNPQRSTVWXYZ";
let mut out = String::with_capacity(len);
let mut state = unique_u64();
while out.len() < len {
out.push(ALPHABET[(state & 31) as usize] as char);
state >>= 5;
if state == 0 {
state = unique_u64();
}
}
out
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn two_calls_differ() {
assert_ne!(unique_u64(), unique_u64());
}
#[test]
fn name_meets_length() {
let n = unique_name(8);
assert!(n.len() >= 8);
}
#[test]
fn names_are_unique_across_calls() {
let a = unique_name(16);
let b = unique_name(16);
assert_ne!(a, b);
}
}