use rand::prelude::*;
use std::error::Error;
use std::time::{SystemTime, UNIX_EPOCH};
use std::vec::Vec;
const ENCODE: &[u8; 36] = &[
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, ];
pub fn encode_base36(number: usize) -> Result<String, Box<dyn Error>> {
let mut res = Vec::new();
let mut number = number;
while 0 < number {
res.push(ENCODE[number % 36]);
number /= 36;
}
res.reverse();
Ok(String::from_utf8(res)?)
}
const AID_EPOCH: u64 = 946684800000;
fn gen_time(time: SystemTime) -> Result<String, Box<dyn Error>> {
let time = time.duration_since(UNIX_EPOCH)?;
Ok(format!(
"{:0>8}",
encode_base36(
(time.as_secs() * 1000 + time.subsec_nanos() as u64 / 1_000_000 - AID_EPOCH) as usize,
)?
))
}
fn gen_noise() -> Result<String, Box<dyn Error>> {
let mut rng = rand::thread_rng();
let n = format!("{:0>2}", encode_base36(rng.gen::<u16>() as usize)?).as_str()[..2].to_string();
Ok(n)
}
pub fn gen(time: SystemTime) -> Result<String, Box<dyn Error>> {
let t = gen_time(time)?;
let n = gen_noise()?;
Ok(format!("{}{}", t, n))
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashSet;
use std::hash::Hash;
use std::thread::sleep;
use std::time::{Duration, SystemTime};
fn has_unique_elements<T>(iter: T) -> bool
where
T: IntoIterator,
T::Item: Eq + Hash,
{
let mut uniq = HashSet::new();
iter.into_iter().all(move |x| uniq.insert(x))
}
#[test]
fn no_dups() {
let mut ids: Vec<String> = vec![String::new(); 1000];
for i in 0..999 {
let aid = gen(SystemTime::now()).unwrap();
ids[i] = aid;
sleep(Duration::from_millis(1));
}
assert!(has_unique_elements(ids));
}
}