1use rand::Rng;
2use std::time::{Duration, SystemTime};
3
4#[derive(PartialOrd, Ord, PartialEq, Eq, Hash, Clone, Copy)]
5pub struct SUlid(u64);
6
7impl SUlid {
8 #[allow(dead_code)]
9 const TIME_BITS: u8 = 43;
10 const TIME_BITMASK: u64 = 0b1111111111111111111111111111111111111111111;
11
12 const RAND_BITS: u8 = 21;
13 const RAND_BITMASK: u64 = 0b111111111111111111111;
14
15 pub fn new() -> Self {
17 let timestamp = SystemTime::now()
18 .duration_since(SystemTime::UNIX_EPOCH)
19 .unwrap_or(Duration::ZERO) .as_millis();
21
22 let val = ((timestamp as u64 & Self::TIME_BITMASK) << Self::RAND_BITS)
23 | (rand::rng().random::<u64>() & Self::TIME_BITMASK);
24
25 Self(val)
26 }
27
28 pub fn datetime(self) -> SystemTime {
30 SystemTime::UNIX_EPOCH + Duration::from_millis(self.0 >> Self::RAND_BITS)
31 }
32
33 pub fn random(self) -> u64 {
35 self.0 & Self::RAND_BITMASK
36 }
37}
38
39impl Default for SUlid {
40 fn default() -> Self {
41 Self::new()
42 }
43}