use crate::options::IGOptions;
use crate::fast_generator::FastIdGenerator;
use std::time::{SystemTime, UNIX_EPOCH};
use std::sync::OnceLock;
static ID_GENERATOR: OnceLock<FastIdGenerator> = OnceLock::new();
fn get_generator() -> &'static FastIdGenerator {
ID_GENERATOR.get().expect("ID generator not initialized.")
}
#[derive(Debug, Clone)]
pub struct IdInfo {
pub timestamp: i64,
pub worker_id: u16,
pub sequence: u32,
pub system_time: SystemTime,
}
impl Default for IdInfo {
fn default() -> Self {
Self {
timestamp: 0,
worker_id: 0,
sequence: 0,
system_time: UNIX_EPOCH,
}
}
}
pub fn snowflake_init(worker_id: u16) {
set_options(IGOptions::quick_init(worker_id));
}
pub fn init_with_capacity(worker_id: u16, max_nodes: u32, max_qps: u32) {
let options = IGOptions::with_capacity(worker_id, max_nodes, max_qps);
set_options(options);
}
pub fn set_options(options: IGOptions) {
if ID_GENERATOR.get().is_some() {
return;
}
ID_GENERATOR
.set(FastIdGenerator::new(&options))
.expect("ID generator has already been initialized with different options.");
}
pub fn init_with_builder(options: IGOptions) {
set_options(options);
}
pub fn is_initialized() -> bool {
ID_GENERATOR.get().is_some()
}
pub fn get_options() -> IGOptions {
ID_GENERATOR.get()
.map(|g| IGOptions::builder(g.worker_id()).build())
.unwrap_or_else(|| IGOptions::quick_init(1))
}
pub fn next_id() -> u64 {
get_generator().next_id()
}
pub fn try_next_id() -> Result<u64, &'static str> {
ID_GENERATOR
.get()
.map(|g| g.next_id())
.ok_or("ID generator not initialized. Call snowflake_init() or set_options() first.")
}
pub fn next_ids(count: usize) -> Vec<u64> {
let gen = get_generator();
(0..count).map(|_| gen.next_id()).collect()
}
pub fn extract_time(id: u64) -> SystemTime {
UNIX_EPOCH + std::time::Duration::from_millis(get_generator().extract_timestamp(id) as u64)
}
pub fn extract_id_info(id: u64) -> IdInfo {
get_generator().extract_id_info(id)
}
pub fn extract_id_infos(ids: &[u64]) -> Vec<IdInfo> {
let gen = get_generator();
ids.iter().map(|&id| gen.extract_id_info(id)).collect()
}
pub fn extract_time_utc(id: u64) -> Option<chrono::DateTime<chrono::Utc>> {
let ms = get_generator().extract_timestamp(id);
chrono::DateTime::from_timestamp_millis(ms)
}