1use rand::prelude::*;
2use std::error::Error;
3use std::time::{SystemTime, UNIX_EPOCH};
4use std::vec::Vec;
5
6const ENCODE: &[u8; 36] = &[
7 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, ];
44
45pub fn encode_base36(number: usize) -> Result<String, Box<dyn Error>> {
46 let mut res = Vec::new();
47
48 let mut number = number;
49 while 0 < number {
50 res.push(ENCODE[number % 36]);
51 number /= 36;
52 }
53 res.reverse();
54
55 Ok(String::from_utf8(res)?)
56}
57const AID_EPOCH: u64 = 946684800000;
58
59fn gen_time(time: SystemTime) -> Result<String, Box<dyn Error>> {
60 let time = time.duration_since(UNIX_EPOCH)?;
61
62 Ok(format!(
63 "{:0>8}",
64 encode_base36(
65 (time.as_secs() * 1000 + time.subsec_nanos() as u64 / 1_000_000 - AID_EPOCH) as usize,
66 )?
67 ))
68}
69
70fn gen_noise() -> Result<String, Box<dyn Error>> {
71 let mut rng = rand::thread_rng();
72 let n = format!("{:0>2}", encode_base36(rng.gen::<u16>() as usize)?).as_str()[..2].to_string();
73
74 Ok(n)
75}
76
77pub fn gen(time: SystemTime) -> Result<String, Box<dyn Error>> {
93 let t = gen_time(time)?;
94 let n = gen_noise()?;
95
96 Ok(format!("{}{}", t, n))
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102 use std::collections::HashSet;
103 use std::hash::Hash;
104 use std::thread::sleep;
105 use std::time::{Duration, SystemTime};
106
107 fn has_unique_elements<T>(iter: T) -> bool
108 where
109 T: IntoIterator,
110 T::Item: Eq + Hash,
111 {
112 let mut uniq = HashSet::new();
113 iter.into_iter().all(move |x| uniq.insert(x))
114 }
115
116 #[test]
117 fn no_dups() {
118 let mut ids: Vec<String> = vec![String::new(); 1000];
119
120 for i in 0..999 {
121 let aid = gen(SystemTime::now()).unwrap();
122 ids[i] = aid;
123
124 sleep(Duration::from_millis(1));
125 }
126
127 assert!(has_unique_elements(ids));
128 }
129}