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