aid_rs/
lib.rs

1use rand::Rng;
2use chrono::{DateTime, TimeZone, Utc};
3use std::num::ParseIntError;
4
5pub fn get_noise() -> String {
6    let mut rng = rand::thread_rng();
7    let counter: u16 = rng.gen_range(0..=u16::MAX);
8    format!("{:02x}", counter)
9}
10
11pub fn parse_aid(aid: &str) -> Result<DateTime<Utc>, Box<dyn std::error::Error>> {
12    let base36_time = &aid[..8];
13    let time_milliseconds = b36_decode(base36_time)?;
14    let timestamp = 946684800 + time_milliseconds / 1000;
15    Utc.timestamp_opt(timestamp as i64, 0)
16        .single()
17        .ok_or_else(|| "Invalid timestamp".into())
18}
19
20pub fn gen_aid() -> String {
21    let current = ((chrono::Utc::now().timestamp() + 946684800) * 1000) as u64;
22    let base36_time = b36_encode(current);
23    let noise = get_noise();
24    format!("{:0>8}{}", base36_time, noise)
25}
26
27pub fn gen_aidx() -> String {
28    let current_time = ((chrono::Utc::now().timestamp() + 946684800) * 1000) as u64;
29    let base36_time = b36_encode(current_time);
30    let individual_id = format!("{:04X}", rand::thread_rng().gen_range(0..=u16::MAX));
31    let counter = format!("{:04X}", rand::thread_rng().gen_range(0..=u16::MAX));
32    format!("{:0>8}{}{}", base36_time, individual_id, counter)
33}
34
35pub fn parse_aidx(aidx: &str) -> Result<DateTime<Utc>, Box<dyn std::error::Error>> {
36    let base36_time = &aidx[..8];
37    let time_milliseconds = b36_decode(base36_time)?;
38    let timestamp = 946684800 + time_milliseconds / 1000;
39    Utc.timestamp_opt(timestamp as i64, 0)
40        .single()
41        .ok_or_else(|| "Invalid timestamp".into())
42}
43
44fn b36_encode(mut number: u64) -> String {
45    let alphabet = "0123456789abcdefghijklmnopqrstuvwxyz";
46    let mut base36 = String::new();
47    while number > 0 {
48        let (quotient, remainder) = (number / 36, number % 36);
49        base36.insert(0, alphabet.chars().nth(remainder as usize).unwrap());
50        number = quotient;
51    }
52    if base36.is_empty() {
53        base36.push(alphabet.chars().nth(0).unwrap());
54    }
55    base36
56}
57
58fn b36_decode(number: &str) -> Result<u64, ParseIntError> {
59    u64::from_str_radix(number, 36)
60}