Skip to main content

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}