use jiff::Timestamp;
pub const DEFAULT_EPOCH: u64 = 1288834974657;
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct IdGenerator {
pub epoch: u64,
pub shard_id: u16,
pub sequence: u16,
pub timestamp: u64,
}
impl IdGenerator {
pub fn new(shard_id: u16) -> Self {
Self {
epoch: DEFAULT_EPOCH,
shard_id,
sequence: 0,
timestamp: Timestamp::now().as_millisecond() as u64,
}
}
pub fn with_epoch(mut self, epoch: u64) -> Self {
self.epoch = epoch;
self
}
pub fn generate_id(&mut self) -> u64 {
let now = Timestamp::now().as_millisecond() as u64;
if now > self.timestamp + 1 {
self.timestamp = now;
self.sequence = 0;
}
let ts = now - self.epoch;
let id = ((ts & 0x1FFFFFFFFFF) << 22)
| ((self.shard_id as u64 & 0x3FF) << 12)
| (self.sequence as u64 & 0xFFF);
self.sequence += 1;
id
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn mass_unique() {
let mut cf = IdGenerator::new(49);
let mut prev_id: u64 = 0;
for _ in 0..50_000_000 {
let id = cf.generate_id();
assert!(prev_id != id);
prev_id = id;
}
}
#[test]
fn clone_works() {
let cf = IdGenerator::new(49);
let new_one = cf.clone();
assert_eq!(cf.epoch, new_one.epoch);
assert_eq!(cf.shard_id, new_one.shard_id);
assert_eq!(cf.sequence, new_one.sequence);
assert_eq!(cf.timestamp, new_one.timestamp);
}
}