mr_ulid/nonzero.rs
1use std::{
2 fmt,
3 num::NonZero,
4 str::FromStr,
5 time::{Duration, SystemTime},
6};
7
8use crate::{Error, RANDOM_BITS, RANDOM_MASK, ZeroableUlid, base32, generator, util};
9
10/// A ULID which never is zero.
11///
12/// Because this `Ulid` can never become zero, size of `Ulid` and size of `Option<Ulid>` are
13/// guaranteed to be equal thanks to Rust null pointer optimization:
14///
15/// ```
16/// use std::mem::size_of;
17/// use mr_ulid::Ulid;
18///
19/// assert_eq!(size_of::<Ulid>(), size_of::<Option<Ulid>>());
20/// ```
21///
22/// Parsing a zero value ULID will fail:
23///
24/// ```
25/// use mr_ulid::Ulid;
26///
27/// let s = "00000000000000000000000000";
28///
29/// assert!(s.parse::<Ulid>().is_err());
30/// ```
31///
32/// For a ULID which can become zero, check out the [`ZeroableUlid`] type.
33/// However, it is more idiomatic to just use `Option<Ulid>`.
34///
35#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
36#[repr(transparent)]
37pub struct Ulid(NonZero<u128>);
38
39impl Ulid {
40 /// Minimum allowed [`Ulid`]
41 ///
42 /// The smallest value for [`Ulid`] is 1, because zero is explicitly not allowed.
43 ///
44 /// # Example
45 ///
46 /// ```
47 /// use mr_ulid::Ulid;
48 ///
49 /// assert_eq!(Ulid::MIN.to_u128(), 1);
50 /// ```
51 pub const MIN: Self = unsafe { Self::from_u128_unchecked(1) };
52
53 /// Maximum allowed [`Ulid`]
54 ///
55 /// The largest value for [`Ulid`] is `u128::MAX`.
56 ///
57 /// # Example
58 ///
59 /// ```
60 /// use mr_ulid::Ulid;
61 ///
62 /// assert_eq!(Ulid::MAX.to_u128(), u128::MAX);
63 /// ```
64 pub const MAX: Self = unsafe { Self::from_u128_unchecked(u128::MAX) };
65
66 /// Generates a new unique ULID.
67 ///
68 /// The generated ULIDs are guaranteed to be unique and monotonically increasing and never zero.
69 ///
70 /// A lot of care is taken, that the ULIDs cannot overflow. You can create as many
71 /// ULIDs as you like, and they will always be unique and strict monotonically increasing.
72 ///
73 /// # Panics
74 ///
75 /// With the standard entropy source ([`STANDARD_ENTROPY_SOURCE`][generator::STANDARD_ENTROPY_SOURCE]),
76 /// this method will panic if the system date is somewhere after the year 10889 or before the Unix epoch (year 1970).
77 ///
78 /// # Example
79 ///
80 /// ```
81 /// use mr_ulid::Ulid;
82 ///
83 /// let u1 = Ulid::new();
84 /// let u2 = Ulid::new();
85 ///
86 /// assert!(u1 != u2);
87 /// assert!(u1 < u2);
88 ///
89 /// let t1 = u1.timestamp();
90 /// let t2 = u2.timestamp();
91 ///
92 /// let r1 = u1.randomness();
93 /// let r2 = u2.randomness();
94 ///
95 /// assert!((t1 < t2) || (t1 == t2 && r1 < r2));
96 /// ```
97 #[must_use]
98 pub fn new() -> Self {
99 Self(NonZero::new(generator::generate().unwrap()).unwrap())
100 }
101
102 /// Returns the timestamp part of a `Ulid`.
103 ///
104 /// The timestamp is measured in milliseconds since the Unix epoch (1. January 1970).
105 /// ULID timestamps are limited to 48 bits.
106 ///
107 /// # Example
108 ///
109 /// ```
110 /// use mr_ulid::Ulid;
111 ///
112 /// let u = Ulid::new();
113 ///
114 /// assert!(u.timestamp() > 1704067200000); // 1st January 2024
115 /// ```
116 #[must_use]
117 pub const fn timestamp(self) -> u64 {
118 (self.0.get() >> RANDOM_BITS) as u64
119 }
120
121 /// Returns the random part of a `Ulid`.
122 ///
123 /// The randomness of a `ULID` is limited to 80 bits.
124 ///
125 /// # Example
126 ///
127 /// ```
128 /// use mr_ulid::Ulid;
129 ///
130 /// let u = Ulid::new();
131 ///
132 /// assert!(u.randomness() < (1<<80));
133 /// ```
134 ///
135 #[must_use]
136 pub const fn randomness(self) -> u128 {
137 self.0.get() & RANDOM_MASK
138 }
139
140 /// Returns the timestamp part of a `Ulid` as a `SystemTime`.
141 ///
142 /// # Panics
143 ///
144 /// In Rust the allowed range for [`SystemTime`] is not defined.
145 /// So this method may panic if the timestamp of the ULID cannot represented with [`SystemTime`].
146 /// On most common systems that will not happen.
147 ///
148 /// For a variant which never panics, see [`Ulid::try_datetime`].
149 ///
150 /// # Example
151 ///
152 /// ```
153 /// use std::time::SystemTime;
154 /// use mr_ulid::Ulid;
155 ///
156 /// let u = Ulid::new();
157 ///
158 /// assert!(u.datetime() <= SystemTime::now());
159 /// ```
160 #[must_use]
161 pub fn datetime(self) -> SystemTime {
162 SystemTime::UNIX_EPOCH + Duration::from_millis(self.timestamp())
163 }
164
165 /// Converts this `Ulid` to a [`ZeroableUlid`].
166 ///
167 /// This method always succeeds, as every [`Ulid`] is a valid [`ZeroableUlid`].
168 ///
169 /// # Example
170 ///
171 /// ```
172 /// use mr_ulid::Ulid;
173 ///
174 /// let u1 = Ulid::new();
175 /// let u2 = u1.to_zeroable_ulid();
176 ///
177 /// assert_eq!(u1.to_u128(), u2.to_u128());
178 ///
179 /// ```
180 #[must_use]
181 pub const fn to_zeroable_ulid(self) -> ZeroableUlid {
182 ZeroableUlid::from_u128(self.0.get())
183 }
184
185 /// Creates a `Ulid` from a [`ZeroableUlid`].
186 ///
187 /// When the [`ZeroableUlid`] is zero, `None` is returned.
188 ///
189 /// # Example
190 ///
191 /// ```
192 /// use mr_ulid::{Ulid, ZeroableUlid};
193 ///
194 /// let u1 = ZeroableUlid::new();
195 /// assert!(Ulid::from_zeroable_ulid(u1).is_some());
196 ///
197 /// let u2 = ZeroableUlid::zeroed(); // Create a ZeroableUlid with zero value
198 /// assert!(Ulid::from_zeroable_ulid(u2).is_none());
199 /// ```
200 #[must_use]
201 pub const fn from_zeroable_ulid(zeroable: ZeroableUlid) -> Option<Self> {
202 Self::from_u128(zeroable.to_u128())
203 }
204
205 /// Returns the timestamp and randomness parts of a `Ulid` as a pair.
206 ///
207 /// # Example
208 ///
209 /// ```
210 /// use mr_ulid::Ulid;
211 ///
212 /// let u = Ulid::new();
213 /// let (timestamp, randomness) = u.to_parts();
214 ///
215 /// assert_eq!(timestamp, u.timestamp());
216 /// assert_eq!(randomness, u.randomness());
217 /// ```
218 #[must_use]
219 pub const fn to_parts(self) -> (u64, u128) {
220 (self.timestamp(), self.randomness())
221 }
222
223 /// Creates a `Ulid` from a timestamp and randomness parts.
224 ///
225 /// # Errors
226 ///
227 /// Will fail if the timestamp (48 bits) or randomness (80 bits) are out of range,
228 /// and will fail, if both values are zero, because [`Ulid`] is not allowed to be zero.
229 ///
230 /// # Example
231 ///
232 /// ```
233 /// # use std::error::Error;
234 /// # fn main() -> Result<(), Box<dyn Error>> {
235 /// use mr_ulid::Ulid;
236 ///
237 /// let u1 = Ulid::new();
238 /// let (timestamp, randomness) = u1.to_parts();
239 /// let u2 = Ulid::from_parts(timestamp, randomness)?;
240 ///
241 /// assert_eq!(u1, u2);
242 ///
243 /// assert!(Ulid::from_parts(0, 0).is_err());
244 /// # Ok(()) }
245 /// ```
246 pub const fn from_parts(timestamp: u64, randomness: u128) -> Result<Self, Error> {
247 match util::from_parts(timestamp, randomness) {
248 Ok(n) => match Self::from_u128(n) {
249 Some(ulid) => Ok(ulid),
250 None => Err(Error::InvalidZero),
251 },
252 Err(error) => Err(error),
253 }
254 }
255
256 /// Converts a `Ulid` into binary bytes
257 ///
258 /// The bytes are in network byte order (big endian).
259 ///
260 /// # Example
261 ///
262 /// ```
263 /// # use std::error::Error;
264 /// # fn main() -> Result<(), Box<dyn Error>> {
265 /// use mr_ulid::Ulid;
266 ///
267 // cspell:disable-next-line
268 /// let ulid: Ulid = "01JB05JV6H9ZA2YQ6X3K1DAGVA".parse()?;
269 ///
270 /// assert_eq!(ulid.to_bytes(), [1, 146, 192, 89, 108, 209, 79, 212, 47, 92, 221, 28, 194, 213, 67, 106]);
271 /// # Ok(()) }
272 /// ```
273 #[must_use]
274 pub const fn to_bytes(self) -> [u8; 16] {
275 self.0.get().to_be_bytes()
276 }
277
278 /// Creates a `Ulid` from a binary byte array.
279 ///
280 /// The byte array must be in network byte order (big endian).
281 ///
282 /// Returns `None` if all bytes in the byte array are zero, because [`Ulid`] is not allowed to be zero.
283 ///
284 /// # Example
285 ///
286 /// ```
287 /// # { inner(); fn inner() -> Option<()> {
288 /// use mr_ulid::Ulid;
289 ///
290 /// let bytes: [u8; 16] = [1, 146, 192, 89, 108, 209, 79, 212, 47, 92, 221, 28, 194, 213, 67, 106];
291 /// let u = Ulid::from_bytes(bytes)?;
292 ///
293 // cspell:disable-next-line
294 /// assert_eq!(u.to_string(), "01JB05JV6H9ZA2YQ6X3K1DAGVA");
295 /// # Some(()) }}
296 /// ```
297 #[must_use]
298 pub const fn from_bytes(bytes: [u8; 16]) -> Option<Self> {
299 Self::from_u128(u128::from_be_bytes(bytes))
300 }
301
302 /// Converts a `Ulid` into a `u128` integer.
303 ///
304 /// # Example
305 ///
306 /// ```
307 /// # use std::error::Error;
308 /// # fn main() -> Result<(), Box<dyn Error>> {
309 /// use mr_ulid::Ulid;
310 ///
311 // cspell:disable-next-line
312 /// let u: Ulid = "01JB07NQ643XZXVHZDY0JNYR02".parse()?;
313 ///
314 /// assert_eq!(u.to_u128(), 2091207293934528941058695985186693122);
315 /// # Ok(()) }
316 /// ```
317 #[must_use]
318 pub const fn to_u128(self) -> u128 {
319 self.0.get()
320 }
321
322 /// Creates a `Ulid` from a `u128` integer.
323 ///
324 /// # Errors
325 ///
326 /// Return `None` if the value was zero, because [`Ulid`] is not allowed to be zero.
327 ///
328 /// # Example
329 ///
330 /// ```
331 /// # { inner(); fn inner() -> Option<()> {
332 /// use mr_ulid::Ulid;
333 ///
334 /// let n = 2091207293934528941058695985186693122_u128;
335 /// let u = Ulid::from_u128(n)?;
336 ///
337 // cspell:disable-next-line
338 /// assert_eq!(u.to_string(), "01JB07NQ643XZXVHZDY0JNYR02");
339 /// # Some(()) }}
340 /// ```
341 #[must_use]
342 pub const fn from_u128(n: u128) -> Option<Self> {
343 match NonZero::new(n) {
344 Some(non_zero) => Some(Self(non_zero)),
345 None => None,
346 }
347 }
348
349 /// Converts a `Ulid` into a `NonZero<u128>` integer.
350 ///
351 /// # Example
352 ///
353 /// ```
354 /// # { inner(); fn inner() -> Option<()> {
355 /// use std::num::NonZero;
356 ///
357 /// use mr_ulid::Ulid;
358 ///
359 // cspell:disable-next-line
360 /// let u = Ulid::from_u128(42)?;
361 ///
362 /// assert_eq!(u.to_non_zero_u128(), NonZero::new(42)?);
363 /// # Some(()) }}
364 /// ```
365 #[must_use]
366 pub const fn to_non_zero_u128(self) -> NonZero<u128> {
367 self.0
368 }
369
370 /// Creates a `Ulid` from a `NonZero<u128>` integer.
371 ///
372 /// Because the `NonZero<u128>` integer cannot be zero, this method always succeed.
373 ///
374 /// # Example
375 ///
376 /// ```
377 /// # { inner(); fn inner() -> Option<()> {
378 /// use std::num::NonZero;
379 ///
380 /// use mr_ulid::Ulid;
381 ///
382 /// let n = NonZero::new(2091207293934528941058695985186693122)?;
383 /// let u = Ulid::from_non_zero_u128(n);
384 ///
385 // cspell:disable-next-line
386 /// assert_eq!(u.to_string(), "01JB07NQ643XZXVHZDY0JNYR02");
387 /// # Some(()) }}
388 /// ```
389 #[must_use]
390 pub const fn from_non_zero_u128(non_zero: NonZero<u128>) -> Self {
391 Self(non_zero)
392 }
393
394 /// Generates a new `Ulid` and never panics.
395 ///
396 /// This is a variant of [`Ulid::new()`] which never panics (with the [`STANDARD_ENTROPY_SOURCE`](generator::STANDARD_ENTROPY_SOURCE)).
397 ///
398 /// In the case of problems with the ULID-generator, this function returns `None`.
399 ///
400 /// # Example
401 ///
402 /// ```
403 /// # { inner(); fn inner() -> Option<()> {
404 /// use mr_ulid::Ulid;
405 ///
406 /// let u1 = Ulid::try_new()?;
407 /// let u2 = Ulid::try_new()?;
408 ///
409 /// assert!(u1 != u2);
410 /// assert!(u1.timestamp() <= u2.timestamp());
411 /// # Some(()) }}
412 /// ```
413 #[must_use]
414 pub fn try_new() -> Option<Self> {
415 Some(Self(NonZero::new(generator::generate()?)?))
416 }
417
418 /// Returns the timestamp part of a `Ulid` as a [`SystemTime`] and never panics.
419 ///
420 /// This is a variant of [`Ulid::datetime()`] which never panics.
421 ///
422 /// In the case that the timestamp of a [`Ulid`] cannot be encoded in a [`SystemTime`], this method returns `None`.
423 ///
424 /// # Example
425 ///
426 /// ```
427 /// use std::time::SystemTime;
428 /// use mr_ulid::Ulid;
429 ///
430 /// let u = Ulid::new();
431 ///
432 /// let datetime: Option<SystemTime> = u.try_datetime();
433 /// ```
434 #[must_use]
435 pub fn try_datetime(self) -> Option<SystemTime> {
436 SystemTime::UNIX_EPOCH.checked_add(Duration::from_millis(self.timestamp()))
437 }
438
439 /// Return the string representation of a [`Ulid`] and never panics.
440 ///
441 /// While the blanket implementation of [`std::string::ToString`] for `std::fmt::Display` may
442 /// panic, this method is guaranteed to never panic, but returns `None` if the string representation cannot be created.
443 /// One reason this can happen is if the allocation of memory for the string fails.
444 #[must_use]
445 pub fn try_to_string(self) -> Option<String> {
446 util::try_to_string(self.0.get())
447 }
448
449 /// Creates a `Ulid` from timestamp and randomness parts without checking.
450 ///
451 /// This results in undefined behaviour if timestamp or randomness parts are too large
452 /// or when both of them are zero.
453 ///
454 /// # Safety
455 ///
456 /// - Timestamp must be less than 2<sup>48</sup>.
457 /// - Randomness must be less than 2<sup>80</sup>.
458 /// - One part (timestamp or randomness) must be non-zero.
459 #[must_use]
460 pub const unsafe fn from_parts_unchecked(timestamp: u64, randomness: u128) -> Self {
461 let n = ((timestamp as u128) << RANDOM_BITS) | randomness;
462 Self(unsafe { NonZero::new_unchecked(n) })
463 }
464
465 /// Creates a `Ulid` from a `u128` integer without checking whether the value is zero.
466 ///
467 /// This results in undefined behaviour if the value is zero.
468 ///
469 /// # Safety
470 ///
471 /// The value must not be zero.
472 #[must_use]
473 pub const unsafe fn from_u128_unchecked(n: u128) -> Self {
474 Self(unsafe { NonZero::new_unchecked(n) })
475 }
476
477 /// Creates a `Ulid` from a binary byte array without checking whether at least one byte is non-zero.
478 ///
479 /// This results in undefined behaviour if all bytes are zero.
480 ///
481 /// # Safety
482 ///
483 /// At least one byte must be non-zero.
484 #[must_use]
485 pub const unsafe fn from_bytes_unchecked(bytes: [u8; 16]) -> Self {
486 let n = u128::from_be_bytes(bytes);
487 Self(unsafe { NonZero::new_unchecked(n) })
488 }
489}
490
491impl Default for Ulid {
492 fn default() -> Self {
493 Self::new()
494 }
495}
496
497impl fmt::Debug for Ulid {
498 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
499 util::debug_ulid("Ulid", self.0.get(), f)
500 }
501}
502
503impl fmt::Display for Ulid {
504 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
505 let mut buffer = [0; 26];
506 f.write_str(base32::encode(self.0.get(), &mut buffer))
507 }
508}
509
510impl FromStr for Ulid {
511 type Err = Error;
512 fn from_str(s: &str) -> Result<Self, Self::Err> {
513 let buffer = util::as_array(s.as_bytes())?;
514 Self::from_u128(base32::decode(buffer)?).ok_or(Error::InvalidZero)
515 }
516}
517
518impl TryFrom<ZeroableUlid> for Ulid {
519 type Error = Error;
520 fn try_from(zeroable: ZeroableUlid) -> Result<Self, Self::Error> {
521 Self::from_u128(zeroable.to_u128()).ok_or(Error::InvalidZero)
522 }
523}
524
525impl From<Ulid> for u128 {
526 fn from(ulid: Ulid) -> Self {
527 ulid.to_u128()
528 }
529}
530
531impl TryFrom<u128> for Ulid {
532 type Error = Error;
533 fn try_from(n: u128) -> Result<Self, Self::Error> {
534 Self::from_u128(n).ok_or(Error::InvalidZero)
535 }
536}
537
538impl From<Ulid> for NonZero<u128> {
539 fn from(ulid: Ulid) -> Self {
540 ulid.to_non_zero_u128()
541 }
542}
543
544impl From<NonZero<u128>> for Ulid {
545 fn from(non_zero: NonZero<u128>) -> Self {
546 Self::from_non_zero_u128(non_zero)
547 }
548}
549
550impl From<Ulid> for [u8; 16] {
551 fn from(ulid: Ulid) -> Self {
552 ulid.to_bytes()
553 }
554}
555
556impl TryFrom<[u8; 16]> for Ulid {
557 type Error = Error;
558 fn try_from(bytes: [u8; 16]) -> Result<Self, Self::Error> {
559 Self::from_bytes(bytes).ok_or(Error::InvalidZero)
560 }
561}
562
563impl TryFrom<&[u8; 16]> for Ulid {
564 type Error = Error;
565 fn try_from(bytes: &[u8; 16]) -> Result<Self, Self::Error> {
566 Self::from_bytes(*bytes).ok_or(Error::InvalidZero)
567 }
568}
569
570impl TryFrom<&[u8]> for Ulid {
571 type Error = Error;
572 fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
573 Self::from_bytes(*util::as_array(bytes)?).ok_or(Error::InvalidZero)
574 }
575}