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(since = "1.11.0", note = "use `Timestamp::from_gregorian(ticks, counter)`")]
169    pub const fn from_rfc4122(ticks: u64, counter: u16) -> Self {
170        Timestamp::from_gregorian(ticks, counter)
171    }
172
173    #[deprecated(since = "1.11.0", note = "use `Timestamp::to_gregorian()`")]
174    pub const fn to_rfc4122(&self) -> (u64, u16) {
175        self.to_gregorian()
176    }
177
178    #[deprecated(since = "1.2.0", note = "`Timestamp::to_unix_nanos()` is deprecated and will be removed: use `Timestamp::to_unix()`")]
179    pub const fn to_unix_nanos(&self) -> u32 {
180        panic!("`Timestamp::to_unix_nanos()` is deprecated and will be removed: use `Timestamp::to_unix()`")
181    }
182}
183
184pub(crate) const fn encode_gregorian_timestamp(
185    ticks: u64,
186    counter: u16,
187    node_id: &[u8; 6],
188) -> Uuid {
189    let time_low = (ticks & 0xFFFF_FFFF) as u32;
190    let time_mid = ((ticks >> 32) & 0xFFFF) as u16;
191    let time_high_and_version = (((ticks >> 48) & 0x0FFF) as u16) | (1 << 12);
192
193    let mut d4 = [0; 8];
194
195    d4[0] = (((counter & 0x3F00) >> 8) as u8) | 0x80;
196    d4[1] = (counter & 0xFF) as u8;
197    d4[2] = node_id[0];
198    d4[3] = node_id[1];
199    d4[4] = node_id[2];
200    d4[5] = node_id[3];
201    d4[6] = node_id[4];
202    d4[7] = node_id[5];
203
204    Uuid::from_fields(time_low, time_mid, time_high_and_version, &d4)
205}
206
207pub(crate) const fn decode_gregorian_timestamp(uuid: &Uuid) -> (u64, u16) {
208    let bytes = uuid.as_bytes();
209
210    let ticks: u64 = ((bytes[6] & 0x0F) as u64) << 56
211        | (bytes[7] as u64) << 48
212        | (bytes[4] as u64) << 40
213        | (bytes[5] as u64) << 32
214        | (bytes[0] as u64) << 24
215        | (bytes[1] as u64) << 16
216        | (bytes[2] as u64) << 8
217        | (bytes[3] as u64);
218
219    let counter: u16 = ((bytes[8] & 0x3F) as u16) << 8 | (bytes[9] as u16);
220
221    (ticks, counter)
222}
223
224pub(crate) const fn encode_sorted_gregorian_timestamp(
225    ticks: u64,
226    counter: u16,
227    node_id: &[u8; 6],
228) -> Uuid {
229    let time_high = ((ticks >> 28) & 0xFFFF_FFFF) as u32;
230    let time_mid = ((ticks >> 12) & 0xFFFF) as u16;
231    let time_low_and_version = ((ticks & 0x0FFF) as u16) | (0x6 << 12);
232
233    let mut d4 = [0; 8];
234
235    d4[0] = (((counter & 0x3F00) >> 8) as u8) | 0x80;
236    d4[1] = (counter & 0xFF) as u8;
237    d4[2] = node_id[0];
238    d4[3] = node_id[1];
239    d4[4] = node_id[2];
240    d4[5] = node_id[3];
241    d4[6] = node_id[4];
242    d4[7] = node_id[5];
243
244    Uuid::from_fields(time_high, time_mid, time_low_and_version, &d4)
245}
246
247pub(crate) const fn decode_sorted_gregorian_timestamp(uuid: &Uuid) -> (u64, u16) {
248    let bytes = uuid.as_bytes();
249
250    let ticks: u64 = ((bytes[0]) as u64) << 52
251        | (bytes[1] as u64) << 44
252        | (bytes[2] as u64) << 36
253        | (bytes[3] as u64) << 28
254        | (bytes[4] as u64) << 20
255        | (bytes[5] as u64) << 12
256        | ((bytes[6] & 0xF) as u64) << 8
257        | (bytes[7] as u64);
258
259    let counter: u16 = ((bytes[8] & 0x3F) as u16) << 8 | (bytes[9] as u16);
260
261    (ticks, counter)
262}
263
264pub(crate) const fn encode_unix_timestamp_millis(
265    millis: u64,
266    counter_random_bytes: &[u8; 10],
267) -> Uuid {
268    let millis_high = ((millis >> 16) & 0xFFFF_FFFF) as u32;
269    let millis_low = (millis & 0xFFFF) as u16;
270
271    let counter_random_version = (counter_random_bytes[1] as u16
272        | ((counter_random_bytes[0] as u16) << 8) & 0x0FFF)
273        | (0x7 << 12);
274
275    let mut d4 = [0; 8];
276
277    d4[0] = (counter_random_bytes[2] & 0x3F) | 0x80;
278    d4[1] = counter_random_bytes[3];
279    d4[2] = counter_random_bytes[4];
280    d4[3] = counter_random_bytes[5];
281    d4[4] = counter_random_bytes[6];
282    d4[5] = counter_random_bytes[7];
283    d4[6] = counter_random_bytes[8];
284    d4[7] = counter_random_bytes[9];
285
286    Uuid::from_fields(millis_high, millis_low, counter_random_version, &d4)
287}
288
289pub(crate) const fn decode_unix_timestamp_millis(uuid: &Uuid) -> u64 {
290    let bytes = uuid.as_bytes();
291
292    let millis: u64 = (bytes[0] as u64) << 40
293        | (bytes[1] as u64) << 32
294        | (bytes[2] as u64) << 24
295        | (bytes[3] as u64) << 16
296        | (bytes[4] as u64) << 8
297        | (bytes[5] as u64);
298
299    millis
300}
301
302#[cfg(all(
303    feature = "std",
304    feature = "js",
305    all(
306        target_arch = "wasm32",
307        target_vendor = "unknown",
308        target_os = "unknown"
309    )
310))]
311fn now() -> (u64, u32) {
312    use wasm_bindgen::prelude::*;
313
314    #[wasm_bindgen]
315    extern "C" {
316        // NOTE: This signature works around https://bugzilla.mozilla.org/show_bug.cgi?id=1787770
317        #[wasm_bindgen(js_namespace = Date, catch)]
318        fn now() -> Result<f64, JsValue>;
319    }
320
321    let now = now().unwrap_throw();
322
323    let secs = (now / 1_000.0) as u64;
324    let nanos = ((now % 1_000.0) * 1_000_000.0) as u32;
325
326    (secs, nanos)
327}
328
329#[cfg(all(
330    feature = "std",
331    not(miri),
332    any(
333        not(feature = "js"),
334        not(all(
335            target_arch = "wasm32",
336            target_vendor = "unknown",
337            target_os = "unknown"
338        ))
339    )
340))]
341fn now() -> (u64, u32) {
342    let dur = std::time::SystemTime::UNIX_EPOCH.elapsed().expect(
343        "Getting elapsed time since UNIX_EPOCH. If this fails, we've somehow violated causality",
344    );
345
346    (dur.as_secs(), dur.subsec_nanos())
347}
348
349#[cfg(all(feature = "std", miri))]
350fn now() -> (u64, u32) {
351    use std::{sync::Mutex, time::Duration};
352
353    static TS: Mutex<u64> = Mutex::new(0);
354
355    let ts = Duration::from_nanos({
356        let mut ts = TS.lock().unwrap();
357        *ts += 1;
358        *ts
359    });
360
361    (ts.as_secs(), ts.subsec_nanos())
362}
363
364/// A counter that can be used by versions 1 and 6 UUIDs to support
365/// the uniqueness of timestamps.
366///
367/// # References
368///
369/// * [UUID Version 1 in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-5.1)
370/// * [UUID Version 6 in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-5.6)
371/// * [UUID Generator States in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-6.3)
372pub trait ClockSequence {
373    /// The type of sequence returned by this counter.
374    type Output;
375
376    /// Get the next value in the sequence to feed into a timestamp.
377    ///
378    /// This method will be called each time a [`Timestamp`] is constructed.
379    ///
380    /// Any bits beyond [`ClockSequence::usable_bits`] in the output must be unset.
381    fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output;
382
383    /// Get the next value in the sequence, potentially also adjusting the timestamp.
384    ///
385    /// This method should be preferred over `generate_sequence`.
386    ///
387    /// Any bits beyond [`ClockSequence::usable_bits`] in the output must be unset.
388    fn generate_timestamp_sequence(
389        &self,
390        seconds: u64,
391        subsec_nanos: u32,
392    ) -> (Self::Output, u64, u32) {
393        (
394            self.generate_sequence(seconds, subsec_nanos),
395            seconds,
396            subsec_nanos,
397        )
398    }
399
400    /// The number of usable bits from the least significant bit in the result of [`ClockSequence::generate_sequence`]
401    /// or [`ClockSequence::generate_timestamp_sequence`].
402    ///
403    /// The number of usable bits must not exceed 128.
404    ///
405    /// The number of usable bits is not expected to change between calls. An implementation of `ClockSequence` should
406    /// always return the same value from this method.
407    fn usable_bits(&self) -> usize
408    where
409        Self::Output: Sized,
410    {
411        cmp::min(128, core::mem::size_of::<Self::Output>())
412    }
413}
414
415impl<'a, T: ClockSequence + ?Sized> ClockSequence for &'a T {
416    type Output = T::Output;
417
418    fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output {
419        (**self).generate_sequence(seconds, subsec_nanos)
420    }
421
422    fn generate_timestamp_sequence(
423        &self,
424        seconds: u64,
425        subsec_nanos: u32,
426    ) -> (Self::Output, u64, u32) {
427        (**self).generate_timestamp_sequence(seconds, subsec_nanos)
428    }
429
430    fn usable_bits(&self) -> usize
431    where
432        Self::Output: Sized,
433    {
434        (**self).usable_bits()
435    }
436}
437
438/// Default implementations for the [`ClockSequence`] trait.
439pub mod context {
440    use super::ClockSequence;
441
442    #[cfg(any(feature = "v1", feature = "v6"))]
443    mod v1_support {
444        use super::*;
445
446        use atomic::{Atomic, Ordering};
447
448        #[cfg(all(feature = "std", feature = "rng"))]
449        static CONTEXT: Context = Context {
450            count: Atomic::new(0),
451        };
452
453        #[cfg(all(feature = "std", feature = "rng"))]
454        static CONTEXT_INITIALIZED: Atomic<bool> = Atomic::new(false);
455
456        #[cfg(all(feature = "std", feature = "rng"))]
457        pub(crate) fn shared_context() -> &'static Context {
458            // If the context is in its initial state then assign it to a random value
459            // It doesn't matter if multiple threads observe `false` here and initialize the context
460            if CONTEXT_INITIALIZED
461                .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
462                .is_ok()
463            {
464                CONTEXT.count.store(crate::rng::u16(), Ordering::Release);
465            }
466
467            &CONTEXT
468        }
469
470        /// A thread-safe, wrapping counter that produces 14-bit values.
471        ///
472        /// This type works by:
473        ///
474        /// 1. Atomically incrementing the counter value for each timestamp.
475        /// 2. Wrapping the counter back to zero if it overflows its 14-bit storage.
476        ///
477        /// This type should be used when constructing versions 1 and 6 UUIDs.
478        ///
479        /// This type should not be used when constructing version 7 UUIDs. When used to
480        /// construct a version 7 UUID, the 14-bit counter will be padded with random data.
481        /// Counter overflows are more likely with a 14-bit counter than they are with a
482        /// 42-bit counter when working at millisecond precision. This type doesn't attempt
483        /// to adjust the timestamp on overflow.
484        #[derive(Debug)]
485        pub struct Context {
486            count: Atomic<u16>,
487        }
488
489        impl Context {
490            /// Construct a new context that's initialized with the given value.
491            ///
492            /// The starting value should be a random number, so that UUIDs from
493            /// different systems with the same timestamps are less likely to collide.
494            /// When the `rng` feature is enabled, prefer the [`Context::new_random`] method.
495            pub const fn new(count: u16) -> Self {
496                Self {
497                    count: Atomic::<u16>::new(count),
498                }
499            }
500
501            /// Construct a new context that's initialized with a random value.
502            #[cfg(feature = "rng")]
503            pub fn new_random() -> Self {
504                Self {
505                    count: Atomic::<u16>::new(crate::rng::u16()),
506                }
507            }
508        }
509
510        impl ClockSequence for Context {
511            type Output = u16;
512
513            fn generate_sequence(&self, _seconds: u64, _nanos: u32) -> Self::Output {
514                // RFC 9562 reserves 2 bits of the clock sequence so the actual
515                // maximum value is smaller than `u16::MAX`. Since we unconditionally
516                // increment the clock sequence we want to wrap once it becomes larger
517                // than what we can represent in a "u14". Otherwise there'd be patches
518                // where the clock sequence doesn't change regardless of the timestamp
519                self.count.fetch_add(1, Ordering::AcqRel) & (u16::MAX >> 2)
520            }
521
522            fn usable_bits(&self) -> usize {
523                14
524            }
525        }
526
527        #[cfg(test)]
528        mod tests {
529            use crate::Timestamp;
530
531            use super::*;
532
533            #[test]
534            fn context() {
535                let seconds = 1_496_854_535;
536                let subsec_nanos = 812_946_000;
537
538                let context = Context::new(u16::MAX >> 2);
539
540                let ts = Timestamp::from_unix(&context, seconds, subsec_nanos);
541                assert_eq!(16383, ts.counter);
542                assert_eq!(14, ts.usable_counter_bits);
543
544                let seconds = 1_496_854_536;
545
546                let ts = Timestamp::from_unix(&context, seconds, subsec_nanos);
547                assert_eq!(0, ts.counter);
548
549                let seconds = 1_496_854_535;
550
551                let ts = Timestamp::from_unix(&context, seconds, subsec_nanos);
552                assert_eq!(1, ts.counter);
553            }
554        }
555    }
556
557    #[cfg(any(feature = "v1", feature = "v6"))]
558    pub use v1_support::*;
559
560    #[cfg(feature = "std")]
561    mod std_support {
562        use super::*;
563
564        use core::panic::{AssertUnwindSafe, RefUnwindSafe};
565        use std::{sync::Mutex, thread::LocalKey};
566
567        /// A wrapper for a context that uses thread-local storage.
568        pub struct ThreadLocalContext<C: 'static>(&'static LocalKey<C>);
569
570        impl<C> std::fmt::Debug for ThreadLocalContext<C> {
571            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
572                f.debug_struct("ThreadLocalContext").finish_non_exhaustive()
573            }
574        }
575
576        impl<C: 'static> ThreadLocalContext<C> {
577            /// Wrap a thread-local container with a context.
578            pub const fn new(local_key: &'static LocalKey<C>) -> Self {
579                ThreadLocalContext(local_key)
580            }
581        }
582
583        impl<C: ClockSequence + 'static> ClockSequence for ThreadLocalContext<C> {
584            type Output = C::Output;
585
586            fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output {
587                self.0
588                    .with(|ctxt| ctxt.generate_sequence(seconds, subsec_nanos))
589            }
590
591            fn generate_timestamp_sequence(
592                &self,
593                seconds: u64,
594                subsec_nanos: u32,
595            ) -> (Self::Output, u64, u32) {
596                self.0
597                    .with(|ctxt| ctxt.generate_timestamp_sequence(seconds, subsec_nanos))
598            }
599
600            fn usable_bits(&self) -> usize {
601                self.0.with(|ctxt| ctxt.usable_bits())
602            }
603        }
604
605        impl<C: ClockSequence> ClockSequence for AssertUnwindSafe<C> {
606            type Output = C::Output;
607
608            fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output {
609                self.0.generate_sequence(seconds, subsec_nanos)
610            }
611
612            fn generate_timestamp_sequence(
613                &self,
614                seconds: u64,
615                subsec_nanos: u32,
616            ) -> (Self::Output, u64, u32) {
617                self.0.generate_timestamp_sequence(seconds, subsec_nanos)
618            }
619
620            fn usable_bits(&self) -> usize
621            where
622                Self::Output: Sized,
623            {
624                self.0.usable_bits()
625            }
626        }
627
628        impl<C: ClockSequence + RefUnwindSafe> ClockSequence for Mutex<C> {
629            type Output = C::Output;
630
631            fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output {
632                self.lock()
633                    .unwrap_or_else(|err| err.into_inner())
634                    .generate_sequence(seconds, subsec_nanos)
635            }
636
637            fn generate_timestamp_sequence(
638                &self,
639                seconds: u64,
640                subsec_nanos: u32,
641            ) -> (Self::Output, u64, u32) {
642                self.lock()
643                    .unwrap_or_else(|err| err.into_inner())
644                    .generate_timestamp_sequence(seconds, subsec_nanos)
645            }
646
647            fn usable_bits(&self) -> usize
648            where
649                Self::Output: Sized,
650            {
651                self.lock()
652                    .unwrap_or_else(|err| err.into_inner())
653                    .usable_bits()
654            }
655        }
656    }
657
658    #[cfg(feature = "std")]
659    pub use std_support::*;
660
661    #[cfg(feature = "v7")]
662    mod v7_support {
663        use super::*;
664
665        use core::{cell::Cell, panic::RefUnwindSafe};
666
667        #[cfg(feature = "std")]
668        static CONTEXT_V7: SharedContextV7 =
669            SharedContextV7(std::sync::Mutex::new(ContextV7::new()));
670
671        #[cfg(feature = "std")]
672        pub(crate) fn shared_context_v7() -> &'static SharedContextV7 {
673            &CONTEXT_V7
674        }
675
676        const USABLE_BITS: usize = 42;
677
678        // Leave the most significant bit unset
679        // This guarantees the counter has at least 2,199,023,255,552
680        // values before it will overflow, which is exceptionally unlikely
681        // even in the worst case
682        const RESEED_MASK: u64 = u64::MAX >> 23;
683        const MAX_COUNTER: u64 = u64::MAX >> 22;
684
685        /// An unsynchronized, reseeding counter that produces 42-bit values.
686        ///
687        /// This type works by:
688        ///
689        /// 1. Reseeding the counter each millisecond with a random 41-bit value. The 42nd bit
690        ///    is left unset so the counter can safely increment over the millisecond.
691        /// 2. Wrapping the counter back to zero if it overflows its 42-bit storage and adding a
692        ///    millisecond to the timestamp.
693        ///
694        /// This type can be used when constructing version 7 UUIDs. When used to construct a
695        /// version 7 UUID, the 42-bit counter will be padded with random data. This type can
696        /// be used to maintain ordering of UUIDs within the same millisecond.
697        ///
698        /// This type should not be used when constructing version 1 or version 6 UUIDs.
699        /// When used to construct a version 1 or version 6 UUID, only the 14 least significant
700        /// bits of the counter will be used.
701        #[derive(Debug)]
702        pub struct ContextV7 {
703            last_reseed: Cell<LastReseed>,
704            counter: Cell<u64>,
705        }
706
707        #[derive(Debug, Default, Clone, Copy)]
708        struct LastReseed {
709            millis: u64,
710            ts_seconds: u64,
711            ts_subsec_nanos: u32,
712        }
713
714        impl LastReseed {
715            fn from_millis(millis: u64) -> Self {
716                LastReseed {
717                    millis,
718                    ts_seconds: millis / 1_000,
719                    ts_subsec_nanos: (millis % 1_000) as u32 * 1_000_000,
720                }
721            }
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                    last_reseed: Cell::new(LastReseed {
732                        millis: 0,
733                        ts_seconds: 0,
734                        ts_subsec_nanos: 0,
735                    }),
736                    counter: Cell::new(0),
737                }
738            }
739        }
740
741        impl ClockSequence for ContextV7 {
742            type Output = u64;
743
744            fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output {
745                self.generate_timestamp_sequence(seconds, subsec_nanos).0
746            }
747
748            fn generate_timestamp_sequence(
749                &self,
750                seconds: u64,
751                subsec_nanos: u32,
752            ) -> (Self::Output, u64, u32) {
753                let millis = (seconds * 1_000).saturating_add(subsec_nanos as u64 / 1_000_000);
754
755                let last_reseed = self.last_reseed.get();
756
757                // If the observed system time has shifted forwards then regenerate the counter
758                if millis > last_reseed.millis {
759                    let last_reseed = LastReseed::from_millis(millis);
760                    self.last_reseed.set(last_reseed);
761
762                    let counter = crate::rng::u64() & RESEED_MASK;
763                    self.counter.set(counter);
764
765                    (counter, last_reseed.ts_seconds, last_reseed.ts_subsec_nanos)
766                }
767                // If the observed system time has not shifted forwards then increment the counter
768                else {
769                    // If the incoming timestamp is earlier than the last observed one then
770                    // use it instead. This may happen if the system clock jitters, or if the counter
771                    // has wrapped and the timestamp is artificially incremented
772                    let millis = ();
773                    let _ = millis;
774
775                    // Guaranteed to never overflow u64
776                    let counter = self.counter.get() + 1;
777
778                    // If the counter has not overflowed its 42-bit storage then return it
779                    if counter <= MAX_COUNTER {
780                        self.counter.set(counter);
781
782                        (counter, last_reseed.ts_seconds, last_reseed.ts_subsec_nanos)
783                    }
784                    // Unlikely: If the counter has overflowed its 42-bit storage then wrap it
785                    // and increment the timestamp. Until the observed system time shifts past
786                    // this incremented value, all timestamps will use it to maintain monotonicity
787                    else {
788                        // Increment the timestamp by 1 milli
789                        let last_reseed = LastReseed::from_millis(last_reseed.millis + 1);
790                        self.last_reseed.set(last_reseed);
791
792                        // Reseed the counter
793                        let counter = crate::rng::u64() & RESEED_MASK;
794                        self.counter.set(counter);
795
796                        (counter, last_reseed.ts_seconds, last_reseed.ts_subsec_nanos)
797                    }
798                }
799            }
800
801            fn usable_bits(&self) -> usize {
802                USABLE_BITS
803            }
804        }
805
806        #[cfg(feature = "std")]
807        pub(crate) struct SharedContextV7(std::sync::Mutex<ContextV7>);
808
809        #[cfg(feature = "std")]
810        impl ClockSequence for SharedContextV7 {
811            type Output = u64;
812
813            fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output {
814                self.0.generate_sequence(seconds, subsec_nanos)
815            }
816
817            fn generate_timestamp_sequence(
818                &self,
819                seconds: u64,
820                subsec_nanos: u32,
821            ) -> (Self::Output, u64, u32) {
822                self.0.generate_timestamp_sequence(seconds, subsec_nanos)
823            }
824
825            fn usable_bits(&self) -> usize
826            where
827                Self::Output: Sized,
828            {
829                USABLE_BITS
830            }
831        }
832
833        #[cfg(test)]
834        mod tests {
835            use core::time::Duration;
836
837            use super::*;
838
839            use crate::Timestamp;
840
841            #[test]
842            fn context() {
843                let seconds = 1_496_854_535;
844                let subsec_nanos = 812_946_000;
845
846                let context = ContextV7::new();
847
848                let ts1 = Timestamp::from_unix(&context, seconds, subsec_nanos);
849                assert_eq!(42, ts1.usable_counter_bits);
850
851                // Backwards second
852                let seconds = 1_496_854_534;
853
854                let ts2 = Timestamp::from_unix(&context, seconds, subsec_nanos);
855
856                // The backwards time should be ignored
857                // The counter should still increment
858                assert_eq!(ts1.seconds, ts2.seconds);
859                assert_eq!(ts1.subsec_nanos, ts2.subsec_nanos);
860                assert_eq!(ts1.counter + 1, ts2.counter);
861
862                // Forwards second
863                let seconds = 1_496_854_536;
864
865                let ts3 = Timestamp::from_unix(&context, seconds, subsec_nanos);
866
867                // The counter should have reseeded
868                assert_ne!(ts2.counter + 1, ts3.counter);
869                assert_ne!(0, ts3.counter);
870            }
871
872            #[test]
873            fn context_wrap() {
874                let seconds = 1_496_854_535u64;
875                let subsec_nanos = 812_946_000u32;
876
877                let millis = (seconds * 1000).saturating_add(subsec_nanos as u64 / 1_000_000);
878
879                // This context will wrap
880                let context = ContextV7 {
881                    last_reseed: Cell::new(LastReseed::from_millis(millis)),
882                    counter: Cell::new(u64::MAX >> 22),
883                };
884
885                let ts = Timestamp::from_unix(&context, seconds, subsec_nanos);
886
887                // The timestamp should be incremented by 1ms
888                let expected_ts = Duration::new(seconds, subsec_nanos / 1_000_000 * 1_000_000)
889                    + Duration::from_millis(1);
890                assert_eq!(expected_ts.as_secs(), ts.seconds);
891                assert_eq!(expected_ts.subsec_nanos(), ts.subsec_nanos);
892
893                // The counter should have reseeded
894                assert!(ts.counter < (u64::MAX >> 22) as u128);
895                assert_ne!(0, ts.counter);
896            }
897        }
898    }
899
900    #[cfg(feature = "v7")]
901    pub use v7_support::*;
902
903    /// An empty counter that will always return the value `0`.
904    ///
905    /// This type can be used when constructing version 7 UUIDs. When used to
906    /// construct a version 7 UUID, the entire counter segment of the UUID will be
907    /// filled with a random value. This type does not maintain ordering of UUIDs
908    /// within a millisecond but is efficient.
909    ///
910    /// This type should not be used when constructing version 1 or version 6 UUIDs.
911    /// When used to construct a version 1 or version 6 UUID, the counter
912    /// segment will remain zero.
913    #[derive(Debug, Clone, Copy, Default)]
914    pub struct NoContext;
915
916    impl ClockSequence for NoContext {
917        type Output = u16;
918
919        fn generate_sequence(&self, _seconds: u64, _nanos: u32) -> Self::Output {
920            0
921        }
922
923        fn usable_bits(&self) -> usize {
924            0
925        }
926    }
927}
928
929#[cfg(all(test, any(feature = "v1", feature = "v6")))]
930mod tests {
931    use super::*;
932
933    #[cfg(all(
934        target_arch = "wasm32",
935        target_vendor = "unknown",
936        target_os = "unknown"
937    ))]
938    use wasm_bindgen_test::*;
939
940    #[test]
941    #[cfg_attr(
942        all(
943            target_arch = "wasm32",
944            target_vendor = "unknown",
945            target_os = "unknown"
946        ),
947        wasm_bindgen_test
948    )]
949    fn gregorian_unix_does_not_panic() {
950        // Ensure timestamp conversions never panic
951        Timestamp::unix_to_gregorian_ticks(u64::MAX, 0);
952        Timestamp::unix_to_gregorian_ticks(0, u32::MAX);
953        Timestamp::unix_to_gregorian_ticks(u64::MAX, u32::MAX);
954
955        Timestamp::gregorian_to_unix(u64::MAX);
956    }
957
958    #[test]
959    #[cfg_attr(
960        all(
961            target_arch = "wasm32",
962            target_vendor = "unknown",
963            target_os = "unknown"
964        ),
965        wasm_bindgen_test
966    )]
967    fn to_gregorian_truncates_to_usable_bits() {
968        let ts = Timestamp::from_gregorian(123, u16::MAX);
969
970        assert_eq!((123, u16::MAX >> 2), ts.to_gregorian());
971    }
972}