1use chrono::{DateTime, Utc};
8use rand::{CryptoRng, RngExt};
9use ulid::Ulid;
10
11use crate::clock::Clock;
12
13pub type BoxClock = Box<dyn Clock + Send>;
15pub type BoxRng = Box<dyn CryptoRng + Send>;
17
18pub trait UlidExt: Sized {
21 fn from_datetime_with_rng<R: RngExt + ?Sized>(datetime: DateTime<Utc>, rng: &mut R) -> Self;
28
29 fn datetime_utc(&self) -> DateTime<Utc>;
31}
32
33impl UlidExt for Ulid {
34 fn from_datetime_with_rng<R: RngExt + ?Sized>(datetime: DateTime<Utc>, rng: &mut R) -> Self {
35 let timestamp_ms = u64::try_from(datetime.timestamp_millis()).unwrap_or(0);
36 let timebits = timestamp_ms & ((1 << Ulid::TIME_BITS) - 1);
37
38 let msb = timebits << 16 | u64::from(rng.random::<u16>());
39 let lsb = rng.random::<u64>();
40 Ulid::from(u128::from(msb) << 64 | u128::from(lsb))
41 }
42
43 fn datetime_utc(&self) -> DateTime<Utc> {
44 DateTime::from_timestamp_millis(i64::try_from(self.timestamp_ms()).unwrap_or(i64::MAX))
45 .unwrap_or_default()
46 }
47}