1use std::time::{Duration, SystemTime, UNIX_EPOCH};
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
34pub struct Gid(u64);
35
36impl Gid {
37 pub fn new() -> Self {
38 let timestamp = SystemTime::now()
39 .duration_since(UNIX_EPOCH)
40 .expect("Time went backwards");
41 Self::from_duration(timestamp)
42 }
43 pub fn from_duration(timestamp: Duration) -> Self {
44 let timestamp = timestamp.as_secs();
45 let random_num: u32 = rand::random();
46 Gid(timestamp << 32 | random_num as u64)
47 }
48 pub fn timestamp(&self) -> u32 {
49 (self.0 >> 32) as u32
50 }
51 pub fn random(&self) -> u32 {
52 self.0 as u32
53 }
54 pub fn to_hex_string(&self) -> String {
55 format!("{:08x}{:08x}", self.timestamp(), self.random())
56 }
57 pub fn from_hex_string(s: &str) -> Option<Self> {
58 if s.len() != 16 {
59 return None;
60 }
61 let timestamp = u32::from_str_radix(&s[..8], 16).ok()? as u64;
62 let random = u32::from_str_radix(&s[8..], 16).ok()? as u64;
63 Some(Gid(timestamp << 32 | random))
64 }
65}
66
67impl std::fmt::Display for Gid {
68 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69 write!(f, "{}", self.to_hex_string())
70 }
71}
72
73impl std::str::FromStr for Gid {
74 type Err = &'static str;
75 fn from_str(s: &str) -> Result<Self, Self::Err> {
76 Gid::from_hex_string(s).ok_or("Invalid GID format")
77 }
78}
79
80impl Default for Gid {
81 fn default() -> Self {
82 Self::new()
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89
90 #[test]
91 fn test_gid_new() {
92 let gid1 = Gid::new();
93 let gid2 = Gid::new();
94 assert_ne!(gid1, gid2);
95 let timestamp1 = gid1.timestamp();
96 let timestamp2 = gid2.timestamp();
97 assert!(timestamp2 >= timestamp1);
98 assert!(timestamp2 - timestamp1 <= 1);
99 }
100
101 #[test]
102 fn test_gid_from_duration() {
103 let duration = Duration::from_secs(1234567890);
104 let gid = Gid::from_duration(duration);
105 assert_eq!(gid.timestamp(), 1234567890);
106 }
107
108 #[test]
109 fn test_gid_timestamp_and_random() {
110 let timestamp = 1672531200; let random_val = 0x12345678;
112 let gid = Gid((timestamp as u64) << 32 | random_val as u64);
113 assert_eq!(gid.timestamp(), timestamp);
114 assert_eq!(gid.random(), random_val);
115 }
116
117 #[test]
118 fn test_gid_to_hex_string() {
119 let gid = Gid(0x1234567890ABCDEF);
120 let hex_string = gid.to_hex_string();
121 assert_eq!(hex_string, "1234567890abcdef");
122 }
123
124 #[test]
125 fn test_gid_from_hex_string() {
126 let hex_string = "1234567890abcdef";
128 let gid = Gid::from_hex_string(hex_string).unwrap();
129 assert_eq!(gid.timestamp(), 0x12345678);
130 assert_eq!(gid.random(), 0x90ABCDEF);
131
132 assert!(Gid::from_hex_string("").is_none()); assert!(Gid::from_hex_string("123").is_none()); assert!(Gid::from_hex_string("1234567890abcdef123").is_none()); assert!(Gid::from_hex_string("gggggggggggggggg").is_none()); }
138}