Skip to main content

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