use std::{fmt, hint};
use ferroid::{
generator::BasicSnowflakeGenerator,
time::{MonotonicClock, UNIX_EPOCH},
};
use rand::random;
ferroid::define_snowflake_id!(
InfinoId128, u128,
reserved: 0,
timestamp: 64,
machine_id: 40,
sequence: 24
);
const WORKER_BITS: u32 = 40;
const WORKER_MASK: u64 = (1u64 << WORKER_BITS) - 1;
pub struct IdGenerator {
worker_id: u64,
inner: BasicSnowflakeGenerator<InfinoId128, MonotonicClock>,
}
impl IdGenerator {
pub fn new() -> Self {
let worker_id = random::<u64>() & WORKER_MASK;
Self::with_worker_id(worker_id)
}
pub fn with_worker_id(worker_id: u64) -> Self {
let worker40 = worker_id & WORKER_MASK;
let clock = MonotonicClock::<1>::with_epoch(UNIX_EPOCH);
Self {
worker_id: worker40,
inner: BasicSnowflakeGenerator::new(worker40 as u128, clock),
}
}
pub fn worker_id(&self) -> u64 {
self.worker_id
}
#[inline]
pub fn next_id(&self) -> i128 {
let id: InfinoId128 = self.inner.next_id(|_| hint::spin_loop());
id.to_raw() as i128
}
pub fn reserve_range(&self, n: u32) -> Vec<(i128, i128)> {
if n == 0 {
return Vec::new();
}
let mut spans: Vec<(i128, i128)> = Vec::with_capacity(1);
let first = self.next_id();
let mut span_first = first;
let mut span_last = first;
for _ in 1..n {
let id = self.next_id();
if id == span_last + 1 {
span_last = id;
} else {
spans.push((span_first, span_last));
span_first = id;
span_last = id;
}
}
spans.push((span_first, span_last));
spans
}
}
impl Default for IdGenerator {
fn default() -> Self {
Self::new()
}
}
impl fmt::Debug for IdGenerator {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("IdGenerator")
.field("worker_id", &format_args!("0x{:010x}", self.worker_id))
.finish()
}
}
#[cfg(test)]
mod tests {
use std::{collections::HashSet, thread::sleep, time};
use super::*;
fn worker_id_of(id: i128) -> u64 {
(((id as u128) >> 24) & (WORKER_MASK as u128)) as u64
}
fn timestamp_of(id: i128) -> u64 {
((id as u128) >> 64) as u64
}
fn sequence_of(id: i128) -> u32 {
((id as u128) & ((1u128 << 24) - 1)) as u32
}
#[test]
fn strict_monotonicity_within_one_generator() {
let g = IdGenerator::with_worker_id(0x0012_3456_789A);
let mut last = i128::MIN;
for _ in 0..100_000 {
let id = g.next_id();
assert!(
id > last,
"expected strict monotonic; got {id} after {last}"
);
last = id;
}
}
#[test]
fn high_bit_stays_zero_for_current_era_timestamps() {
let g = IdGenerator::new();
let id = g.next_id();
assert!(id >= 0, "id={id} unexpectedly negative");
}
#[test]
fn timestamp_field_matches_now() {
let g = IdGenerator::with_worker_id(0xABCD);
let now_ms = time::SystemTime::now()
.duration_since(time::UNIX_EPOCH)
.expect("clock pre-1970?")
.as_millis() as u64;
let id = g.next_id();
let ts = timestamp_of(id);
let drift_ms = ts.abs_diff(now_ms);
assert!(
drift_ms < 5_000,
"id timestamp {ts} drifted {drift_ms}ms from now_ms {now_ms}"
);
}
#[test]
fn worker_id_truncates_to_40_bits_and_is_recoverable() {
let g = IdGenerator::with_worker_id(u64::MAX);
assert_eq!(g.worker_id(), WORKER_MASK);
let id = g.next_id();
assert_eq!(worker_id_of(id), WORKER_MASK);
}
#[test]
fn worker_id_zero_is_valid() {
let g = IdGenerator::with_worker_id(0);
let id = g.next_id();
assert_eq!(worker_id_of(id), 0);
}
#[test]
fn different_worker_ids_appear_in_their_id_field() {
let g1 = IdGenerator::with_worker_id(0x01);
let g2 = IdGenerator::with_worker_id(0xFE_DCBA);
assert_eq!(worker_id_of(g1.next_id()), 0x01);
assert_eq!(worker_id_of(g2.next_id()), 0xFE_DCBA);
}
#[test]
fn sequence_resets_per_ms_advances_within_ms() {
let g = IdGenerator::with_worker_id(0);
let mut prev_ts = 0u64;
let mut prev_seq = u32::MAX;
for _ in 0..10_000 {
let id = g.next_id();
let ts = timestamp_of(id);
let seq = sequence_of(id);
if ts == prev_ts {
assert!(
seq == prev_seq.wrapping_add(1),
"same-ms seq must increment: ts={ts} prev_seq={prev_seq} seq={seq}"
);
} else {
assert!(
ts > prev_ts || prev_ts == 0,
"ts must be non-decreasing: prev_ts={prev_ts} ts={ts}"
);
assert_eq!(
seq, 0,
"new-ms seq must be 0; got {seq} after ts={prev_ts} → {ts}"
);
}
prev_ts = ts;
prev_seq = seq;
}
}
#[test]
fn new_picks_random_worker_id_per_instance() {
let g1 = IdGenerator::new();
let g2 = IdGenerator::new();
assert_ne!(
g1.worker_id(),
g2.worker_id(),
"two IdGenerator::new() collided on worker_id — \
this is a ~10⁻¹² event"
);
}
#[test]
fn debug_format_includes_worker_id_in_hex() {
let g = IdGenerator::with_worker_id(0xDEAD_BEEF);
let s = format!("{g:?}");
assert!(s.contains("0x00deadbeef"), "got: {s}");
}
fn flatten_spans(spans: &[(i128, i128)]) -> Vec<i128> {
let mut out = Vec::new();
for (first, last) in spans {
for v in *first..=*last {
out.push(v);
}
}
out
}
#[test]
fn reserve_range_zero_returns_empty() {
let g = IdGenerator::with_worker_id(0x1234);
let spans = g.reserve_range(0);
assert!(spans.is_empty());
}
#[test]
fn reserve_range_one_returns_singleton_span() {
let g = IdGenerator::with_worker_id(0x1234);
let spans = g.reserve_range(1);
assert_eq!(spans.len(), 1);
let (first, last) = spans[0];
assert_eq!(first, last);
}
#[test]
fn reserve_range_small_n_flattens_to_n_monotonic_ids() {
let g = IdGenerator::with_worker_id(0x1234);
let spans = g.reserve_range(100);
let flat = flatten_spans(&spans);
assert_eq!(flat.len(), 100);
for w in flat.windows(2) {
assert!(w[1] > w[0], "reserve_range ids must be strictly monotonic");
}
}
#[test]
fn reserve_range_large_n_still_flattens_correctly() {
let g = IdGenerator::with_worker_id(0xCAFE);
let n = 10_000u32;
let spans = g.reserve_range(n);
let flat = flatten_spans(&spans);
assert_eq!(flat.len(), n as usize);
let mut seen = HashSet::with_capacity(n as usize);
for id in &flat {
assert!(
seen.insert(*id),
"duplicate id in reserve_range output: {id}"
);
}
for w in flat.windows(2) {
assert!(w[1] > w[0]);
}
for (first, last) in &spans {
assert!(last >= first, "span ({first}, {last}) is inverted");
}
}
#[test]
fn reserve_range_back_to_back_calls_produce_disjoint_ids() {
let g = IdGenerator::with_worker_id(0x10);
let a = flatten_spans(&g.reserve_range(50));
let b = flatten_spans(&g.reserve_range(50));
let a_set: HashSet<i128> = a.iter().copied().collect();
for id in &b {
assert!(!a_set.contains(id), "id {id} in both reservations");
}
}
#[test]
fn reserve_range_across_ms_boundary_produces_multi_span() {
let g = IdGenerator::with_worker_id(0x20);
let a = g.next_id();
sleep(time::Duration::from_millis(2));
let b = g.next_id();
assert!(b > a, "monotonic");
assert_ne!(
b,
a + 1,
"two ids straddling a ms boundary should NOT be numerically adjacent — {a} → {b}"
);
}
#[test]
fn cross_worker_ids_remain_distinct_within_same_ms() {
let g1 = IdGenerator::with_worker_id(0xAAAA);
let g2 = IdGenerator::with_worker_id(0xBBBB);
let id1 = g1.next_id();
let id2 = g2.next_id();
assert_ne!(id1, id2);
assert_eq!(worker_id_of(id1), 0xAAAA);
assert_eq!(worker_id_of(id2), 0xBBBB);
}
#[test]
fn default_constructs_a_usable_generator() {
let g = IdGenerator::default();
let a = g.next_id();
let b = g.next_id();
assert!(b > a, "generator must yield monotonically increasing ids");
}
}