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