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}