yuan-id 0.1.1

A lightweight and high-performance u64 ID generator with customizable step allocation and async persistence.
Documentation
use crate::Id;
use std::{
    sync::atomic::AtomicU64,
    time::{SystemTime, UNIX_EPOCH},
};

pub struct Local<F>
where
    F: Fn(u64) + Send + Sync + 'static,
{
    next: AtomicU64,
    max: AtomicU64,
    step: u64,
    remain_step: u64,
    save_fn: F,
    last_write: AtomicU64,
}

impl<F> Id for Local<F>
where
    F: Fn(u64) + Send + Sync + 'static,
{
    fn next(&self) -> u64 {
        let cur = self.next.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
        if cur % self.remain_step == 0 {
            self.schedule_write(cur);
        }
        cur
    }
}

impl<F> Local<F>
where
    F: Fn(u64) + Send + Sync + 'static,
{
    pub fn new(next: u64, step: u64, remain_step: u64, write: F) -> Self {
        let max = next - (next % step) + step;
        Local {
            next: AtomicU64::new(next),
            max: AtomicU64::new(max),
            step,
            save_fn: write,
            remain_step,
            last_write: AtomicU64::new(0),
        }
    }

    fn apply(&self, n: u64) {
        self.max
            .fetch_add(n * self.step, std::sync::atomic::Ordering::Relaxed);
    }

    #[inline]
    fn schedule_write(&self, id: u64) {
        let max = self.max.load(std::sync::atomic::Ordering::Relaxed);
        if max - id >= self.remain_step {
            let last_write = self.last_write.load(std::sync::atomic::Ordering::Acquire);
            let now = SystemTime::now()
                .duration_since(UNIX_EPOCH)
                .unwrap()
                .as_millis() as u64;
            if now > last_write {
                match self.last_write.compare_exchange(
                    last_write,
                    now,
                    std::sync::atomic::Ordering::Relaxed,
                    std::sync::atomic::Ordering::Relaxed,
                ) {
                    Ok(_) => {
                        if now - last_write < 10000 {
                            tracing::warn!("两次写间隔时间小于10秒,扩容10倍");
                            self.apply(1);
                        } else {
                            tracing::debug!("扩容id");
                            self.apply(1);
                        }
                        (self.save_fn)(self.max.load(std::sync::atomic::Ordering::Relaxed));
                    }
                    Err(_) => {
                        tracing::debug!("并发,忽略写入");
                        // self.apply(1);
                    }
                }
            } else {
                tracing::debug!("并发,忽略写入");
                // self.apply(1);
            }
        }
    }
}