use std::hint::spin_loop;
use std::time::{SystemTime, UNIX_EPOCH};
#[derive(Copy, Clone, Debug)]
pub struct SnowflakeIdGenerator {
epoch: SystemTime,
last_time_millis: i64,
pub machine_id: i32,
pub node_id: i32,
idx: u16,
}
#[derive(Clone, Debug)]
pub struct SnowflakeIdBucket {
snowflake_id_generator: SnowflakeIdGenerator,
bucket: Vec<i64>,
}
impl SnowflakeIdGenerator {
pub fn new(machine_id: i32, node_id: i32) -> SnowflakeIdGenerator {
Self::with_epoch(machine_id, node_id, UNIX_EPOCH)
}
pub fn with_epoch(machine_id: i32, node_id: i32, epoch: SystemTime) -> SnowflakeIdGenerator {
let last_time_millis = get_time_millis(epoch);
SnowflakeIdGenerator {
epoch,
last_time_millis,
machine_id,
node_id,
idx: 0,
}
}
pub fn real_time_generate(&mut self) -> i64 {
self.idx = (self.idx + 1) % 4096;
let mut now_millis = get_time_millis(self.epoch);
if now_millis == self.last_time_millis {
if self.idx == 0 {
now_millis = biding_time_conditions(self.last_time_millis, self.epoch);
self.last_time_millis = now_millis;
}
} else {
self.last_time_millis = now_millis;
self.idx = 0;
}
self.last_time_millis << 22
| ((self.machine_id << 17) as i64)
| ((self.node_id << 12) as i64)
| (self.idx as i64)
}
pub fn generate(&mut self) -> i64 {
self.idx = (self.idx + 1) % 4096;
if self.idx == 0 {
let mut now_millis = get_time_millis(self.epoch);
if now_millis == self.last_time_millis {
now_millis = biding_time_conditions(self.last_time_millis, self.epoch);
}
self.last_time_millis = now_millis;
}
self.last_time_millis << 22
| ((self.machine_id << 17) as i64)
| ((self.node_id << 12) as i64)
| (self.idx as i64)
}
pub fn lazy_generate(&mut self) -> i64 {
self.idx = (self.idx + 1) % 4096;
if self.idx == 0 {
self.last_time_millis += 1;
}
self.last_time_millis << 22
| ((self.machine_id << 17) as i64)
| ((self.node_id << 12) as i64)
| (self.idx as i64)
}
}
impl SnowflakeIdBucket {
pub fn new(machine_id: i32, node_id: i32) -> Self {
Self::with_epoch(machine_id, node_id, UNIX_EPOCH)
}
pub fn with_epoch(machine_id: i32, node_id: i32, epoch: SystemTime) -> Self {
let snowflake_id_generator = SnowflakeIdGenerator::with_epoch(machine_id, node_id, epoch);
let bucket = Vec::new();
SnowflakeIdBucket {
snowflake_id_generator,
bucket,
}
}
pub fn get_id(&mut self) -> i64 {
if self.bucket.is_empty() {
self.generate_ids();
}
self.bucket.pop().unwrap()
}
fn generate_ids(&mut self) {
for _ in 0..4091 {
self.bucket
.push(self.snowflake_id_generator.lazy_generate());
}
}
}
#[inline(always)]
pub fn get_time_millis(epoch: SystemTime) -> i64 {
SystemTime::now()
.duration_since(epoch)
.expect("Time went mackward")
.as_millis() as i64
}
#[inline(always)]
fn biding_time_conditions(last_time_millis: i64, epoch: SystemTime) -> i64 {
let mut latest_time_millis: i64;
loop {
latest_time_millis = get_time_millis(epoch);
if latest_time_millis > last_time_millis {
return latest_time_millis;
}
spin_loop();
}
}