Coverage Report

Created: 2026-08-31 06:40

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