dev_tool/
id_util.rs

1use rand::Rng;
2use std::sync::atomic::{AtomicU64, Ordering};
3use std::time::SystemTime;
4use uuid::Uuid;
5
6// 数据中心ID和机器ID
7const DATA_CENTER_ID: u16 = 0;
8const MACHINE_ID: u16 = 0;
9
10// 时间戳左移22位 (10 + 12)
11const TIMESTAMP_LEFT_SHIFT: u64 = 22;
12// 数据中心ID左移17位 (5 + 12)
13const DATA_CENTER_ID_SHIFT: u64 = 17;
14// 机器ID左移12位
15const MACHINE_ID_SHIFT: u64 = 12;
16// 序列号掩码,12位全为1
17const SEQUENCE_MASK: u64 = 0xfff;
18
19// 上次生成ID的时间戳
20static LAST_TIMESTAMP: AtomicU64 = AtomicU64::new(0);
21// 序列号
22static SEQUENCE: AtomicU64 = AtomicU64::new(0);
23
24/// ID工具,用于生成ID使用,UUID和雪花算法
25pub struct IdUtil;
26
27impl IdUtil {
28    /// 生成UUID
29    pub fn gen_uuid() -> String {
30        Uuid::new_v4().to_string()
31    }
32
33    /// 生成UUID,不带中横线,共计32位
34    pub fn uuid32() -> String {
35        Uuid::new_v4().to_string().replace("-", "")
36    }
37
38    /// 生成UUID,带中横线,共计36位
39    pub fn uuid36() -> String {
40        Uuid::new_v4().to_string()
41    }
42
43    /// 生成指定长度的随机字符串ID
44    ///
45    /// 该函数使用字母和数字字符集生成随机字符串,适用于生成唯一标识符
46    ///
47    /// # 参数
48    /// * `length` - 指定生成字符串的长度
49    ///
50    /// # 返回值
51    /// 返回一个包含随机字符的String,长度为指定的length
52    ///
53    /// # 示例
54    /// ```
55    /// let id = random_string_id(128);
56    /// assert_eq!(id.len(), 128);
57    /// ```
58    pub fn random_string_id(length: usize) -> String {
59        let str_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
60        let mut rng = rand::thread_rng();
61        let mut result = String::with_capacity(length);
62        // 循环生成指定长度的随机字符串
63        for _ in 0..length {
64            let index = rng.gen_range(0..str_chars.len());
65            result.push(str_chars.chars().nth(index).unwrap());
66        }
67        result
68    }
69
70    /// 生成一个唯一的 tik ID 字符串
71    ///
72    /// 该函数通过组合三个随机字符串来创建一个格式化的唯一标识符。
73    /// 生成的格式为: "{2位随机字符串}_{14位随机字符串}_{16位随机字符串}__"
74    ///
75    /// # 返回值
76    /// * `String` - 返回生成的唯一 tik ID 字符串
77    ///
78    /// # 示例
79    /// ```
80    /// let id = tik_id();
81    /// // 示例输出: "ab_cdefghijklmn_opqrstuvwxyzabcdefg__"
82    /// ```
83    pub fn tik_id() -> String {
84        format!(
85            "{}_{}_{}__",
86            Self::random_string_id(2),
87            Self::random_string_id(14),
88            Self::random_string_id(16)
89        )
90    }
91
92    /// 使用雪花算法生成ID
93    ///
94    /// 1位0 + 41位时间戳 + 10位机器ID(5位数据中心ID + 5位机器ID) + 12位序列号 = 64位二进制数字
95    pub fn snowflake_id() -> u64 {
96        let mut timestamp = Self::get_current_timestamp();
97
98        // 如果当前时间小于上一次生成ID的时间戳,说明系统时钟回退过,抛出异常
99        let last_timestamp = LAST_TIMESTAMP.load(Ordering::Relaxed);
100        if timestamp < last_timestamp {
101            panic!(
102                "Clock moved backwards. Refusing to generate id for {} milliseconds",
103                last_timestamp - timestamp
104            );
105        }
106
107        // 如果是同一毫秒内生成的ID,则序列号递增
108        if timestamp == last_timestamp {
109            let sequence = SEQUENCE.fetch_add(1, Ordering::Relaxed) & SEQUENCE_MASK;
110            // 如果序列号溢出,等待下一毫秒
111            if sequence == 0 {
112                timestamp = Self::til_next_millis(last_timestamp);
113            }
114        } else {
115            // 不同毫秒内,序列号重置为0
116            SEQUENCE.store(0, Ordering::Relaxed);
117        }
118
119        // 记录上一次生成ID的时间戳
120        LAST_TIMESTAMP.store(timestamp, Ordering::Relaxed);
121
122        // 生成雪花ID
123        (timestamp << TIMESTAMP_LEFT_SHIFT)
124            | ((DATA_CENTER_ID as u64) << DATA_CENTER_ID_SHIFT)
125            | ((MACHINE_ID as u64) << MACHINE_ID_SHIFT)
126            | SEQUENCE.load(Ordering::Relaxed)
127    }
128
129    fn get_current_timestamp() -> u64 {
130        SystemTime::now()
131            .duration_since(SystemTime::UNIX_EPOCH)
132            .expect("Time went backwards")
133            .as_millis() as u64
134    }
135
136    fn til_next_millis(last_timestamp: u64) -> u64 {
137        let mut timestamp = Self::get_current_timestamp();
138        while timestamp <= last_timestamp {
139            timestamp = Self::get_current_timestamp();
140        }
141        timestamp
142    }
143}
144
145#[cfg(test)]
146mod tests {
147    use super::*;
148
149    #[test]
150    fn test_uuid() {
151        let uuid = IdUtil::uuid32();
152        println!("{}", uuid);
153        let uuid = IdUtil::uuid36();
154        println!("{}", uuid);
155    }
156
157    #[test]
158    fn test_random_string_id() {
159        let id = IdUtil::random_string_id(128);
160        println!("{}", id)
161    }
162
163    #[test]
164    fn test_snowflake_id() {
165        let id = IdUtil::snowflake_id();
166        println!("{}", id);
167        println!("{:b}", id);
168    }
169}