Coverage Report

Created: 2026-03-23 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/ulid-1.2.1/src/generator.rs
Line
Count
Source
1
use std::time::{Duration, SystemTime};
2
3
use std::fmt;
4
5
use crate::Ulid;
6
7
/// A Ulid generator that provides monotonically increasing Ulids
8
pub struct Generator {
9
    previous: Ulid,
10
}
11
12
impl 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
0
    pub const fn new() -> Generator {
27
0
        Generator {
28
0
            previous: Ulid::nil(),
29
0
        }
30
0
    }
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
0
    pub fn generate(&mut self) -> Result<Ulid, MonotonicError> {
45
0
        self.generate_from_datetime(crate::time_utils::now())
46
0
    }
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
0
    pub fn generate_from_datetime(&mut self, datetime: SystemTime) -> Result<Ulid, MonotonicError> {
67
0
        self.generate_from_datetime_with_source(datetime, &mut rand::rng())
68
0
    }
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
0
    pub fn generate_with_source<R>(&mut self, source: &mut R) -> Result<Ulid, MonotonicError>
90
0
    where
91
0
        R: rand::Rng + ?Sized,
92
    {
93
0
        self.generate_from_datetime_with_source(crate::time_utils::now(), source)
94
0
    }
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
0
    pub fn generate_from_datetime_with_source<R>(
117
0
        &mut self,
118
0
        datetime: SystemTime,
119
0
        source: &mut R,
120
0
    ) -> Result<Ulid, MonotonicError>
121
0
    where
122
0
        R: rand::Rng + ?Sized,
123
    {
124
0
        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
0
        if datetime
128
0
            .duration_since(SystemTime::UNIX_EPOCH)
129
0
            .unwrap_or(Duration::ZERO)
130
0
            .as_millis()
131
0
            <= u128::from(last_ms)
132
        {
133
0
            if let Some(next) = self.previous.increment() {
134
0
                self.previous = next;
135
0
                return Ok(next);
136
            } else {
137
0
                return Err(MonotonicError::Overflow);
138
            }
139
0
        }
140
0
        let next = Ulid::from_datetime_with_source(datetime, source);
141
0
        self.previous = next;
142
0
        Ok(next)
143
0
    }
144
}
145
146
impl Default for Generator {
147
0
    fn default() -> Self {
148
0
        Self::new()
149
0
    }
150
}
151
152
/// Error while trying to generate a monotonic increment in the same millisecond
153
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
154
pub enum MonotonicError {
155
    /// Would overflow into the next millisecond
156
    Overflow,
157
}
158
159
impl std::error::Error for MonotonicError {}
160
161
impl fmt::Display for MonotonicError {
162
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
163
0
        let text = match *self {
164
0
            MonotonicError::Overflow => "Ulid random bits would overflow",
165
        };
166
0
        write!(f, "{}", text)
167
0
    }
168
}
169
170
#[cfg(test)]
171
mod 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
}