use std::sync::atomic::{AtomicU64, Ordering};
#[derive(Debug)]
pub struct ClientIdGenerator {
prefix: String,
counter: AtomicU64,
}
impl ClientIdGenerator {
pub fn new(prefix: impl Into<String>) -> Self {
Self {
prefix: prefix.into(),
counter: AtomicU64::new(0),
}
}
pub fn with_seed(prefix: impl Into<String>, seed: u64) -> Self {
Self {
prefix: prefix.into(),
counter: AtomicU64::new(seed),
}
}
pub fn next_id(&self) -> String {
let n = self.counter.fetch_add(1, Ordering::Relaxed);
format!("{}-{n}", self.prefix)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashSet;
#[test]
fn ids_carry_the_prefix_and_increment() {
let gen = ClientIdGenerator::new("wkex");
assert_eq!(gen.next_id(), "wkex-0");
assert_eq!(gen.next_id(), "wkex-1");
assert_eq!(gen.next_id(), "wkex-2");
}
#[test]
fn seed_makes_the_sequence_reproducible() {
let gen = ClientIdGenerator::with_seed("x", 100);
assert_eq!(gen.next_id(), "x-100");
assert_eq!(gen.next_id(), "x-101");
}
#[test]
fn ids_are_unique_over_a_run() {
let gen = ClientIdGenerator::new("p");
let ids: HashSet<String> = (0..1000).map(|_| gen.next_id()).collect();
assert_eq!(ids.len(), 1000);
}
}