1use rand::Rng;
2use std::sync::atomic::{AtomicU64, Ordering};
3use std::time::SystemTime;
4use uuid::Uuid;
5
6const DATA_CENTER_ID: u16 = 0;
8const MACHINE_ID: u16 = 0;
9
10const TIMESTAMP_LEFT_SHIFT: u64 = 22;
12const DATA_CENTER_ID_SHIFT: u64 = 17;
14const MACHINE_ID_SHIFT: u64 = 12;
16const SEQUENCE_MASK: u64 = 0xfff;
18
19static LAST_TIMESTAMP: AtomicU64 = AtomicU64::new(0);
21static SEQUENCE: AtomicU64 = AtomicU64::new(0);
23
24pub struct IdUtil;
26
27impl IdUtil {
28 pub fn gen_uuid() -> String {
30 Uuid::new_v4().to_string()
31 }
32
33 pub fn uuid32() -> String {
35 Uuid::new_v4().to_string().replace("-", "")
36 }
37
38 pub fn uuid36() -> String {
40 Uuid::new_v4().to_string()
41 }
42
43 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 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 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 pub fn snowflake_id() -> u64 {
96 let mut timestamp = Self::get_current_timestamp();
97
98 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 if timestamp == last_timestamp {
109 let sequence = SEQUENCE.fetch_add(1, Ordering::Relaxed) & SEQUENCE_MASK;
110 if sequence == 0 {
112 timestamp = Self::til_next_millis(last_timestamp);
113 }
114 } else {
115 SEQUENCE.store(0, Ordering::Relaxed);
117 }
118
119 LAST_TIMESTAMP.store(timestamp, Ordering::Relaxed);
121
122 (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}