ulid/
generator.rs

1use std::time::{Duration, SystemTime};
2
3use std::fmt;
4
5use crate::Ulid;
6
7/// A Ulid generator that provides monotonically increasing Ulids
8pub struct Generator {
9    previous: Ulid,
10}
11
12impl Generator {
13    /// Create a new ulid generator for monotonically ordered ulids
14    ///
15    /// # Example
16    /// ```rust
17    /// use ulid::Generator;
18    ///
19    /// let mut gen = Generator::new();
20    ///
21    /// let ulid1 = gen.generate().unwrap();
22    /// let ulid2 = gen.generate().unwrap();
23    ///
24    /// assert!(ulid1 < ulid2);
25    /// ```
26    pub const fn new() -> Generator {
27        Generator {
28            previous: Ulid::nil(),
29        }
30    }
31
32    /// Generate a new Ulid. Each call is guaranteed to provide a Ulid with a larger value than the
33    /// last call. If the random bits would overflow, this method will return an error.
34    ///
35    /// ```rust
36    /// use ulid::Generator;
37    /// let mut gen = Generator::new();
38    ///
39    /// let ulid1 = gen.generate().unwrap();
40    /// let ulid2 = gen.generate().unwrap();
41    ///
42    /// assert!(ulid1 < ulid2);
43    /// ```
44    pub fn generate(&mut self) -> Result<Ulid, MonotonicError> {
45        self.generate_from_datetime(crate::time_utils::now())
46    }
47
48    /// Generate a new Ulid matching the given DateTime.
49    /// Each call is guaranteed to provide a Ulid with a larger value than the last call.
50    /// If the random bits would overflow, this method will return an error.
51    ///
52    /// # Example
53    /// ```rust
54    /// use ulid::Generator;
55    /// use std::time::SystemTime;
56    ///
57    /// let dt = SystemTime::now();
58    /// let mut gen = Generator::new();
59    ///
60    /// let ulid1 = gen.generate_from_datetime(dt).unwrap();
61    /// let ulid2 = gen.generate_from_datetime(dt).unwrap();
62    ///
63    /// assert_eq!(ulid1.datetime(), ulid2.datetime());
64    /// assert!(ulid1 < ulid2);
65    /// ```
66    pub fn generate_from_datetime(&mut self, datetime: SystemTime) -> Result<Ulid, MonotonicError> {
67        self.generate_from_datetime_with_source(datetime, &mut rand::rng())
68    }
69
70    /// Generate a new monotonic increasing Ulid with the given source
71    /// Each call is guaranteed to provide a Ulid with a larger value than the last call.
72    /// If the random bits would overflow, this method will return an error.
73    ///
74    /// # Example
75    /// ```rust
76    /// use ulid::Generator;
77    /// use ulid::Ulid;
78    /// use std::time::SystemTime;
79    /// use rand::prelude::*;
80    ///
81    /// let mut rng = StdRng::from_os_rng();
82    /// let mut gen = Generator::new();
83    ///
84    /// let ulid1 = gen.generate_with_source(&mut rng).unwrap();
85    /// let ulid2 = gen.generate_with_source(&mut rng).unwrap();
86    ///
87    /// assert!(ulid1 < ulid2);
88    /// ```
89    pub fn generate_with_source<R>(&mut self, source: &mut R) -> Result<Ulid, MonotonicError>
90    where
91        R: rand::Rng + ?Sized,
92    {
93        self.generate_from_datetime_with_source(crate::time_utils::now(), source)
94    }
95
96    /// Generate a new monotonic increasing Ulid with the given source matching the given DateTime
97    /// Each call is guaranteed to provide a Ulid with a larger value than the last call.
98    /// If the random bits would overflow, this method will return an error.
99    ///
100    /// # Example
101    /// ```rust
102    /// use ulid::Generator;
103    /// use std::time::SystemTime;
104    /// use rand::prelude::*;
105    ///
106    /// let dt = SystemTime::now();
107    /// let mut rng = StdRng::from_os_rng();
108    /// let mut gen = Generator::new();
109    ///
110    /// let ulid1 = gen.generate_from_datetime_with_source(dt, &mut rng).unwrap();
111    /// let ulid2 = gen.generate_from_datetime_with_source(dt, &mut rng).unwrap();
112    ///
113    /// assert_eq!(ulid1.datetime(), ulid2.datetime());
114    /// assert!(ulid1 < ulid2);
115    /// ```
116    pub fn generate_from_datetime_with_source<R>(
117        &mut self,
118        datetime: SystemTime,
119        source: &mut R,
120    ) -> Result<Ulid, MonotonicError>
121    where
122        R: rand::Rng + ?Sized,
123    {
124        let last_ms = self.previous.timestamp_ms();
125        // maybe time went backward, or it is the same ms.
126        // increment instead of generating a new random so that it is monotonic
127        if datetime
128            .duration_since(SystemTime::UNIX_EPOCH)
129            .unwrap_or(Duration::ZERO)
130            .as_millis()
131            <= u128::from(last_ms)
132        {
133            if let Some(next) = self.previous.increment() {
134                self.previous = next;
135                return Ok(next);
136            } else {
137                return Err(MonotonicError::Overflow);
138            }
139        }
140        let next = Ulid::from_datetime_with_source(datetime, source);
141        self.previous = next;
142        Ok(next)
143    }
144}
145
146impl Default for Generator {
147    fn default() -> Self {
148        Self::new()
149    }
150}
151
152/// Error while trying to generate a monotonic increment in the same millisecond
153#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
154pub enum MonotonicError {
155    /// Would overflow into the next millisecond
156    Overflow,
157}
158
159impl std::error::Error for MonotonicError {}
160
161impl fmt::Display for MonotonicError {
162    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
163        let text = match *self {
164            MonotonicError::Overflow => "Ulid random bits would overflow",
165        };
166        write!(f, "{}", text)
167    }
168}
169
170#[cfg(test)]
171mod tests {
172    use super::*;
173    use std::time::Duration;
174
175    #[test]
176    fn test_order_monotonic() {
177        let dt = SystemTime::now();
178        let mut gen = Generator::new();
179        let ulid1 = gen.generate_from_datetime(dt).unwrap();
180        let ulid2 = gen.generate_from_datetime(dt).unwrap();
181        let ulid3 = Ulid::from_datetime(dt + Duration::from_millis(1));
182        assert_eq!(ulid1.0 + 1, ulid2.0);
183        assert!(ulid2 < ulid3);
184        assert!(ulid2.timestamp_ms() < ulid3.timestamp_ms())
185    }
186
187    #[test]
188    fn test_order_monotonic_with_source() {
189        use rand::rngs::mock::StepRng;
190        let mut source = StepRng::new(123, 0);
191        let mut gen = Generator::new();
192
193        let _has_default = Generator::default();
194
195        let ulid1 = gen.generate_with_source(&mut source).unwrap();
196        let ulid2 = gen.generate_with_source(&mut source).unwrap();
197        assert!(ulid1 < ulid2);
198    }
199
200    #[test]
201    fn can_display_things() {
202        println!("{}", MonotonicError::Overflow);
203    }
204}