1use crate::{bitmask, Ulid};
2use std::time::{Duration, SystemTime};
3
4impl Ulid {
5 pub fn new() -> Ulid {
16 Ulid::from_datetime(crate::time_utils::now())
17 }
18
19 pub fn with_source<R: rand::Rng>(source: &mut R) -> Ulid {
30 Ulid::from_datetime_with_source(crate::time_utils::now(), source)
31 }
32
33 pub fn from_datetime(datetime: SystemTime) -> Ulid {
48 Ulid::from_datetime_with_source(datetime, &mut rand::rng())
49 }
50
51 pub fn from_datetime_with_source<R>(datetime: SystemTime, source: &mut R) -> Ulid
66 where
67 R: rand::Rng + ?Sized,
68 {
69 let timestamp = datetime
70 .duration_since(SystemTime::UNIX_EPOCH)
71 .unwrap_or(Duration::ZERO)
72 .as_millis();
73 let timebits = (timestamp & bitmask!(Self::TIME_BITS)) as u64;
74
75 let msb = timebits << 16 | u64::from(source.random::<u16>());
76 let lsb = source.random::<u64>();
77 Ulid::from((msb, lsb))
78 }
79
80 pub fn datetime(&self) -> SystemTime {
96 let stamp = self.timestamp_ms();
97 SystemTime::UNIX_EPOCH + Duration::from_millis(stamp)
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104
105 #[test]
106 fn test_dynamic() {
107 let ulid = Ulid::new();
108 let encoded = ulid.to_string();
109 let ulid2 = Ulid::from_string(&encoded).expect("failed to deserialize");
110
111 println!("{}", encoded);
112 println!("{:?}", ulid);
113 println!("{:?}", ulid2);
114 assert_eq!(ulid, ulid2);
115 }
116
117 #[test]
118 fn test_source() {
119 use rand::rngs::mock::StepRng;
120 let mut source = StepRng::new(123, 0);
121
122 let u1 = Ulid::with_source(&mut source);
123 let dt = SystemTime::now() + Duration::from_millis(1);
124 let u2 = Ulid::from_datetime_with_source(dt, &mut source);
125 let u3 = Ulid::from_datetime_with_source(dt, &mut source);
126
127 assert!(u1 < u2);
128 assert_eq!(u2, u3);
129 }
130
131 #[test]
132 fn test_order() {
133 let dt = SystemTime::now();
134 let ulid1 = Ulid::from_datetime(dt);
135 let ulid2 = Ulid::from_datetime(dt + Duration::from_millis(1));
136 assert!(ulid1 < ulid2);
137 }
138
139 #[test]
140 fn test_datetime() {
141 let dt = SystemTime::now();
142 let ulid = Ulid::from_datetime(dt);
143
144 println!("{:?}, {:?}", dt, ulid.datetime());
145 assert!(ulid.datetime() <= dt);
146 assert!(ulid.datetime() + Duration::from_millis(1) >= dt);
147 }
148
149 #[test]
150 fn test_timestamp() {
151 let dt = SystemTime::now();
152 let ulid = Ulid::from_datetime(dt);
153 let ts = dt
154 .duration_since(SystemTime::UNIX_EPOCH)
155 .unwrap()
156 .as_millis();
157
158 assert_eq!(u128::from(ulid.timestamp_ms()), ts);
159 }
160
161 #[test]
162 fn default_is_nil() {
163 assert_eq!(Ulid::default(), Ulid::nil());
164 }
165
166 #[test]
167 fn nil_is_at_unix_epoch() {
168 assert_eq!(Ulid::nil().datetime(), SystemTime::UNIX_EPOCH);
169 }
170
171 #[test]
172 fn truncates_at_unix_epoch() {
173 if let Some(before_epoch) = SystemTime::UNIX_EPOCH.checked_sub(Duration::from_secs(100)) {
174 assert!(before_epoch < SystemTime::UNIX_EPOCH);
175 assert_eq!(
176 Ulid::from_datetime(before_epoch).datetime(),
177 SystemTime::UNIX_EPOCH
178 );
179 } else {
180 }
182 }
183}