uuid/
timestamp.rs

1//! Generating UUIDs from timestamps.
2//!
3//! Timestamps are used in a few UUID versions as a source of decentralized
4//! uniqueness (as in versions 1 and 6), and as a way to enable sorting (as
5//! in versions 6 and 7). Timestamps aren't encoded the same way by all UUID
6//! versions so this module provides a single [`Timestamp`] type that can
7//! convert between them.
8//!
9//! # Timestamp representations in UUIDs
10//!
11//! Versions 1 and 6 UUIDs use a bespoke timestamp that consists of the
12//! number of 100ns ticks since `1582-10-15 00:00:00`, along with
13//! a counter value to avoid duplicates.
14//!
15//! Version 7 UUIDs use a more standard timestamp that consists of the
16//! number of millisecond ticks since the Unix epoch (`1970-01-01 00:00:00`).
17//!
18//! # References
19//!
20//! * [UUID Version 1 in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-5.1)
21//! * [UUID Version 7 in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-5.7)
22//! * [Timestamp Considerations in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-6.1)
23
24use core::cmp;
25
26use crate::Uuid;
27
28/// The number of 100 nanosecond ticks between the RFC 9562 epoch
29/// (`1582-10-15 00:00:00`) and the Unix epoch (`1970-01-01 00:00:00`).
30pub const UUID_TICKS_BETWEEN_EPOCHS: u64 = 0x01B2_1DD2_1381_4000;
31
32/// A timestamp that can be encoded into a UUID.
33///
34/// This type abstracts the specific encoding, so versions 1, 6, and 7
35/// UUIDs can both be supported through the same type, even
36/// though they have a different representation of a timestamp.
37///
38/// # References
39///
40/// * [Timestamp Considerations in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-6.1)
41/// * [UUID Generator States in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-6.3)
42#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
43pub struct Timestamp {
44    seconds: u64,
45    subsec_nanos: u32,
46    counter: u128,
47    usable_counter_bits: u8,
48}
49
50impl Timestamp {
51    /// Get a timestamp representing the current system time and up to a 128-bit counter.
52    ///
53    /// This method defers to the standard library's `SystemTime` type.
54    #[cfg(feature = "std")]
55    pub fn now(context: impl ClockSequence<Output = impl Into<u128>>) -> Self {
56        let (seconds, subsec_nanos) = now();
57
58        let (counter, seconds, subsec_nanos) =
59            context.generate_timestamp_sequence(seconds, subsec_nanos);
60        let counter = counter.into();
61        let usable_counter_bits = context.usable_bits() as u8;
62
63        Timestamp {
64            seconds,
65            subsec_nanos,
66            counter,
67            usable_counter_bits,
68        }
69    }
70
71    /// Construct a `Timestamp` from the number of 100 nanosecond ticks since 00:00:00.00,
72    /// 15 October 1582 (the date of Gregorian reform to the Christian calendar) and a 14-bit
73    /// counter, as used in versions 1 and 6 UUIDs.
74    ///
75    /// # Overflow
76    ///
77    /// If conversion from RFC 9562 ticks to the internal timestamp format would overflow
78    /// it will wrap.
79    pub const fn from_gregorian(ticks: u64, counter: u16) -> Self {
80        let (seconds, subsec_nanos) = Self::gregorian_to_unix(ticks);
81
82        Timestamp {
83            seconds,
84            subsec_nanos,
85            counter: counter as u128,
86            usable_counter_bits: 14,
87        }
88    }
89
90    /// Construct a `Timestamp` from a Unix timestamp and up to a 128-bit counter, as used in version 7 UUIDs.
91    pub const fn from_unix_time(
92        seconds: u64,
93        subsec_nanos: u32,
94        counter: u128,
95        usable_counter_bits: u8,
96    ) -> Self {
97        Timestamp {
98            seconds,
99            subsec_nanos,
100            counter,
101            usable_counter_bits,
102        }
103    }
104
105    /// Construct a `Timestamp` from a Unix timestamp and up to a 128-bit counter, as used in version 7 UUIDs.
106    pub fn from_unix(
107        context: impl ClockSequence<Output = impl Into<u128>>,
108        seconds: u64,
109        subsec_nanos: u32,
110    ) -> Self {
111        let (counter, seconds, subsec_nanos) =
112            context.generate_timestamp_sequence(seconds, subsec_nanos);
113        let counter = counter.into();
114        let usable_counter_bits = context.usable_bits() as u8;
115
116        Timestamp {
117            seconds,
118            subsec_nanos,
119            counter,
120            usable_counter_bits,
121        }
122    }
123
124    /// Get the value of the timestamp as the number of 100 nanosecond ticks since 00:00:00.00,
125    /// 15 October 1582 and a 14-bit counter, as used in versions 1 and 6 UUIDs.
126    ///
127    /// # Overflow
128    ///
129    /// If conversion from the internal timestamp format to ticks would overflow
130    /// then it will wrap.
131    ///
132    /// If the internal counter is wider than 14 bits then it will be truncated to 14 bits.
133    pub const fn to_gregorian(&self) -> (u64, u16) {
134        (
135            Self::unix_to_gregorian_ticks(self.seconds, self.subsec_nanos),
136            (self.counter as u16) & 0x3FFF,
137        )
138    }
139
140    // NOTE: This method is not public; the usable counter bits are lost in a version 7 UUID
141    // so can't be reliably recovered.
142    #[cfg(feature = "v7")]
143    pub(crate) const fn counter(&self) -> (u128, u8) {
144        (self.counter, self.usable_counter_bits)
145    }
146
147    /// Get the value of the timestamp as a Unix timestamp, as used in version 7 UUIDs.
148    pub const fn to_unix(&self) -> (u64, u32) {
149        (self.seconds, self.subsec_nanos)
150    }
151
152    const fn unix_to_gregorian_ticks(seconds: u64, nanos: u32) -> u64 {
153        UUID_TICKS_BETWEEN_EPOCHS
154            .wrapping_add(seconds.wrapping_mul(10_000_000))
155            .wrapping_add(nanos as u64 / 100)
156    }
157
158    const fn gregorian_to_unix(ticks: u64) -> (u64, u32) {
159        (
160            ticks.wrapping_sub(UUID_TICKS_BETWEEN_EPOCHS) / 10_000_000,
161            (ticks.wrapping_sub(UUID_TICKS_BETWEEN_EPOCHS) % 10_000_000) as u32 * 100,
162        )
163    }
164}
165
166#[doc(hidden)]
167impl Timestamp {
168    #[deprecated(
169        since = "1.10.0",
170        note = "use `Timestamp::from_gregorian(ticks, counter)`"
171    )]
172    pub const fn from_rfc4122(ticks: u64, counter: u16) -> Self {
173        Timestamp::from_gregorian(ticks, counter)
174    }
175
176    #[deprecated(since = "1.10.0", note = "use `Timestamp::to_gregorian()`")]
177    pub const fn to_rfc4122(&self) -> (u64, u16) {
178        self.to_gregorian()
179    }
180
181    #[deprecated(
182        since = "1.2.0",
183        note = "`Timestamp::to_unix_nanos()` is deprecated and will be removed: use `Timestamp::to_unix()`"
184    )]
185    pub const fn to_unix_nanos(&self) -> u32 {
186        panic!("`Timestamp::to_unix_nanos()` is deprecated and will be removed: use `Timestamp::to_unix()`")
187    }
188}
189
190#[cfg(feature = "std")]
191impl TryFrom<std::time::SystemTime> for Timestamp {
192    type Error = crate::Error;
193
194    /// Perform the conversion.
195    ///
196    /// This method will fail if the system time is earlier than the Unix Epoch.
197    /// On some platforms it may panic instead.
198    fn try_from(st: std::time::SystemTime) -> Result<Self, Self::Error> {
199        let dur = st.duration_since(std::time::UNIX_EPOCH).map_err(|_| {
200            crate::Error(crate::error::ErrorKind::InvalidSystemTime(
201                "unable to convert the system tie into a Unix timestamp",
202            ))
203        })?;
204
205        Ok(Self::from_unix_time(
206            dur.as_secs(),
207            dur.subsec_nanos(),
208            0,
209            0,
210        ))
211    }
212}
213
214#[cfg(feature = "std")]
215impl From<Timestamp> for std::time::SystemTime {
216    fn from(ts: Timestamp) -> Self {
217        let (seconds, subsec_nanos) = ts.to_unix();
218
219        Self::UNIX_EPOCH + std::time::Duration::new(seconds, subsec_nanos)
220    }
221}
222
223pub(crate) const fn encode_gregorian_timestamp(
224    ticks: u64,
225    counter: u16,
226    node_id: &[u8; 6],
227) -> Uuid {
228    let time_low = (ticks & 0xFFFF_FFFF) as u32;
229    let time_mid = ((ticks >> 32) & 0xFFFF) as u16;
230    let time_high_and_version = (((ticks >> 48) & 0x0FFF) as u16) | (1 << 12);
231
232    let mut d4 = [0; 8];
233
234    d4[0] = (((counter & 0x3F00) >> 8) as u8) | 0x80;
235    d4[1] = (counter & 0xFF) as u8;
236    d4[2] = node_id[0];
237    d4[3] = node_id[1];
238    d4[4] = node_id[2];
239    d4[5] = node_id[3];
240    d4[6] = node_id[4];
241    d4[7] = node_id[5];
242
243    Uuid::from_fields(time_low, time_mid, time_high_and_version, &d4)
244}
245
246pub(crate) const fn decode_gregorian_timestamp(uuid: &Uuid) -> (u64, u16) {
247    let bytes = uuid.as_bytes();
248
249    let ticks: u64 = ((bytes[6] & 0x0F) as u64) << 56
250        | (bytes[7] as u64) << 48
251        | (bytes[4] as u64) << 40
252        | (bytes[5] as u64) << 32
253        | (bytes[0] as u64) << 24
254        | (bytes[1] as u64) << 16
255        | (bytes[2] as u64) << 8
256        | (bytes[3] as u64);
257
258    let counter: u16 = ((bytes[8] & 0x3F) as u16) << 8 | (bytes[9] as u16);
259
260    (ticks, counter)
261}
262
263pub(crate) const fn encode_sorted_gregorian_timestamp(
264    ticks: u64,
265    counter: u16,
266    node_id: &[u8; 6],
267) -> Uuid {
268    let time_high = ((ticks >> 28) & 0xFFFF_FFFF) as u32;
269    let time_mid = ((ticks >> 12) & 0xFFFF) as u16;
270    let time_low_and_version = ((ticks & 0x0FFF) as u16) | (0x6 << 12);
271
272    let mut d4 = [0; 8];
273
274    d4[0] = (((counter & 0x3F00) >> 8) as u8) | 0x80;
275    d4[1] = (counter & 0xFF) as u8;
276    d4[2] = node_id[0];
277    d4[3] = node_id[1];
278    d4[4] = node_id[2];
279    d4[5] = node_id[3];
280    d4[6] = node_id[4];
281    d4[7] = node_id[5];
282
283    Uuid::from_fields(time_high, time_mid, time_low_and_version, &d4)
284}
285
286pub(crate) const fn decode_sorted_gregorian_timestamp(uuid: &Uuid) -> (u64, u16) {
287    let bytes = uuid.as_bytes();
288
289    let ticks: u64 = ((bytes[0]) as u64) << 52
290        | (bytes[1] as u64) << 44
291        | (bytes[2] as u64) << 36
292        | (bytes[3] as u64) << 28
293        | (bytes[4] as u64) << 20
294        | (bytes[5] as u64) << 12
295        | ((bytes[6] & 0xF) as u64) << 8
296        | (bytes[7] as u64);
297
298    let counter: u16 = ((bytes[8] & 0x3F) as u16) << 8 | (bytes[9] as u16);
299
300    (ticks, counter)
301}
302
303pub(crate) const fn encode_unix_timestamp_millis(
304    millis: u64,
305    counter_random_bytes: &[u8; 10],
306) -> Uuid {
307    let millis_high = ((millis >> 16) & 0xFFFF_FFFF) as u32;
308    let millis_low = (millis & 0xFFFF) as u16;
309
310    let counter_random_version = (counter_random_bytes[1] as u16
311        | ((counter_random_bytes[0] as u16) << 8) & 0x0FFF)
312        | (0x7 << 12);
313
314    let mut d4 = [0; 8];
315
316    d4[0] = (counter_random_bytes[2] & 0x3F) | 0x80;
317    d4[1] = counter_random_bytes[3];
318    d4[2] = counter_random_bytes[4];
319    d4[3] = counter_random_bytes[5];
320    d4[4] = counter_random_bytes[6];
321    d4[5] = counter_random_bytes[7];
322    d4[6] = counter_random_bytes[8];
323    d4[7] = counter_random_bytes[9];
324
325    Uuid::from_fields(millis_high, millis_low, counter_random_version, &d4)
326}
327
328pub(crate) const fn decode_unix_timestamp_millis(uuid: &Uuid) -> u64 {
329    let bytes = uuid.as_bytes();
330
331    let millis: u64 = (bytes[0] as u64) << 40
332        | (bytes[1] as u64) << 32
333        | (bytes[2] as u64) << 24
334        | (bytes[3] as u64) << 16
335        | (bytes[4] as u64) << 8
336        | (bytes[5] as u64);
337
338    millis
339}
340
341#[cfg(all(
342    feature = "std",
343    feature = "js",
344    all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none"))
345))]
346fn now() -> (u64, u32) {
347    use wasm_bindgen::prelude::*;
348
349    #[wasm_bindgen]
350    extern "C" {
351        // NOTE: This signature works around https://bugzilla.mozilla.org/show_bug.cgi?id=1787770
352        #[wasm_bindgen(js_namespace = Date, catch)]
353        fn now() -> Result<f64, JsValue>;
354    }
355
356    let now = now().unwrap_throw();
357
358    let secs = (now / 1_000.0) as u64;
359    let nanos = ((now % 1_000.0) * 1_000_000.0) as u32;
360
361    (secs, nanos)
362}
363
364#[cfg(all(
365    feature = "std",
366    not(miri),
367    any(
368        not(feature = "js"),
369        not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))
370    )
371))]
372fn now() -> (u64, u32) {
373    let dur = std::time::SystemTime::UNIX_EPOCH.elapsed().expect(
374        "Getting elapsed time since UNIX_EPOCH. If this fails, we've somehow violated causality",
375    );
376
377    (dur.as_secs(), dur.subsec_nanos())
378}
379
380#[cfg(all(feature = "std", miri))]
381fn now() -> (u64, u32) {
382    use std::{sync::Mutex, time::Duration};
383
384    static TS: Mutex<u64> = Mutex::new(0);
385
386    let ts = Duration::from_nanos({
387        let mut ts = TS.lock().unwrap();
388        *ts += 1;
389        *ts
390    });
391
392    (ts.as_secs(), ts.subsec_nanos())
393}
394
395/// A counter that can be used by versions 1 and 6 UUIDs to support
396/// the uniqueness of timestamps.
397///
398/// # References
399///
400/// * [UUID Version 1 in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-5.1)
401/// * [UUID Version 6 in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-5.6)
402/// * [UUID Generator States in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-6.3)
403pub trait ClockSequence {
404    /// The type of sequence returned by this counter.
405    type Output;
406
407    /// Get the next value in the sequence to feed into a timestamp.
408    ///
409    /// This method will be called each time a [`Timestamp`] is constructed.
410    ///
411    /// Any bits beyond [`ClockSequence::usable_bits`] in the output must be unset.
412    fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output;
413
414    /// Get the next value in the sequence, potentially also adjusting the timestamp.
415    ///
416    /// This method should be preferred over `generate_sequence`.
417    ///
418    /// Any bits beyond [`ClockSequence::usable_bits`] in the output must be unset.
419    fn generate_timestamp_sequence(
420        &self,
421        seconds: u64,
422        subsec_nanos: u32,
423    ) -> (Self::Output, u64, u32) {
424        (
425            self.generate_sequence(seconds, subsec_nanos),
426            seconds,
427            subsec_nanos,
428        )
429    }
430
431    /// The number of usable bits from the least significant bit in the result of [`ClockSequence::generate_sequence`]
432    /// or [`ClockSequence::generate_timestamp_sequence`].
433    ///
434    /// The number of usable bits must not exceed 128.
435    ///
436    /// The number of usable bits is not expected to change between calls. An implementation of `ClockSequence` should
437    /// always return the same value from this method.
438    fn usable_bits(&self) -> usize
439    where
440        Self::Output: Sized,
441    {
442        cmp::min(128, core::mem::size_of::<Self::Output>())
443    }
444}
445
446impl<T: ClockSequence + ?Sized> ClockSequence for &T {
447    type Output = T::Output;
448
449    fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output {
450        (**self).generate_sequence(seconds, subsec_nanos)
451    }
452
453    fn generate_timestamp_sequence(
454        &self,
455        seconds: u64,
456        subsec_nanos: u32,
457    ) -> (Self::Output, u64, u32) {
458        (**self).generate_timestamp_sequence(seconds, subsec_nanos)
459    }
460
461    fn usable_bits(&self) -> usize
462    where
463        Self::Output: Sized,
464    {
465        (**self).usable_bits()
466    }
467}
468
469/// Default implementations for the [`ClockSequence`] trait.
470pub mod context {
471    use super::ClockSequence;
472
473    #[cfg(any(feature = "v1", feature = "v6"))]
474    mod v1_support {
475        use super::*;
476
477        use atomic::{Atomic, Ordering};
478
479        #[cfg(all(feature = "std", feature = "rng"))]
480        static CONTEXT: Context = Context {
481            count: Atomic::new(0),
482        };
483
484        #[cfg(all(feature = "std", feature = "rng"))]
485        static CONTEXT_INITIALIZED: Atomic<bool> = Atomic::new(false);
486
487        #[cfg(all(feature = "std", feature = "rng"))]
488        pub(crate) fn shared_context() -> &'static Context {
489            // If the context is in its initial state then assign it to a random value
490            // It doesn't matter if multiple threads observe `false` here and initialize the context
491            if CONTEXT_INITIALIZED
492                .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
493                .is_ok()
494            {
495                CONTEXT.count.store(crate::rng::u16(), Ordering::Release);
496            }
497
498            &CONTEXT
499        }
500
501        /// A thread-safe, wrapping counter that produces 14-bit values.
502        ///
503        /// This type works by:
504        ///
505        /// 1. Atomically incrementing the counter value for each timestamp.
506        /// 2. Wrapping the counter back to zero if it overflows its 14-bit storage.
507        ///
508        /// This type should be used when constructing versions 1 and 6 UUIDs.
509        ///
510        /// This type should not be used when constructing version 7 UUIDs. When used to
511        /// construct a version 7 UUID, the 14-bit counter will be padded with random data.
512        /// Counter overflows are more likely with a 14-bit counter than they are with a
513        /// 42-bit counter when working at millisecond precision. This type doesn't attempt
514        /// to adjust the timestamp on overflow.
515        #[derive(Debug)]
516        pub struct Context {
517            count: Atomic<u16>,
518        }
519
520        impl Context {
521            /// Construct a new context that's initialized with the given value.
522            ///
523            /// The starting value should be a random number, so that UUIDs from
524            /// different systems with the same timestamps are less likely to collide.
525            /// When the `rng` feature is enabled, prefer the [`Context::new_random`] method.
526            pub const fn new(count: u16) -> Self {
527                Self {
528                    count: Atomic::<u16>::new(count),
529                }
530            }
531
532            /// Construct a new context that's initialized with a random value.
533            #[cfg(feature = "rng")]
534            pub fn new_random() -> Self {
535                Self {
536                    count: Atomic::<u16>::new(crate::rng::u16()),
537                }
538            }
539        }
540
541        impl ClockSequence for Context {
542            type Output = u16;
543
544            fn generate_sequence(&self, _seconds: u64, _nanos: u32) -> Self::Output {
545                // RFC 9562 reserves 2 bits of the clock sequence so the actual
546                // maximum value is smaller than `u16::MAX`. Since we unconditionally
547                // increment the clock sequence we want to wrap once it becomes larger
548                // than what we can represent in a "u14". Otherwise there'd be patches
549                // where the clock sequence doesn't change regardless of the timestamp
550                self.count.fetch_add(1, Ordering::AcqRel) & (u16::MAX >> 2)
551            }
552
553            fn usable_bits(&self) -> usize {
554                14
555            }
556        }
557
558        #[cfg(test)]
559        mod tests {
560            use crate::Timestamp;
561
562            use super::*;
563
564            #[test]
565            fn context() {
566                let seconds = 1_496_854_535;
567                let subsec_nanos = 812_946_000;
568
569                let context = Context::new(u16::MAX >> 2);
570
571                let ts = Timestamp::from_unix(&context, seconds, subsec_nanos);
572                assert_eq!(16383, ts.counter);
573                assert_eq!(14, ts.usable_counter_bits);
574
575                let seconds = 1_496_854_536;
576
577                let ts = Timestamp::from_unix(&context, seconds, subsec_nanos);
578                assert_eq!(0, ts.counter);
579
580                let seconds = 1_496_854_535;
581
582                let ts = Timestamp::from_unix(&context, seconds, subsec_nanos);
583                assert_eq!(1, ts.counter);
584            }
585
586            #[test]
587            fn context_overflow() {
588                let seconds = u64::MAX;
589                let subsec_nanos = u32::MAX;
590
591                let context = Context::new(u16::MAX);
592
593                // Ensure we don't panic
594                Timestamp::from_unix(&context, seconds, subsec_nanos);
595            }
596        }
597    }
598
599    #[cfg(any(feature = "v1", feature = "v6"))]
600    pub use v1_support::*;
601
602    #[cfg(feature = "std")]
603    mod std_support {
604        use super::*;
605
606        use core::panic::{AssertUnwindSafe, RefUnwindSafe};
607        use std::{sync::Mutex, thread::LocalKey};
608
609        /// A wrapper for a context that uses thread-local storage.
610        pub struct ThreadLocalContext<C: 'static>(&'static LocalKey<C>);
611
612        impl<C> std::fmt::Debug for ThreadLocalContext<C> {
613            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
614                f.debug_struct("ThreadLocalContext").finish_non_exhaustive()
615            }
616        }
617
618        impl<C: 'static> ThreadLocalContext<C> {
619            /// Wrap a thread-local container with a context.
620            pub const fn new(local_key: &'static LocalKey<C>) -> Self {
621                ThreadLocalContext(local_key)
622            }
623        }
624
625        impl<C: ClockSequence + 'static> ClockSequence for ThreadLocalContext<C> {
626            type Output = C::Output;
627
628            fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output {
629                self.0
630                    .with(|ctxt| ctxt.generate_sequence(seconds, subsec_nanos))
631            }
632
633            fn generate_timestamp_sequence(
634                &self,
635                seconds: u64,
636                subsec_nanos: u32,
637            ) -> (Self::Output, u64, u32) {
638                self.0
639                    .with(|ctxt| ctxt.generate_timestamp_sequence(seconds, subsec_nanos))
640            }
641
642            fn usable_bits(&self) -> usize {
643                self.0.with(|ctxt| ctxt.usable_bits())
644            }
645        }
646
647        impl<C: ClockSequence> ClockSequence for AssertUnwindSafe<C> {
648            type Output = C::Output;
649
650            fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output {
651                self.0.generate_sequence(seconds, subsec_nanos)
652            }
653
654            fn generate_timestamp_sequence(
655                &self,
656                seconds: u64,
657                subsec_nanos: u32,
658            ) -> (Self::Output, u64, u32) {
659                self.0.generate_timestamp_sequence(seconds, subsec_nanos)
660            }
661
662            fn usable_bits(&self) -> usize
663            where
664                Self::Output: Sized,
665            {
666                self.0.usable_bits()
667            }
668        }
669
670        impl<C: ClockSequence + RefUnwindSafe> ClockSequence for Mutex<C> {
671            type Output = C::Output;
672
673            fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output {
674                self.lock()
675                    .unwrap_or_else(|err| err.into_inner())
676                    .generate_sequence(seconds, subsec_nanos)
677            }
678
679            fn generate_timestamp_sequence(
680                &self,
681                seconds: u64,
682                subsec_nanos: u32,
683            ) -> (Self::Output, u64, u32) {
684                self.lock()
685                    .unwrap_or_else(|err| err.into_inner())
686                    .generate_timestamp_sequence(seconds, subsec_nanos)
687            }
688
689            fn usable_bits(&self) -> usize
690            where
691                Self::Output: Sized,
692            {
693                self.lock()
694                    .unwrap_or_else(|err| err.into_inner())
695                    .usable_bits()
696            }
697        }
698    }
699
700    #[cfg(feature = "std")]
701    pub use std_support::*;
702
703    #[cfg(feature = "v7")]
704    mod v7_support {
705        use super::*;
706
707        use core::{cell::Cell, cmp, panic::RefUnwindSafe};
708
709        #[cfg(feature = "std")]
710        static CONTEXT_V7: SharedContextV7 =
711            SharedContextV7(std::sync::Mutex::new(ContextV7::new()));
712
713        #[cfg(feature = "std")]
714        pub(crate) fn shared_context_v7() -> &'static SharedContextV7 {
715            &CONTEXT_V7
716        }
717
718        const USABLE_BITS: usize = 42;
719
720        // Leave the most significant bit unset
721        // This guarantees the counter has at least 2,199,023,255,552
722        // values before it will overflow, which is exceptionally unlikely
723        // even in the worst case
724        const RESEED_MASK: u64 = u64::MAX >> 23;
725        const MAX_COUNTER: u64 = u64::MAX >> 22;
726
727        /// An unsynchronized, reseeding counter that produces 42-bit values.
728        ///
729        /// This type works by:
730        ///
731        /// 1. Reseeding the counter each millisecond with a random 41-bit value. The 42nd bit
732        ///    is left unset so the counter can safely increment over the millisecond.
733        /// 2. Wrapping the counter back to zero if it overflows its 42-bit storage and adding a
734        ///    millisecond to the timestamp.
735        ///
736        /// The counter can use additional sub-millisecond precision from the timestamp to better
737        /// synchronize UUID sorting in distributed systems. In these cases, the additional precision
738        /// is masked into the left-most 12 bits of the counter. The counter is still reseeded on
739        /// each new millisecond, and incremented within the millisecond. This behavior may change
740        /// in the future. The only guarantee is monotonicity.
741        ///
742        /// This type can be used when constructing version 7 UUIDs. When used to construct a
743        /// version 7 UUID, the 42-bit counter will be padded with random data. This type can
744        /// be used to maintain ordering of UUIDs within the same millisecond.
745        ///
746        /// This type should not be used when constructing version 1 or version 6 UUIDs.
747        /// When used to construct a version 1 or version 6 UUID, only the 14 least significant
748        /// bits of the counter will be used.
749        #[derive(Debug)]
750        pub struct ContextV7 {
751            timestamp: Cell<ReseedingTimestamp>,
752            counter: Cell<Counter>,
753            adjust: Adjust,
754            precision: Precision,
755        }
756
757        impl RefUnwindSafe for ContextV7 {}
758
759        impl ContextV7 {
760            /// Construct a new context that will reseed its counter on the first
761            /// non-zero timestamp it receives.
762            pub const fn new() -> Self {
763                ContextV7 {
764                    timestamp: Cell::new(ReseedingTimestamp {
765                        last_seed: 0,
766                        seconds: 0,
767                        subsec_nanos: 0,
768                    }),
769                    counter: Cell::new(Counter { value: 0 }),
770                    adjust: Adjust { by_ns: 0 },
771                    precision: Precision {
772                        bits: 0,
773                        mask: 0,
774                        factor: 0,
775                        shift: 0,
776                    },
777                }
778            }
779
780            /// Specify an amount to shift timestamps by to obfuscate their actual generation time.
781            pub fn with_adjust_by_millis(mut self, millis: u32) -> Self {
782                self.adjust = Adjust::by_millis(millis);
783                self
784            }
785
786            /// Use the leftmost 12 bits of the counter for additional timestamp precision.
787            ///
788            /// This method can provide better sorting for distributed applications that generate frequent UUIDs
789            /// by trading a small amount of entropy for better counter synchronization. Note that the counter
790            /// will still be reseeded on millisecond boundaries, even though some of its storage will be
791            /// dedicated to the timestamp.
792            pub fn with_additional_precision(mut self) -> Self {
793                self.precision = Precision::new(12);
794                self
795            }
796        }
797
798        impl ClockSequence for ContextV7 {
799            type Output = u64;
800
801            fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output {
802                self.generate_timestamp_sequence(seconds, subsec_nanos).0
803            }
804
805            fn generate_timestamp_sequence(
806                &self,
807                seconds: u64,
808                subsec_nanos: u32,
809            ) -> (Self::Output, u64, u32) {
810                let (seconds, subsec_nanos) = self.adjust.apply(seconds, subsec_nanos);
811
812                let mut counter;
813                let (mut timestamp, should_reseed) =
814                    self.timestamp.get().advance(seconds, subsec_nanos);
815
816                if should_reseed {
817                    // If the observed system time has shifted forwards then regenerate the counter
818                    counter = Counter::reseed(&self.precision, &timestamp);
819                } else {
820                    // If the observed system time has not shifted forwards then increment the counter
821
822                    // If the incoming timestamp is earlier than the last observed one then
823                    // use it instead. This may happen if the system clock jitters, or if the counter
824                    // has wrapped and the timestamp is artificially incremented
825
826                    counter = self.counter.get().increment(&self.precision, &timestamp);
827
828                    // Unlikely: If the counter has overflowed its 42-bit storage then wrap it
829                    // and increment the timestamp. Until the observed system time shifts past
830                    // this incremented value, all timestamps will use it to maintain monotonicity
831                    if counter.has_overflowed() {
832                        // Increment the timestamp by 1 milli and reseed the counter
833                        timestamp = timestamp.increment();
834                        counter = Counter::reseed(&self.precision, &timestamp);
835                    }
836                };
837
838                self.timestamp.set(timestamp);
839                self.counter.set(counter);
840
841                (counter.value, timestamp.seconds, timestamp.subsec_nanos)
842            }
843
844            fn usable_bits(&self) -> usize {
845                USABLE_BITS
846            }
847        }
848
849        #[derive(Debug)]
850        struct Adjust {
851            by_ns: u128,
852        }
853
854        impl Adjust {
855            #[inline]
856            fn by_millis(millis: u32) -> Self {
857                Adjust {
858                    by_ns: (millis as u128).saturating_mul(1_000_000),
859                }
860            }
861
862            #[inline]
863            fn apply(&self, seconds: u64, subsec_nanos: u32) -> (u64, u32) {
864                if self.by_ns == 0 {
865                    // No shift applied
866                    return (seconds, subsec_nanos);
867                }
868
869                let ts = (seconds as u128)
870                    .saturating_mul(1_000_000_000)
871                    .saturating_add(subsec_nanos as u128)
872                    .saturating_add(self.by_ns);
873
874                ((ts / 1_000_000_000) as u64, (ts % 1_000_000_000) as u32)
875            }
876        }
877
878        #[derive(Debug, Default, Clone, Copy)]
879        struct ReseedingTimestamp {
880            last_seed: u64,
881            seconds: u64,
882            subsec_nanos: u32,
883        }
884
885        impl ReseedingTimestamp {
886            #[inline]
887            fn advance(&self, seconds: u64, subsec_nanos: u32) -> (Self, bool) {
888                let incoming = ReseedingTimestamp::from_ts(seconds, subsec_nanos);
889
890                if incoming.last_seed > self.last_seed {
891                    // The incoming value is part of a new millisecond
892                    (incoming, true)
893                } else {
894                    // The incoming value is part of the same or an earlier millisecond
895                    // We may still have advanced the subsecond portion, so use the larger value
896                    let mut value = *self;
897                    value.subsec_nanos = cmp::max(self.subsec_nanos, subsec_nanos);
898
899                    (value, false)
900                }
901            }
902
903            #[inline]
904            fn from_ts(seconds: u64, subsec_nanos: u32) -> Self {
905                // Reseed when the millisecond advances
906                let last_seed = seconds
907                    .saturating_mul(1_000)
908                    .saturating_add((subsec_nanos / 1_000_000) as u64);
909
910                ReseedingTimestamp {
911                    last_seed,
912                    seconds,
913                    subsec_nanos,
914                }
915            }
916
917            #[inline]
918            fn increment(&self) -> Self {
919                let (seconds, subsec_nanos) =
920                    Adjust::by_millis(1).apply(self.seconds, self.subsec_nanos);
921
922                ReseedingTimestamp::from_ts(seconds, subsec_nanos)
923            }
924
925            #[inline]
926            fn submilli_nanos(&self) -> u32 {
927                self.subsec_nanos % 1_000_000
928            }
929        }
930
931        #[derive(Debug)]
932        struct Precision {
933            bits: usize,
934            factor: u64,
935            mask: u64,
936            shift: u64,
937        }
938
939        impl Precision {
940            fn new(bits: usize) -> Self {
941                // The mask and shift are used to paste the sub-millisecond precision
942                // into the most significant bits of the counter
943                let mask = u64::MAX >> (64 - USABLE_BITS + bits);
944                let shift = (USABLE_BITS - bits) as u64;
945
946                // The factor reduces the size of the sub-millisecond precision to
947                // fit into the specified number of bits
948                let factor = (999_999 / u64::pow(2, bits as u32)) + 1;
949
950                Precision {
951                    bits,
952                    factor,
953                    mask,
954                    shift,
955                }
956            }
957
958            #[inline]
959            fn apply(&self, value: u64, timestamp: &ReseedingTimestamp) -> u64 {
960                if self.bits == 0 {
961                    // No additional precision is being used
962                    return value;
963                }
964
965                let additional = timestamp.submilli_nanos() as u64 / self.factor;
966
967                (value & self.mask) | (additional << self.shift)
968            }
969        }
970
971        #[derive(Debug, Clone, Copy)]
972        struct Counter {
973            value: u64,
974        }
975
976        impl Counter {
977            #[inline]
978            fn reseed(precision: &Precision, timestamp: &ReseedingTimestamp) -> Self {
979                Counter {
980                    value: precision.apply(crate::rng::u64() & RESEED_MASK, timestamp),
981                }
982            }
983
984            #[inline]
985            fn increment(&self, precision: &Precision, timestamp: &ReseedingTimestamp) -> Self {
986                let mut counter = Counter {
987                    value: precision.apply(self.value, timestamp),
988                };
989
990                // We unconditionally increment the counter even though the precision
991                // may have set higher bits already. This could technically be avoided,
992                // but the higher bits are a coarse approximation so we just avoid the
993                // `if` branch and increment it either way
994
995                // Guaranteed to never overflow u64
996                counter.value += 1;
997
998                counter
999            }
1000
1001            #[inline]
1002            fn has_overflowed(&self) -> bool {
1003                self.value > MAX_COUNTER
1004            }
1005        }
1006
1007        #[cfg(feature = "std")]
1008        pub(crate) struct SharedContextV7(std::sync::Mutex<ContextV7>);
1009
1010        #[cfg(feature = "std")]
1011        impl ClockSequence for SharedContextV7 {
1012            type Output = u64;
1013
1014            fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output {
1015                self.0.generate_sequence(seconds, subsec_nanos)
1016            }
1017
1018            fn generate_timestamp_sequence(
1019                &self,
1020                seconds: u64,
1021                subsec_nanos: u32,
1022            ) -> (Self::Output, u64, u32) {
1023                self.0.generate_timestamp_sequence(seconds, subsec_nanos)
1024            }
1025
1026            fn usable_bits(&self) -> usize
1027            where
1028                Self::Output: Sized,
1029            {
1030                USABLE_BITS
1031            }
1032        }
1033
1034        #[cfg(test)]
1035        mod tests {
1036            use core::time::Duration;
1037
1038            use super::*;
1039
1040            use crate::{Timestamp, Uuid};
1041
1042            #[test]
1043            fn context() {
1044                let seconds = 1_496_854_535;
1045                let subsec_nanos = 812_946_000;
1046
1047                let context = ContextV7::new();
1048
1049                let ts1 = Timestamp::from_unix(&context, seconds, subsec_nanos);
1050                assert_eq!(42, ts1.usable_counter_bits);
1051
1052                // Backwards second
1053                let seconds = 1_496_854_534;
1054
1055                let ts2 = Timestamp::from_unix(&context, seconds, subsec_nanos);
1056
1057                // The backwards time should be ignored
1058                // The counter should still increment
1059                assert_eq!(ts1.seconds, ts2.seconds);
1060                assert_eq!(ts1.subsec_nanos, ts2.subsec_nanos);
1061                assert_eq!(ts1.counter + 1, ts2.counter);
1062
1063                // Forwards second
1064                let seconds = 1_496_854_536;
1065
1066                let ts3 = Timestamp::from_unix(&context, seconds, subsec_nanos);
1067
1068                // The counter should have reseeded
1069                assert_ne!(ts2.counter + 1, ts3.counter);
1070                assert_ne!(0, ts3.counter);
1071            }
1072
1073            #[test]
1074            fn context_wrap() {
1075                let seconds = 1_496_854_535u64;
1076                let subsec_nanos = 812_946_000u32;
1077
1078                // This context will wrap
1079                let context = ContextV7 {
1080                    timestamp: Cell::new(ReseedingTimestamp::from_ts(seconds, subsec_nanos)),
1081                    adjust: Adjust::by_millis(0),
1082                    precision: Precision {
1083                        bits: 0,
1084                        mask: 0,
1085                        factor: 0,
1086                        shift: 0,
1087                    },
1088                    counter: Cell::new(Counter {
1089                        value: u64::MAX >> 22,
1090                    }),
1091                };
1092
1093                let ts = Timestamp::from_unix(&context, seconds, subsec_nanos);
1094
1095                // The timestamp should be incremented by 1ms
1096                let expected_ts = Duration::new(seconds, subsec_nanos) + Duration::from_millis(1);
1097                assert_eq!(expected_ts.as_secs(), ts.seconds);
1098                assert_eq!(expected_ts.subsec_nanos(), ts.subsec_nanos);
1099
1100                // The counter should have reseeded
1101                assert!(ts.counter < (u64::MAX >> 22) as u128);
1102                assert_ne!(0, ts.counter);
1103            }
1104
1105            #[test]
1106            fn context_shift() {
1107                let seconds = 1_496_854_535;
1108                let subsec_nanos = 812_946_000;
1109
1110                let context = ContextV7::new().with_adjust_by_millis(1);
1111
1112                let ts = Timestamp::from_unix(&context, seconds, subsec_nanos);
1113
1114                assert_eq!((1_496_854_535, 813_946_000), ts.to_unix());
1115            }
1116
1117            #[test]
1118            fn context_additional_precision() {
1119                let seconds = 1_496_854_535;
1120                let subsec_nanos = 812_946_000;
1121
1122                let context = ContextV7::new().with_additional_precision();
1123
1124                let ts1 = Timestamp::from_unix(&context, seconds, subsec_nanos);
1125
1126                // NOTE: Future changes in rounding may change this value slightly
1127                assert_eq!(3861, ts1.counter >> 30);
1128
1129                assert!(ts1.counter < (u64::MAX >> 22) as u128);
1130
1131                // Generate another timestamp; it should continue to sort
1132                let ts2 = Timestamp::from_unix(&context, seconds, subsec_nanos);
1133
1134                assert!(Uuid::new_v7(ts2) > Uuid::new_v7(ts1));
1135
1136                // Generate another timestamp with an extra nanosecond
1137                let subsec_nanos = subsec_nanos + 1;
1138
1139                let ts3 = Timestamp::from_unix(&context, seconds, subsec_nanos);
1140
1141                assert!(Uuid::new_v7(ts3) > Uuid::new_v7(ts2));
1142            }
1143
1144            #[test]
1145            fn context_overflow() {
1146                let seconds = u64::MAX;
1147                let subsec_nanos = u32::MAX;
1148
1149                // Ensure we don't panic
1150                for context in [
1151                    ContextV7::new(),
1152                    ContextV7::new().with_additional_precision(),
1153                    ContextV7::new().with_adjust_by_millis(u32::MAX),
1154                ] {
1155                    Timestamp::from_unix(&context, seconds, subsec_nanos);
1156                }
1157            }
1158        }
1159    }
1160
1161    #[cfg(feature = "v7")]
1162    pub use v7_support::*;
1163
1164    /// An empty counter that will always return the value `0`.
1165    ///
1166    /// This type can be used when constructing version 7 UUIDs. When used to
1167    /// construct a version 7 UUID, the entire counter segment of the UUID will be
1168    /// filled with a random value. This type does not maintain ordering of UUIDs
1169    /// within a millisecond but is efficient.
1170    ///
1171    /// This type should not be used when constructing version 1 or version 6 UUIDs.
1172    /// When used to construct a version 1 or version 6 UUID, the counter
1173    /// segment will remain zero.
1174    #[derive(Debug, Clone, Copy, Default)]
1175    pub struct NoContext;
1176
1177    impl ClockSequence for NoContext {
1178        type Output = u16;
1179
1180        fn generate_sequence(&self, _seconds: u64, _nanos: u32) -> Self::Output {
1181            0
1182        }
1183
1184        fn usable_bits(&self) -> usize {
1185            0
1186        }
1187    }
1188}
1189
1190#[cfg(all(test, any(feature = "v1", feature = "v6")))]
1191mod tests {
1192    use super::*;
1193
1194    #[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))]
1195    use wasm_bindgen_test::*;
1196
1197    #[test]
1198    #[cfg_attr(
1199        all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")),
1200        wasm_bindgen_test
1201    )]
1202    fn gregorian_unix_does_not_panic() {
1203        // Ensure timestamp conversions never panic
1204        Timestamp::unix_to_gregorian_ticks(u64::MAX, 0);
1205        Timestamp::unix_to_gregorian_ticks(0, u32::MAX);
1206        Timestamp::unix_to_gregorian_ticks(u64::MAX, u32::MAX);
1207
1208        Timestamp::gregorian_to_unix(u64::MAX);
1209    }
1210
1211    #[test]
1212    #[cfg_attr(
1213        all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")),
1214        wasm_bindgen_test
1215    )]
1216    fn to_gregorian_truncates_to_usable_bits() {
1217        let ts = Timestamp::from_gregorian(123, u16::MAX);
1218
1219        assert_eq!((123, u16::MAX >> 2), ts.to_gregorian());
1220    }
1221}
1222
1223/// Tests for conversion between `std::time::SystemTime` and `Timestamp`.
1224#[cfg(all(test, feature = "std", not(miri)))]
1225mod test_conversion {
1226    use std::time::{Duration, SystemTime};
1227
1228    use super::Timestamp;
1229
1230    // Components of an arbitrary timestamp with non-zero nanoseconds.
1231    const KNOWN_SECONDS: u64 = 1_501_520_400;
1232    const KNOWN_NANOS: u32 = 1_000;
1233
1234    fn known_system_time() -> SystemTime {
1235        SystemTime::UNIX_EPOCH
1236            .checked_add(Duration::new(KNOWN_SECONDS, KNOWN_NANOS))
1237            .unwrap()
1238    }
1239
1240    fn known_timestamp() -> Timestamp {
1241        Timestamp::from_unix_time(KNOWN_SECONDS, KNOWN_NANOS, 0, 0)
1242    }
1243
1244    #[test]
1245    fn to_system_time() {
1246        let st: SystemTime = known_timestamp().into();
1247
1248        assert_eq!(known_system_time(), st);
1249    }
1250
1251    #[test]
1252    fn from_system_time() {
1253        let ts: Timestamp = known_system_time().try_into().unwrap();
1254
1255        assert_eq!(known_timestamp(), ts);
1256    }
1257
1258    #[test]
1259    fn from_system_time_before_epoch() {
1260        let before_epoch = match SystemTime::UNIX_EPOCH.checked_sub(Duration::from_nanos(1_000)) {
1261            Some(st) => st,
1262            None => return,
1263        };
1264
1265        Timestamp::try_from(before_epoch)
1266            .expect_err("Timestamp should not be created from before epoch");
1267    }
1268}