1use std::{num::ParseIntError, time::SystemTime};
9
10use chrono::{DateTime, TimeZone, Utc};
11use lazy_static::lazy_static;
12use rand::Rng;
13use regex::Regex;
14
15const CHARS: &str = "0123456789abcdef";
16lazy_static! {
17 static ref MEID_REGEX: Regex = Regex::new(r"^[0-9a-f]{24}$").unwrap();
18}
19
20fn get_time(mut time: u64) -> String {
21 if time == 0 {
22 return CHARS[0..1].to_string();
23 }
24
25 time += 0x800000000000;
26
27 format!("{:012x}", time)
28}
29
30fn get_random() -> String {
31 let mut rng = rand::rng();
32 (0..12)
33 .map(|_| {
34 let idx = rng.random_range(0..CHARS.len());
35 CHARS.chars().nth(idx).unwrap()
36 })
37 .collect()
38}
39
40pub fn gen(time: u64) -> String {
42 format!("{}{}", get_time(time), get_random())
43}
44
45pub fn parse(id: &str) -> Result<SystemTime, ParseIntError> {
46 let timestamp = u64::from_str_radix(&id[0..12], 16).unwrap() - 0x800000000000;
47 let time = SystemTime::UNIX_EPOCH + std::time::Duration::from_millis(timestamp);
48 Ok(time)
49}
50
51pub fn parse_meid_with_format(id: &str) -> DateTime<Utc> {
52 let time = parse(id).unwrap();
53 let duration = time.duration_since(SystemTime::UNIX_EPOCH).unwrap();
54 Utc.timestamp_millis_opt(duration.as_millis() as i64)
55 .unwrap()
56}
57
58#[cfg(test)]
63mod tests {
64 use super::*;
65
66 #[test]
67 fn test_gen() {
68 let generated = gen(1735889660414);
69 println!("{}", generated);
70 assert_eq!(generated.len(), 24);
71 assert!(MEID_REGEX.is_match(&generated));
72 }
73
74 #[test]
75 fn test_parse() {
76 let generated = gen(1735889660414);
77 let parsed = parse(&generated).unwrap();
78 assert_eq!(
79 parsed
80 .duration_since(SystemTime::UNIX_EPOCH)
81 .unwrap()
82 .as_millis(),
83 1735889660414
84 );
85 }
86}