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)
2324use core::cmp;
2526use crate::Uuid;
2728/// 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;
3132/// 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}
4950impl 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")]
55pub fn now(context: impl ClockSequence<Output = impl Into<u128>>) -> Self {
56let (seconds, subsec_nanos) = now();
5758let (counter, seconds, subsec_nanos) =
59context.generate_timestamp_sequence(seconds, subsec_nanos);
60let counter = counter.into();
61let usable_counter_bits = context.usable_bits() as u8;
6263Timestamp {
64seconds,
65subsec_nanos,
66counter,
67usable_counter_bits,
68 }
69 }
7071/// 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.
79pub const fn from_gregorian_time(ticks: u64, counter: u16) -> Self {
80let (seconds, subsec_nanos) = Self::gregorian_to_unix(ticks);
8182Timestamp {
83seconds,
84subsec_nanos,
85 counter: counteras u128,
86 usable_counter_bits: 14,
87 }
88 }
8990/// Construct a `Timestamp` from a Unix timestamp and up to a 128-bit counter, as used in version 7 UUIDs.
91pub const fn from_unix_time(
92 seconds: u64,
93 subsec_nanos: u32,
94 counter: u128,
95 usable_counter_bits: u8,
96 ) -> Self {
97Timestamp {
98seconds,
99subsec_nanos,
100counter,
101usable_counter_bits,
102 }
103 }
104105/// Construct a `Timestamp` from a Unix timestamp and up to a 128-bit counter, as used in version 7 UUIDs.
106pub fn from_unix(
107 context: impl ClockSequence<Output = impl Into<u128>>,
108 seconds: u64,
109 subsec_nanos: u32,
110 ) -> Self {
111let (counter, seconds, subsec_nanos) =
112context.generate_timestamp_sequence(seconds, subsec_nanos);
113let counter = counter.into();
114let usable_counter_bits = context.usable_bits() as u8;
115116Timestamp {
117seconds,
118subsec_nanos,
119counter,
120usable_counter_bits,
121 }
122 }
123124/// 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.
133pub const fn to_gregorian(&self) -> (u64, u16) {
134 (
135Self::unix_to_gregorian_ticks(self.seconds, self.subsec_nanos),
136 (self.counter as u16) & 0x3FFF,
137 )
138 }
139140// 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")]
143pub(crate) const fn counter(&self) -> (u128, u8) {
144 (self.counter, self.usable_counter_bits)
145 }
146147/// Get the value of the timestamp as a Unix timestamp, as used in version 7 UUIDs.
148pub const fn to_unix(&self) -> (u64, u32) {
149 (self.seconds, self.subsec_nanos)
150 }
151152const fn unix_to_gregorian_ticks(seconds: u64, nanos: u32) -> u64 {
153UUID_TICKS_BETWEEN_EPOCHS154 .wrapping_add(seconds.wrapping_mul(10_000_000))
155 .wrapping_add(nanosas u64 / 100)
156 }
157158const fn gregorian_to_unix(ticks: u64) -> (u64, u32) {
159 (
160ticks.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}
165166#[doc(hidden)]
167impl Timestamp {
168#[deprecated(
169 since = "1.10.0",
170 note = "use `Timestamp::from_gregorian_time(ticks, counter)`"
171)]
172pub const fn from_rfc4122(ticks: u64, counter: u16) -> Self {
173Timestamp::from_gregorian_time(ticks, counter)
174 }
175176#[deprecated(since = "1.10.0", note = "use `Timestamp::to_gregorian()`")]
177pub const fn to_rfc4122(&self) -> (u64, u16) {
178self.to_gregorian()
179 }
180181#[deprecated(
182 since = "1.2.0",
183 note = "`Timestamp::to_unix_nanos()` is deprecated and will be removed: use `Timestamp::to_unix()`"
184)]
185pub 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 }
188189#[deprecated(
190 since = "1.23.0",
191 note = "use `Timestamp::from_gregorian_time(ticks, counter)`"
192)]
193pub const fn from_gregorian(ticks: u64, counter: u16) -> Self {
194Timestamp::from_gregorian_time(ticks, counter)
195 }
196}
197198#[cfg(feature = "std")]
199impl TryFrom<std::time::SystemTime> for Timestamp {
200type Error = crate::Error;
201202/// 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.
206fn try_from(st: std::time::SystemTime) -> Result<Self, Self::Error> {
207let dur = st.duration_since(std::time::UNIX_EPOCH).map_err(|_| {
208crate::Error(crate::error::ErrorKind::InvalidSystemTime(
209"unable to convert the system tie into a Unix timestamp",
210 ))
211 })?;
212213Ok(Self::from_unix_time(
214dur.as_secs(),
215dur.subsec_nanos(),
2160,
2170,
218 ))
219 }
220}
221222#[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.
229fn from(ts: Timestamp) -> Self {
230let (seconds, subsec_nanos) = ts.to_unix();
231232// NOTE: The actual value on overflow is undefined and may change
233 // See: https://github.com/rust-lang/rust/issues/151199
234Self::UNIX_EPOCH235 .checked_add(std::time::Duration::new(seconds, subsec_nanos))
236 .unwrap_or(std::time::SystemTime::UNIX_EPOCH)
237 }
238}
239240pub(crate) const fn encode_gregorian_timestamp(
241 ticks: u64,
242 counter: u16,
243 node_id: &[u8; 6],
244) -> Uuid {
245let time_low = (ticks & 0xFFFF_FFFF) as u32;
246let time_mid = ((ticks >> 32) & 0xFFFF) as u16;
247let time_high_and_version = (((ticks >> 48) & 0x0FFF) as u16) | (1 << 12);
248249let mut d4 = [0; 8];
250251d4[0] = (((counter & 0x3F00) >> 8) as u8) | 0x80;
252d4[1] = (counter & 0xFF) as u8;
253d4[2] = node_id[0];
254d4[3] = node_id[1];
255d4[4] = node_id[2];
256d4[5] = node_id[3];
257d4[6] = node_id[4];
258d4[7] = node_id[5];
259260Uuid::from_fields(time_low, time_mid, time_high_and_version, &d4)
261}
262263pub(crate) const fn decode_gregorian_timestamp(uuid: &Uuid) -> (u64, u16) {
264let bytes = uuid.as_bytes();
265266let 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);
274275let counter: u16 = ((bytes[8] & 0x3F) as u16) << 8 | (bytes[9] as u16);
276277 (ticks, counter)
278}
279280pub(crate) const fn encode_sorted_gregorian_timestamp(
281 ticks: u64,
282 counter: u16,
283 node_id: &[u8; 6],
284) -> Uuid {
285let time_high = ((ticks >> 28) & 0xFFFF_FFFF) as u32;
286let time_mid = ((ticks >> 12) & 0xFFFF) as u16;
287let time_low_and_version = ((ticks & 0x0FFF) as u16) | (0x6 << 12);
288289let mut d4 = [0; 8];
290291d4[0] = (((counter & 0x3F00) >> 8) as u8) | 0x80;
292d4[1] = (counter & 0xFF) as u8;
293d4[2] = node_id[0];
294d4[3] = node_id[1];
295d4[4] = node_id[2];
296d4[5] = node_id[3];
297d4[6] = node_id[4];
298d4[7] = node_id[5];
299300Uuid::from_fields(time_high, time_mid, time_low_and_version, &d4)
301}
302303pub(crate) const fn decode_sorted_gregorian_timestamp(uuid: &Uuid) -> (u64, u16) {
304let bytes = uuid.as_bytes();
305306let 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);
314315let counter: u16 = ((bytes[8] & 0x3F) as u16) << 8 | (bytes[9] as u16);
316317 (ticks, counter)
318}
319320pub(crate) const fn encode_unix_timestamp_millis(
321 millis: u64,
322 counter_random_bytes: &[u8; 10],
323) -> Uuid {
324let millis_high = ((millis >> 16) & 0xFFFF_FFFF) as u32;
325let millis_low = (millis & 0xFFFF) as u16;
326327let counter_random_version = (counter_random_bytes[1] as u16328 | ((counter_random_bytes[0] as u16) << 8) & 0x0FFF)
329 | (0x7 << 12);
330331let mut d4 = [0; 8];
332333d4[0] = (counter_random_bytes[2] & 0x3F) | 0x80;
334d4[1] = counter_random_bytes[3];
335d4[2] = counter_random_bytes[4];
336d4[3] = counter_random_bytes[5];
337d4[4] = counter_random_bytes[6];
338d4[5] = counter_random_bytes[7];
339d4[6] = counter_random_bytes[8];
340d4[7] = counter_random_bytes[9];
341342Uuid::from_fields(millis_high, millis_low, counter_random_version, &d4)
343}
344345pub(crate) const fn decode_unix_timestamp_millis(uuid: &Uuid) -> u64 {
346let bytes = uuid.as_bytes();
347348let 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);
354355millis356}
357358#[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) {
364use wasm_bindgen::prelude::*;
365366#[wasm_bindgen]
367extern "C" {
368// NOTE: This signature works around https://bugzilla.mozilla.org/show_bug.cgi?id=1787770
369#[wasm_bindgen(js_namespace = Date, catch)]
370fn now() -> Result<f64, JsValue>;
371 }
372373let now = now().unwrap_throw();
374375let secs = (now / 1_000.0) as u64;
376let nanos = ((now % 1_000.0) * 1_000_000.0) as u32;
377378 (secs, nanos)
379}
380381#[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) {
390let dur = std::time::SystemTime::UNIX_EPOCH.elapsed().expect(
391"Getting elapsed time since UNIX_EPOCH. If this fails, we've somehow violated causality",
392 );
393394 (dur.as_secs(), dur.subsec_nanos())
395}
396397#[cfg(all(feature = "std", miri))]
398fn now() -> (u64, u32) {
399use std::{sync::Mutex, time::Duration};
400401static TS: Mutex<u64> = Mutex::new(0);
402403let ts = Duration::from_nanos({
404let mut ts = TS.lock().unwrap();
405*ts += 1;
406*ts
407 });
408409 (ts.as_secs(), ts.subsec_nanos())
410}
411412/// 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.
422type Output;
423424/// 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.
429fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output;
430431/// 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.
436fn generate_timestamp_sequence(
437&self,
438 seconds: u64,
439 subsec_nanos: u32,
440 ) -> (Self::Output, u64, u32) {
441 (
442self.generate_sequence(seconds, subsec_nanos),
443seconds,
444subsec_nanos,
445 )
446 }
447448/// 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.
455fn usable_bits(&self) -> usize456where
457Self::Output: Sized,
458 {
459 cmp::min(128, core::mem::size_of::<Self::Output>() * 8)
460 }
461}
462463impl<T: ClockSequence + ?Sized> ClockSequencefor &T {
464type Output = T::Output;
465466fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output {
467 (**self).generate_sequence(seconds, subsec_nanos)
468 }
469470fn 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 }
477478fn usable_bits(&self) -> usize479where
480Self::Output: Sized,
481 {
482 (**self).usable_bits()
483 }
484}
485486/// Default implementations for the [`ClockSequence`] trait.
487pub mod context {
488use super::ClockSequence;
489490#[cfg(any(feature = "v1", feature = "v6"))]
491mod v1_support {
492use super::*;
493494#[cfg(all(feature = "std", feature = "rng"))]
495use crate::std::sync::LazyLock;
496497use atomic::{Atomic, Ordering};
498499#[cfg(all(feature = "std", feature = "rng"))]
500static CONTEXT: LazyLock<ContextV1> = LazyLock::new(ContextV1::new_random);
501502#[cfg(all(feature = "std", feature = "rng"))]
503pub(crate) fn shared_context_v1() -> &'static ContextV1 {
504&*CONTEXT
505 }
506507/// 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)]
523pub struct ContextV1 {
524 count: Atomic<u16>,
525 }
526527impl 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.
533pub const fn new(count: u16) -> Self {
534Self {
535 count: Atomic::<u16>::new(count),
536 }
537 }
538539/// Construct a new context that's initialized with a random value.
540#[cfg(feature = "rng")]
541pub fn new_random() -> Self {
542Self {
543 count: Atomic::<u16>::new(crate::rng::u16()),
544 }
545 }
546 }
547548impl ClockSequence for ContextV1 {
549type Output = u16;
550551fn 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
557self.count.fetch_add(1, Ordering::AcqRel) & (u16::MAX >> 2)
558 }
559560fn usable_bits(&self) -> usize {
56114
562}
563 }
564565#[deprecated(since = "1.23.0", note = "renamed to `ContextV1`")]
566 #[doc(hidden)]
567pub type Context = ContextV1;
568569#[cfg(test)]
570mod tests {
571use crate::Timestamp;
572573use super::*;
574575#[test]
576fn context() {
577let seconds = 1_496_854_535;
578let subsec_nanos = 812_946_000;
579580let context = ContextV1::new(u16::MAX >> 2);
581582let ts = Timestamp::from_unix(&context, seconds, subsec_nanos);
583assert_eq!(16383, ts.counter);
584assert_eq!(14, ts.usable_counter_bits);
585586let seconds = 1_496_854_536;
587588let ts = Timestamp::from_unix(&context, seconds, subsec_nanos);
589assert_eq!(0, ts.counter);
590591let seconds = 1_496_854_535;
592593let ts = Timestamp::from_unix(&context, seconds, subsec_nanos);
594assert_eq!(1, ts.counter);
595 }
596597#[test]
598fn context_overflow() {
599let seconds = u64::MAX;
600let subsec_nanos = u32::MAX;
601602let context = ContextV1::new(u16::MAX);
603604// Ensure we don't panic
605Timestamp::from_unix(&context, seconds, subsec_nanos);
606 }
607 }
608 }
609610#[cfg(any(feature = "v1", feature = "v6"))]
611pub use v1_support::*;
612613#[cfg(feature = "std")]
614mod std_support {
615use super::*;
616617use core::panic::{AssertUnwindSafe, RefUnwindSafe};
618use std::{sync::Mutex, thread::LocalKey};
619620/// A wrapper for a context that uses thread-local storage.
621pub struct ThreadLocalContext<C: 'static>(&'static LocalKey<C>);
622623impl<C> std::fmt::Debugfor ThreadLocalContext<C> {
624fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
625f.debug_struct("ThreadLocalContext").finish_non_exhaustive()
626 }
627 }
628629impl<C: 'static> ThreadLocalContext<C> {
630/// Wrap a thread-local container with a context.
631pub const fn new(local_key: &'static LocalKey<C>) -> Self {
632ThreadLocalContext(local_key)
633 }
634 }
635636impl<C: ClockSequence + 'static> ClockSequencefor ThreadLocalContext<C> {
637type Output = C::Output;
638639fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output {
640self.0
641.with(|ctxt| ctxt.generate_sequence(seconds, subsec_nanos))
642 }
643644fn generate_timestamp_sequence(
645&self,
646 seconds: u64,
647 subsec_nanos: u32,
648 ) -> (Self::Output, u64, u32) {
649self.0
650.with(|ctxt| ctxt.generate_timestamp_sequence(seconds, subsec_nanos))
651 }
652653fn usable_bits(&self) -> usize {
654self.0.with(|ctxt| ctxt.usable_bits())
655 }
656 }
657658impl<C: ClockSequence> ClockSequencefor AssertUnwindSafe<C> {
659type Output = C::Output;
660661fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output {
662self.0.generate_sequence(seconds, subsec_nanos)
663 }
664665fn generate_timestamp_sequence(
666&self,
667 seconds: u64,
668 subsec_nanos: u32,
669 ) -> (Self::Output, u64, u32) {
670self.0.generate_timestamp_sequence(seconds, subsec_nanos)
671 }
672673fn usable_bits(&self) -> usize674where
675Self::Output: Sized,
676 {
677self.0.usable_bits()
678 }
679 }
680681impl<C: ClockSequence + RefUnwindSafe> ClockSequencefor Mutex<C> {
682type Output = C::Output;
683684fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output {
685self.lock()
686 .unwrap_or_else(|err| err.into_inner())
687 .generate_sequence(seconds, subsec_nanos)
688 }
689690fn generate_timestamp_sequence(
691&self,
692 seconds: u64,
693 subsec_nanos: u32,
694 ) -> (Self::Output, u64, u32) {
695self.lock()
696 .unwrap_or_else(|err| err.into_inner())
697 .generate_timestamp_sequence(seconds, subsec_nanos)
698 }
699700fn usable_bits(&self) -> usize701where
702Self::Output: Sized,
703 {
704self.lock()
705 .unwrap_or_else(|err| err.into_inner())
706 .usable_bits()
707 }
708 }
709 }
710711#[cfg(feature = "std")]
712pub use std_support::*;
713714#[cfg(feature = "v7")]
715mod v7_support {
716use super::*;
717718use core::{cell::Cell, cmp, panic::RefUnwindSafe};
719720#[cfg(feature = "std")]
721static CONTEXT_V7: SharedContextV7 =
722 SharedContextV7(std::sync::Mutex::new(ContextV7::new()));
723724#[cfg(feature = "std")]
725pub(crate) fn shared_context_v7() -> &'static SharedContextV7 {
726&CONTEXT_V7
727 }
728729const USABLE_BITS: usize = 42;
730731// 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
735const RESEED_MASK: u64 = u64::MAX >> 23;
736const MAX_COUNTER: u64 = u64::MAX >> 22;
737738/// 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)]
764pub struct ContextV7 {
765 timestamp: Cell<ReseedingTimestamp>,
766 counter: Cell<Counter>,
767 adjust: Adjust,
768 precision: Precision,
769 }
770771impl RefUnwindSafe for ContextV7 {}
772773impl ContextV7 {
774/// Construct a new context that will reseed its counter on the first
775 /// non-zero timestamp it receives.
776pub 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 }
793794/// Specify an amount to shift timestamps by to obfuscate their actual generation time.
795pub fn with_adjust_by_millis(mut self, millis: u32) -> Self {
796self.adjust = Adjust::by_millis(millis);
797self
798}
799800/// 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.
806pub fn with_additional_precision(self) -> Self {
807self.with_additional_precision_bits(12)
808 }
809810/// 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.
819pub fn with_additional_precision_bits(mut self, bits: usize) -> Self {
820self.precision = Precision::new(cmp::min(bits, 12));
821self
822}
823 }
824825impl ClockSequence for ContextV7 {
826type Output = u64;
827828fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output {
829self.generate_timestamp_sequence(seconds, subsec_nanos).0
830}
831832fn generate_timestamp_sequence(
833&self,
834 seconds: u64,
835 subsec_nanos: u32,
836 ) -> (Self::Output, u64, u32) {
837let (seconds, subsec_nanos) = self.adjust.apply(seconds, subsec_nanos);
838839let mut counter;
840let (mut timestamp, should_reseed) =
841self.timestamp.get().advance(seconds, subsec_nanos);
842843if should_reseed {
844// If the observed system time has shifted forwards then regenerate the counter
845counter = Counter::reseed(&self.precision, ×tamp);
846 } else {
847// If the observed system time has not shifted forwards then increment the counter
848849 // 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
852853counter = self.counter.get().increment(&self.precision, ×tamp);
854855// 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
858if counter.has_overflowed() {
859// Increment the timestamp by 1 milli and reseed the counter
860timestamp = timestamp.increment();
861 counter = Counter::reseed(&self.precision, ×tamp);
862 }
863 };
864865self.timestamp.set(timestamp);
866self.counter.set(counter);
867868 (counter.value, timestamp.seconds, timestamp.subsec_nanos)
869 }
870871fn usable_bits(&self) -> usize {
872 USABLE_BITS
873 }
874 }
875876/// A timestamp that keeps track of whether a reseed is necessary.
877#[derive(Debug, Default, Clone, Copy)]
878struct ReseedingTimestamp {
879 last_seed: u64,
880 seconds: u64,
881 subsec_nanos: u32,
882 }
883884impl ReseedingTimestamp {
885#[inline]
886fn from_ts(seconds: u64, subsec_nanos: u32) -> Self {
887// Reseed when the millisecond advances
888let last_seed = seconds
889 .saturating_mul(1_000)
890 .saturating_add((subsec_nanos / 1_000_000) as u64);
891892 ReseedingTimestamp {
893 last_seed,
894 seconds,
895 subsec_nanos,
896 }
897 }
898899/// Advance the timestamp to a new value, returning whether a reseed is necessary.
900#[inline]
901fn advance(&self, seconds: u64, subsec_nanos: u32) -> (Self, bool) {
902let incoming = ReseedingTimestamp::from_ts(seconds, subsec_nanos);
903904if 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
910let mut value = *self;
911 value.subsec_nanos = cmp::max(self.subsec_nanos, subsec_nanos);
912913 (value, false)
914 }
915 }
916917/// Advance the timestamp by a millisecond.
918#[inline]
919fn increment(&self) -> Self {
920let (seconds, subsec_nanos) =
921 Adjust::by_millis(1).apply(self.seconds, self.subsec_nanos);
922923 ReseedingTimestamp::from_ts(seconds, subsec_nanos)
924 }
925926#[inline]
927fn submilli_nanos(&self) -> u32 {
928self.subsec_nanos % 1_000_000
929}
930 }
931932/// A counter that initializes to a safe random seed and tracks overflow.
933#[derive(Debug, Clone, Copy)]
934struct Counter {
935 value: u64,
936 }
937938impl Counter {
939#[inline]
940fn reseed(precision: &Precision, timestamp: &ReseedingTimestamp) -> Self {
941 Counter {
942 value: precision.apply(crate::rng::u64() & RESEED_MASK, timestamp),
943 }
944 }
945946/// Advance the counter.
947#[inline]
948fn increment(&self, precision: &Precision, timestamp: &ReseedingTimestamp) -> Self {
949let mut counter = Counter {
950 value: precision.apply(self.value, timestamp),
951 };
952953// 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
957958 // Guaranteed to never overflow u64
959counter.value += 1;
960961 counter
962 }
963964#[inline]
965fn has_overflowed(&self) -> bool {
966self.value > MAX_COUNTER
967 }
968 }
969970/// A utility that adjusts an input timestamp by a given number of nanoseconds.
971#[derive(Debug)]
972struct Adjust {
973 by_ns: u128,
974 }
975976impl Adjust {
977#[inline]
978fn by_millis(millis: u32) -> Self {
979 Adjust {
980 by_ns: (millis as u128).saturating_mul(1_000_000),
981 }
982 }
983984/// Apply the adjustment, returning the adjusted timestamp.
985#[inline]
986fn apply(&self, seconds: u64, subsec_nanos: u32) -> (u64, u32) {
987if self.by_ns == 0 {
988// No shift applied
989return (seconds, subsec_nanos);
990 }
991992let ts = (seconds as u128)
993 .saturating_mul(1_000_000_000)
994 .saturating_add(subsec_nanos as u128)
995 .saturating_add(self.by_ns);
996997 ((ts / 1_000_000_000) as u64, (ts % 1_000_000_000) as u32)
998 }
999 }
10001001/// A utility that overwrites some number of counter bits with additional timestamp precision.
1002#[derive(Debug)]
1003struct Precision {
1004 bits: usize,
1005 factor: u64,
1006 mask: u64,
1007 shift: u64,
1008 }
10091010impl Precision {
1011fn 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
1014let mask = u64::MAX >> (64 - USABLE_BITS + bits);
1015let shift = (USABLE_BITS - bits) as u64;
10161017// The factor reduces the size of the sub-millisecond precision to
1018 // fit into the specified number of bits
1019let factor = (999_999 / u64::pow(2, bits as u32)) + 1;
10201021 Precision {
1022 bits,
1023 factor,
1024 mask,
1025 shift,
1026 }
1027 }
10281029/// Apply additional precision from the given timestamp to the counter.
1030#[inline]
1031fn apply(&self, counter: u64, timestamp: &ReseedingTimestamp) -> u64 {
1032if self.bits == 0 {
1033// No additional precision is being used
1034return counter;
1035 }
10361037let additional = timestamp.submilli_nanos() as u64 / self.factor;
10381039 (counter & self.mask) | (additional << self.shift)
1040 }
1041 }
10421043#[cfg(feature = "std")]
1044pub(crate) struct SharedContextV7(std::sync::Mutex<ContextV7>);
10451046#[cfg(feature = "std")]
1047impl ClockSequence for SharedContextV7 {
1048type Output = u64;
10491050fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output {
1051self.0.generate_sequence(seconds, subsec_nanos)
1052 }
10531054fn generate_timestamp_sequence(
1055&self,
1056 seconds: u64,
1057 subsec_nanos: u32,
1058 ) -> (Self::Output, u64, u32) {
1059self.0.generate_timestamp_sequence(seconds, subsec_nanos)
1060 }
10611062fn usable_bits(&self) -> usize
1063where
1064Self::Output: Sized,
1065 {
1066 USABLE_BITS
1067 }
1068 }
10691070#[cfg(test)]
1071mod tests {
1072use core::time::Duration;
10731074use super::*;
10751076use crate::{Timestamp, Uuid};
10771078#[test]
1079fn context() {
1080let seconds = 1_496_854_535;
1081let subsec_nanos = 812_946_000;
10821083let context = ContextV7::new();
10841085let ts1 = Timestamp::from_unix(&context, seconds, subsec_nanos);
1086assert_eq!(42, ts1.usable_counter_bits);
10871088// Backwards second
1089let seconds = 1_496_854_534;
10901091let ts2 = Timestamp::from_unix(&context, seconds, subsec_nanos);
10921093// The backwards time should be ignored
1094 // The counter should still increment
1095assert_eq!(ts1.seconds, ts2.seconds);
1096assert_eq!(ts1.subsec_nanos, ts2.subsec_nanos);
1097assert_eq!(ts1.counter + 1, ts2.counter);
10981099// Forwards second
1100let seconds = 1_496_854_536;
11011102let ts3 = Timestamp::from_unix(&context, seconds, subsec_nanos);
11031104// The counter should have reseeded
1105assert_ne!(ts2.counter + 1, ts3.counter);
1106assert_ne!(0, ts3.counter);
1107 }
11081109#[test]
1110fn context_wrap() {
1111let seconds = 1_496_854_535u64;
1112let subsec_nanos = 812_946_000u32;
11131114// This context will wrap
1115let 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 };
11281129let ts = Timestamp::from_unix(&context, seconds, subsec_nanos);
11301131// The timestamp should be incremented by 1ms
1132let expected_ts = Duration::new(seconds, subsec_nanos) + Duration::from_millis(1);
1133assert_eq!(expected_ts.as_secs(), ts.seconds);
1134assert_eq!(expected_ts.subsec_nanos(), ts.subsec_nanos);
11351136// The counter should have reseeded
1137assert!(ts.counter < (u64::MAX >> 22) as u128);
1138assert_ne!(0, ts.counter);
1139 }
11401141#[test]
1142fn context_shift() {
1143let seconds = 1_496_854_535;
1144let subsec_nanos = 812_946_000;
11451146let context = ContextV7::new().with_adjust_by_millis(1);
11471148let ts = Timestamp::from_unix(&context, seconds, subsec_nanos);
11491150assert_eq!((1_496_854_535, 813_946_000), ts.to_unix());
1151 }
11521153#[test]
1154fn context_additional_precision() {
1155let seconds = 1_496_854_535;
1156let subsec_nanos = 812_946_000;
11571158let context = ContextV7::new().with_additional_precision();
11591160let ts1 = Timestamp::from_unix(&context, seconds, subsec_nanos);
11611162// NOTE: Future changes in rounding may change this value slightly
1163assert_eq!(3861, ts1.counter >> 30);
11641165assert!(ts1.counter < (u64::MAX >> 22) as u128);
11661167// Generate another timestamp; it should continue to sort
1168let ts2 = Timestamp::from_unix(&context, seconds, subsec_nanos);
11691170assert!(Uuid::new_v7(ts2) > Uuid::new_v7(ts1));
11711172// Generate another timestamp with an extra nanosecond
1173let subsec_nanos = subsec_nanos + 1;
11741175let ts3 = Timestamp::from_unix(&context, seconds, subsec_nanos);
11761177assert!(Uuid::new_v7(ts3) > Uuid::new_v7(ts2));
1178 }
11791180#[test]
1181fn context_additional_precision_bits() {
1182let seconds = 1_496_854_535;
1183let subsec_nanos = 812_946_000;
11841185// 10 bits leaves the low 2 bits of `rand_a` for random data, which suits
1186 // platforms with microsecond precision
1187let context = ContextV7::new().with_additional_precision_bits(10);
11881189let ts = Timestamp::from_unix(&context, seconds, subsec_nanos);
11901191// The submillisecond precision occupies the leftmost 10 of the 42 counter bits
1192 // NOTE: Future changes in rounding may change this value slightly
1193assert_eq!(968, ts.counter >> 32);
11941195assert!(ts.counter < (u64::MAX >> 22) as u128);
11961197// The full method is just the 12-bit form of this one
1198let full = Timestamp::from_unix(
1199&ContextV7::new().with_additional_precision(),
1200 seconds,
1201 subsec_nanos,
1202 );
1203let bits12 = Timestamp::from_unix(
1204&ContextV7::new().with_additional_precision_bits(12),
1205 seconds,
1206 subsec_nanos,
1207 );
1208assert_eq!(full.counter >> 30, bits12.counter >> 30);
12091210// Values above 12 are capped at 12
1211let capped = Timestamp::from_unix(
1212&ContextV7::new().with_additional_precision_bits(64),
1213 seconds,
1214 subsec_nanos,
1215 );
1216assert_eq!(bits12.counter >> 30, capped.counter >> 30);
12171218// Zero bits disables additional precision entirely
1219let none = ContextV7::new().with_additional_precision_bits(0);
1220assert_eq!(0, none.precision.bits);
1221 }
12221223#[test]
1224fn context_overflow() {
1225let seconds = u64::MAX;
1226let subsec_nanos = u32::MAX;
12271228// Ensure we don't panic
1229for 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 }
12391240#[cfg(feature = "v7")]
1241pub use v7_support::*;
12421243/// 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)]
1254pub struct NoContext;
12551256impl ClockSequencefor NoContext {
1257type Output = u16;
12581259fn generate_sequence(&self, _seconds: u64, _nanos: u32) -> Self::Output {
12600
1261}
12621263fn usable_bits(&self) -> usize {
12640
1265}
1266 }
1267}
12681269#[cfg(all(test, any(feature = "v1", feature = "v6")))]
1270mod tests {
1271use super::*;
12721273#[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))]
1274use wasm_bindgen_test::*;
12751276#[test]
1277 #[cfg_attr(
1278 all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")),
1279 wasm_bindgen_test
1280 )]
1281fn gregorian_unix_does_not_panic() {
1282// Ensure timestamp conversions never panic
1283Timestamp::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);
12861287 Timestamp::gregorian_to_unix(u64::MAX);
1288 }
12891290#[test]
1291 #[cfg_attr(
1292 all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")),
1293 wasm_bindgen_test
1294 )]
1295fn to_gregorian_truncates_to_usable_bits() {
1296let ts = Timestamp::from_gregorian_time(123, u16::MAX);
12971298assert_eq!((123, u16::MAX >> 2), ts.to_gregorian());
1299 }
13001301#[test]
1302 #[cfg_attr(
1303 all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")),
1304 wasm_bindgen_test
1305 )]
1306fn clock_sequence_usable_bits() {
1307struct MyContext;
13081309impl ClockSequence for MyContext {
1310type Output = u16;
13111312fn generate_sequence(&self, _: u64, _: u32) -> Self::Output {
13130
1314}
1315 }
13161317assert_eq!(16, MyContext.usable_bits());
1318 }
13191320#[cfg(all(test, feature = "std", not(miri)))]
1321mod std_support {
1322use super::*;
13231324use std::time::{Duration, SystemTime};
13251326// Components of an arbitrary timestamp with non-zero nanoseconds.
1327const KNOWN_SECONDS: u64 = 1_501_520_400;
1328const KNOWN_NANOS: u32 = 1_000;
13291330fn known_system_time() -> SystemTime {
1331 SystemTime::UNIX_EPOCH
1332 .checked_add(Duration::new(KNOWN_SECONDS, KNOWN_NANOS))
1333 .unwrap()
1334 }
13351336fn known_timestamp() -> Timestamp {
1337 Timestamp::from_unix_time(KNOWN_SECONDS, KNOWN_NANOS, 0, 0)
1338 }
13391340#[test]
1341fn to_system_time() {
1342let st: SystemTime = known_timestamp().into();
13431344assert_eq!(known_system_time(), st);
1345 }
13461347#[test]
1348fn from_system_time() {
1349let ts: Timestamp = known_system_time().try_into().unwrap();
13501351assert_eq!(known_timestamp(), ts);
1352 }
13531354#[test]
1355fn from_system_time_before_epoch() {
1356let before_epoch = match SystemTime::UNIX_EPOCH.checked_sub(Duration::from_nanos(1_000))
1357 {
1358Some(st) => st,
1359None => return,
1360 };
13611362 Timestamp::try_from(before_epoch)
1363 .expect_err("Timestamp should not be created from before epoch");
1364 }
13651366#[test]
1367fn from_system_time_max() {
1368let ts = Timestamp::from_unix_time(u64::MAX, 999_999_999, 0, 0);
13691370// Just make sure we don't panic
1371let _: SystemTime = ts.into();
1372 }
1373 }
1374}