1use core::cmp;
25
26use crate::Uuid;
27
28pub const UUID_TICKS_BETWEEN_EPOCHS: u64 = 0x01B2_1DD2_1381_4000;
31
32#[derive(#[automatically_derived]impl ::core::fmt::Debug for Timestamp {
#[inline]
#[rustc_trivial_field_reads]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field3_finish(f,
"Timestamp unix_nanos counter usable_counter_bits",
&self.unix_nanos, &self.counter, &&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]
#[rustc_trivial_field_reads]
fn clone(&self) -> Self {
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: &Self) -> bool {
self.unix_nanos == other.unix_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<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.unix_nanos, state);
::core::hash::Hash::hash(&self.counter, state);
::core::hash::Hash::hash(&self.usable_counter_bits, state)
}
}Hash)]
43pub struct Timestamp {
44 unix_nanos: u128,
45 counter: u128,
46 usable_counter_bits: u8,
47}
48
49impl Timestamp {
50 #[cfg(feature = "std")]
54 pub fn now(context: impl ClockSequence<Output = impl Into<u128>>) -> Self {
55 let (seconds, subsec_nanos) = nanos_to_parts(now());
56
57 let (counter, seconds, subsec_nanos) =
58 context.generate_timestamp_sequence(seconds, subsec_nanos);
59 let counter = counter.into();
60 let usable_counter_bits = context.usable_bits() as u8;
61
62 Timestamp {
63 unix_nanos: parts_to_nanos(seconds, subsec_nanos),
64 counter,
65 usable_counter_bits,
66 }
67 }
68
69 pub const fn from_gregorian_time(ticks: u64, counter: u16) -> Self {
78 let (seconds, subsec_nanos) = Self::gregorian_to_unix(ticks);
79
80 Timestamp {
81 unix_nanos: parts_to_nanos(seconds, subsec_nanos),
82 counter: counter as u128,
83 usable_counter_bits: 14,
84 }
85 }
86
87 pub const fn from_unix_time(
89 seconds: u64,
90 subsec_nanos: u32,
91 counter: u128,
92 usable_counter_bits: u8,
93 ) -> Self {
94 Timestamp {
95 unix_nanos: parts_to_nanos(seconds, subsec_nanos),
96 counter,
97 usable_counter_bits,
98 }
99 }
100
101 pub fn from_unix(
103 context: impl ClockSequence<Output = impl Into<u128>>,
104 seconds: u64,
105 subsec_nanos: u32,
106 ) -> Self {
107 let (counter, seconds, subsec_nanos) =
108 context.generate_timestamp_sequence(seconds, subsec_nanos);
109 let counter = counter.into();
110 let usable_counter_bits = context.usable_bits() as u8;
111
112 Timestamp {
113 unix_nanos: parts_to_nanos(seconds, subsec_nanos),
114 counter,
115 usable_counter_bits,
116 }
117 }
118
119 pub const fn to_gregorian(&self) -> (u64, u16) {
129 let (seconds, subsec_nanos) = nanos_to_parts(self.unix_nanos);
130
131 (
132 Self::unix_to_gregorian_ticks(seconds, subsec_nanos),
133 (self.counter as u16) & 0x3FFF,
134 )
135 }
136
137 #[cfg(feature = "v7")]
140 pub(crate) const fn counter(&self) -> (u128, u8) {
141 (self.counter, self.usable_counter_bits)
142 }
143
144 pub const fn to_unix(&self) -> (u64, u32) {
146 nanos_to_parts(self.unix_nanos)
147 }
148
149 const fn unix_to_gregorian_ticks(seconds: u64, nanos: u32) -> u64 {
150 UUID_TICKS_BETWEEN_EPOCHS
151 .wrapping_add(seconds.wrapping_mul(10_000_000))
152 .wrapping_add(nanos as u64 / 100)
153 }
154
155 const fn gregorian_to_unix(ticks: u64) -> (u64, u32) {
156 (
157 ticks.wrapping_sub(UUID_TICKS_BETWEEN_EPOCHS) / 10_000_000,
158 (ticks.wrapping_sub(UUID_TICKS_BETWEEN_EPOCHS) % 10_000_000) as u32 * 100,
159 )
160 }
161}
162
163#[doc(hidden)]
164impl Timestamp {
165 #[deprecated(
166 since = "1.10.0",
167 note = "use `Timestamp::from_gregorian_time(ticks, counter)`"
168 )]
169 pub const fn from_rfc4122(ticks: u64, counter: u16) -> Self {
170 Timestamp::from_gregorian_time(ticks, counter)
171 }
172
173 #[deprecated(since = "1.10.0", note = "use `Timestamp::to_gregorian()`")]
174 pub const fn to_rfc4122(&self) -> (u64, u16) {
175 self.to_gregorian()
176 }
177
178 #[deprecated(
179 since = "1.2.0",
180 note = "`Timestamp::to_unix_nanos()` is deprecated and will be removed: use `Timestamp::to_unix()`"
181 )]
182 pub const fn to_unix_nanos(&self) -> u32 {
183 {
::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()`")
184 }
185
186 #[deprecated(
187 since = "1.23.0",
188 note = "use `Timestamp::from_gregorian_time(ticks, counter)`"
189 )]
190 pub const fn from_gregorian(ticks: u64, counter: u16) -> Self {
191 Timestamp::from_gregorian_time(ticks, counter)
192 }
193}
194
195#[cfg(feature = "std")]
196impl TryFrom<std::time::SystemTime> for Timestamp {
197 type Error = crate::Error;
198
199 fn try_from(st: std::time::SystemTime) -> Result<Self, Self::Error> {
204 let dur = st.duration_since(std::time::UNIX_EPOCH).map_err(|_| {
205 crate::Error(crate::error::ErrorKind::InvalidSystemTime(
206 "unable to convert the system tie into a Unix timestamp",
207 ))
208 })?;
209
210 Ok(Self::from_unix_time(
211 dur.as_secs(),
212 dur.subsec_nanos(),
213 0,
214 0,
215 ))
216 }
217}
218
219#[cfg(feature = "std")]
220impl From<Timestamp> for std::time::SystemTime {
221 fn from(ts: Timestamp) -> Self {
227 let (seconds, subsec_nanos) = ts.to_unix();
228
229 std::time::Duration::from_secs(seconds)
232 .checked_add(std::time::Duration::from_nanos(subsec_nanos as u64))
233 .and_then(|dur| Self::UNIX_EPOCH.checked_add(dur))
234 .unwrap_or(std::time::SystemTime::UNIX_EPOCH)
235 }
236}
237
238pub(crate) const fn encode_gregorian_timestamp(
239 ticks: u64,
240 counter: u16,
241 node_id: &[u8; 6],
242) -> Uuid {
243 let time_low = (ticks & 0xFFFF_FFFF) as u32;
244 let time_mid = ((ticks >> 32) & 0xFFFF) as u16;
245 let time_high_and_version = (((ticks >> 48) & 0x0FFF) as u16) | (1 << 12);
246
247 let mut d4 = [0; 8];
248
249 d4[0] = (((counter & 0x3F00) >> 8) as u8) | 0x80;
250 d4[1] = (counter & 0xFF) as u8;
251 d4[2] = node_id[0];
252 d4[3] = node_id[1];
253 d4[4] = node_id[2];
254 d4[5] = node_id[3];
255 d4[6] = node_id[4];
256 d4[7] = node_id[5];
257
258 Uuid::from_fields(time_low, time_mid, time_high_and_version, &d4)
259}
260
261pub(crate) const fn decode_gregorian_timestamp(uuid: &Uuid) -> (u64, u16) {
262 let bytes = uuid.as_bytes();
263
264 let ticks: u64 = ((bytes[6] & 0x0F) as u64) << 56
265 | (bytes[7] as u64) << 48
266 | (bytes[4] as u64) << 40
267 | (bytes[5] as u64) << 32
268 | (bytes[0] as u64) << 24
269 | (bytes[1] as u64) << 16
270 | (bytes[2] as u64) << 8
271 | (bytes[3] as u64);
272
273 let counter: u16 = ((bytes[8] & 0x3F) as u16) << 8 | (bytes[9] as u16);
274
275 (ticks, counter)
276}
277
278pub(crate) const fn encode_sorted_gregorian_timestamp(
279 ticks: u64,
280 counter: u16,
281 node_id: &[u8; 6],
282) -> Uuid {
283 let time_high = ((ticks >> 28) & 0xFFFF_FFFF) as u32;
284 let time_mid = ((ticks >> 12) & 0xFFFF) as u16;
285 let time_low_and_version = ((ticks & 0x0FFF) as u16) | (0x6 << 12);
286
287 let mut d4 = [0; 8];
288
289 d4[0] = (((counter & 0x3F00) >> 8) as u8) | 0x80;
290 d4[1] = (counter & 0xFF) as u8;
291 d4[2] = node_id[0];
292 d4[3] = node_id[1];
293 d4[4] = node_id[2];
294 d4[5] = node_id[3];
295 d4[6] = node_id[4];
296 d4[7] = node_id[5];
297
298 Uuid::from_fields(time_high, time_mid, time_low_and_version, &d4)
299}
300
301pub(crate) const fn decode_sorted_gregorian_timestamp(uuid: &Uuid) -> (u64, u16) {
302 let bytes = uuid.as_bytes();
303
304 let ticks: u64 = ((bytes[0]) as u64) << 52
305 | (bytes[1] as u64) << 44
306 | (bytes[2] as u64) << 36
307 | (bytes[3] as u64) << 28
308 | (bytes[4] as u64) << 20
309 | (bytes[5] as u64) << 12
310 | ((bytes[6] & 0xF) as u64) << 8
311 | (bytes[7] as u64);
312
313 let counter: u16 = ((bytes[8] & 0x3F) as u16) << 8 | (bytes[9] as u16);
314
315 (ticks, counter)
316}
317
318pub(crate) const fn encode_unix_timestamp_millis(
319 millis: u64,
320 counter_random_bytes: &[u8; 10],
321) -> Uuid {
322 let millis_high = ((millis >> 16) & 0xFFFF_FFFF) as u32;
323 let millis_low = (millis & 0xFFFF) as u16;
324
325 let counter_random_version = (counter_random_bytes[1] as u16
326 | ((counter_random_bytes[0] as u16) << 8) & 0x0FFF)
327 | (0x7 << 12);
328
329 let mut d4 = [0; 8];
330
331 d4[0] = (counter_random_bytes[2] & 0x3F) | 0x80;
332 d4[1] = counter_random_bytes[3];
333 d4[2] = counter_random_bytes[4];
334 d4[3] = counter_random_bytes[5];
335 d4[4] = counter_random_bytes[6];
336 d4[5] = counter_random_bytes[7];
337 d4[6] = counter_random_bytes[8];
338 d4[7] = counter_random_bytes[9];
339
340 Uuid::from_fields(millis_high, millis_low, counter_random_version, &d4)
341}
342
343pub(crate) const fn decode_unix_timestamp_millis(uuid: &Uuid) -> u64 {
344 let bytes = uuid.as_bytes();
345
346 let millis: u64 = (bytes[0] as u64) << 40
347 | (bytes[1] as u64) << 32
348 | (bytes[2] as u64) << 24
349 | (bytes[3] as u64) << 16
350 | (bytes[4] as u64) << 8
351 | (bytes[5] as u64);
352
353 millis
354}
355
356#[cfg(all(
357 feature = "std",
358 feature = "js",
359 all(target_family = "wasm", any(target_os = "unknown", target_os = "none"))
360))]
361fn now() -> u128 {
362 use wasm_bindgen::prelude::*;
363
364 #[wasm_bindgen]
365 extern "C" {
366 #[wasm_bindgen(js_namespace = Date, catch)]
368 fn now() -> Result<f64, JsValue>;
369 }
370
371 let now = now().unwrap_throw();
372
373 (now * 1_000_000.0) as u128
374}
375
376#[cfg(all(
377 feature = "std",
378 not(miri),
379 any(
380 not(feature = "js"),
381 not(all(target_family = "wasm", any(target_os = "unknown", target_os = "none")))
382 )
383))]
384fn now() -> u128 {
385 let dur = std::time::SystemTime::UNIX_EPOCH.elapsed().expect(
386 "Getting elapsed time since UNIX_EPOCH. If this fails, we've somehow violated causality",
387 );
388
389 dur.as_nanos()
390}
391
392#[cfg(all(feature = "std", miri))]
393fn now() -> u128 {
394 use std::{sync::Mutex, time::Duration};
395
396 static TS: Mutex<u128> = Mutex::new(0);
397
398 let mut ts = TS.lock().unwrap();
399 *ts += 1;
400 *ts
401}
402
403const fn nanos_to_parts(nanos: u128) -> (u64, u32) {
413 const MAX_NANOS: u128 = parts_to_nanos(u64::MAX, u32::MAX);
414
415 if nanos > MAX_NANOS {
416 return (u64::MAX, u32::MAX);
417 }
418
419 let secs = nanos / 1_000_000_000;
420
421 if secs > u64::MAX as u128 {
422 (u64::MAX, (nanos - u64::MAX as u128 * 1_000_000_000) as u32)
424 } else {
425 (secs as u64, (nanos % 1_000_000_000) as u32)
426 }
427}
428
429const fn parts_to_nanos(secs: u64, subsec_nanos: u32) -> u128 {
436 (secs as u128 * 1_000_000_000) + subsec_nanos as u128
437}
438
439pub trait ClockSequence {
448 type Output;
450
451 fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output;
462
463 fn generate_timestamp_sequence(
477 &self,
478 seconds: u64,
479 subsec_nanos: u32,
480 ) -> (Self::Output, u64, u32) {
481 (
482 self.generate_sequence(seconds, subsec_nanos),
483 seconds,
484 subsec_nanos,
485 )
486 }
487
488 fn usable_bits(&self) -> usize
496 where
497 Self::Output: Sized,
498 {
499 cmp::min(128, core::mem::size_of::<Self::Output>() * 8)
500 }
501}
502
503impl<T: ClockSequence + ?Sized> ClockSequence for &T {
504 type Output = T::Output;
505
506 fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output {
507 (**self).generate_sequence(seconds, subsec_nanos)
508 }
509
510 fn generate_timestamp_sequence(
511 &self,
512 seconds: u64,
513 subsec_nanos: u32,
514 ) -> (Self::Output, u64, u32) {
515 (**self).generate_timestamp_sequence(seconds, subsec_nanos)
516 }
517
518 fn usable_bits(&self) -> usize
519 where
520 Self::Output: Sized,
521 {
522 (**self).usable_bits()
523 }
524}
525
526pub mod context {
528 use super::ClockSequence;
529
530 #[cfg(any(feature = "v1", feature = "v6"))]
531 mod v1_support {
532 use super::*;
533
534 #[cfg(all(feature = "std", feature = "rng"))]
535 use crate::std::sync::LazyLock;
536
537 use atomic::{Atomic, Ordering};
538
539 #[cfg(all(feature = "std", feature = "rng"))]
540 static CONTEXT: LazyLock<ContextV1> = LazyLock::new(ContextV1::new_random);
541
542 #[cfg(all(feature = "std", feature = "rng"))]
543 pub(crate) fn shared_context_v1() -> &'static ContextV1 {
544 &CONTEXT
545 }
546
547 #[derive(Debug)]
563 pub struct ContextV1 {
564 count: Atomic<u16>,
565 }
566
567 impl ContextV1 {
568 pub const fn new(count: u16) -> Self {
574 Self {
575 count: Atomic::<u16>::new(count),
576 }
577 }
578
579 #[cfg(feature = "rng")]
581 pub fn new_random() -> Self {
582 Self {
583 count: Atomic::<u16>::new(crate::rng::u16()),
584 }
585 }
586 }
587
588 impl ClockSequence for ContextV1 {
589 type Output = u16;
590
591 fn generate_sequence(&self, _seconds: u64, _nanos: u32) -> Self::Output {
592 self.count.fetch_add(1, Ordering::AcqRel) & (u16::MAX >> 2)
598 }
599
600 fn usable_bits(&self) -> usize {
601 14
602 }
603 }
604
605 #[deprecated(since = "1.23.0", note = "renamed to `ContextV1`")]
606 #[doc(hidden)]
607 pub type Context = ContextV1;
608
609 #[cfg(test)]
610 mod tests {
611 use crate::Timestamp;
612
613 use super::*;
614
615 #[test]
616 fn context() {
617 let seconds = 1_496_854_535;
618 let subsec_nanos = 812_946_000;
619
620 let context = ContextV1::new(u16::MAX >> 2);
621
622 let ts = Timestamp::from_unix(&context, seconds, subsec_nanos);
623 assert_eq!(16383, ts.counter);
624 assert_eq!(14, ts.usable_counter_bits);
625
626 let seconds = 1_496_854_536;
627
628 let ts = Timestamp::from_unix(&context, seconds, subsec_nanos);
629 assert_eq!(0, ts.counter);
630
631 let seconds = 1_496_854_535;
632
633 let ts = Timestamp::from_unix(&context, seconds, subsec_nanos);
634 assert_eq!(1, ts.counter);
635 }
636
637 #[test]
638 fn context_overflow() {
639 let seconds = u64::MAX;
640 let subsec_nanos = u32::MAX;
641
642 let context = ContextV1::new(u16::MAX);
643
644 Timestamp::from_unix(&context, seconds, subsec_nanos);
646 }
647 }
648 }
649
650 #[cfg(any(feature = "v1", feature = "v6"))]
651 pub use v1_support::*;
652
653 #[cfg(feature = "std")]
654 mod std_support {
655 use super::*;
656
657 use core::panic::{AssertUnwindSafe, RefUnwindSafe};
658 use std::{sync::Mutex, thread::LocalKey};
659
660 pub struct ThreadLocalContext<C: 'static>(&'static LocalKey<C>);
662
663 impl<C> std::fmt::Debug for ThreadLocalContext<C> {
664 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
665 f.debug_struct("ThreadLocalContext").finish_non_exhaustive()
666 }
667 }
668
669 impl<C: 'static> ThreadLocalContext<C> {
670 pub const fn new(local_key: &'static LocalKey<C>) -> Self {
672 ThreadLocalContext(local_key)
673 }
674 }
675
676 impl<C: ClockSequence + 'static> ClockSequence for ThreadLocalContext<C> {
677 type Output = C::Output;
678
679 fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output {
680 self.0
681 .with(|ctxt| ctxt.generate_sequence(seconds, subsec_nanos))
682 }
683
684 fn generate_timestamp_sequence(
685 &self,
686 seconds: u64,
687 subsec_nanos: u32,
688 ) -> (Self::Output, u64, u32) {
689 self.0
690 .with(|ctxt| ctxt.generate_timestamp_sequence(seconds, subsec_nanos))
691 }
692
693 fn usable_bits(&self) -> usize {
694 self.0.with(|ctxt| ctxt.usable_bits())
695 }
696 }
697
698 impl<C: ClockSequence> ClockSequence for AssertUnwindSafe<C> {
699 type Output = C::Output;
700
701 fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output {
702 self.0.generate_sequence(seconds, subsec_nanos)
703 }
704
705 fn generate_timestamp_sequence(
706 &self,
707 seconds: u64,
708 subsec_nanos: u32,
709 ) -> (Self::Output, u64, u32) {
710 self.0.generate_timestamp_sequence(seconds, subsec_nanos)
711 }
712
713 fn usable_bits(&self) -> usize
714 where
715 Self::Output: Sized,
716 {
717 self.0.usable_bits()
718 }
719 }
720
721 impl<C: ClockSequence + RefUnwindSafe> ClockSequence for Mutex<C> {
722 type Output = C::Output;
723
724 fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output {
725 self.lock()
726 .unwrap_or_else(|err| err.into_inner())
727 .generate_sequence(seconds, subsec_nanos)
728 }
729
730 fn generate_timestamp_sequence(
731 &self,
732 seconds: u64,
733 subsec_nanos: u32,
734 ) -> (Self::Output, u64, u32) {
735 self.lock()
736 .unwrap_or_else(|err| err.into_inner())
737 .generate_timestamp_sequence(seconds, subsec_nanos)
738 }
739
740 fn usable_bits(&self) -> usize
741 where
742 Self::Output: Sized,
743 {
744 self.lock()
745 .unwrap_or_else(|err| err.into_inner())
746 .usable_bits()
747 }
748 }
749 }
750
751 #[cfg(feature = "std")]
752 pub use std_support::*;
753
754 #[cfg(feature = "v7")]
755 mod v7_support {
756 use super::*;
757
758 use crate::timestamp::parts_to_nanos;
759 use core::{cell::Cell, cmp, panic::RefUnwindSafe};
760
761 #[cfg(feature = "std")]
762 static CONTEXT_V7: SharedContextV7 =
763 SharedContextV7(std::sync::Mutex::new(ContextV7::new()));
764
765 #[cfg(feature = "std")]
766 pub(crate) fn shared_context_v7() -> &'static SharedContextV7 {
767 &CONTEXT_V7
768 }
769
770 const USABLE_BITS: usize = 42;
771
772 const RESEED_MASK: u64 = u64::MAX >> 23;
777 const MAX_COUNTER: u64 = u64::MAX >> 22;
778
779 #[derive(Debug, Default)]
805 pub struct ContextV7 {
806 timestamp: Cell<ReseedingTimestamp>,
807 counter: Cell<Counter>,
808 adjust: Adjust,
809 precision: Precision,
810 }
811
812 impl RefUnwindSafe for ContextV7 {}
813
814 impl ContextV7 {
815 pub const fn new() -> Self {
818 ContextV7 {
819 timestamp: Cell::new(ReseedingTimestamp {
820 last_seed: 0,
821 unix_nanos: 0,
822 }),
823 counter: Cell::new(Counter { value: 0 }),
824 adjust: Adjust { by_ns: 0 },
825 precision: Precision {
826 bits: 0,
827 mask: 0,
828 factor: 0,
829 shift: 0,
830 },
831 }
832 }
833
834 pub fn with_adjust_by_millis(mut self, millis: u32) -> Self {
836 self.adjust = Adjust::by_millis(millis);
837 self
838 }
839
840 pub fn with_additional_precision(self) -> Self {
847 self.with_additional_precision_bits(12)
848 }
849
850 pub fn with_additional_precision_bits(mut self, bits: usize) -> Self {
860 self.precision = Precision::new(cmp::min(bits, 12));
861 self
862 }
863 }
864
865 impl ClockSequence for ContextV7 {
866 type Output = u64;
867
868 fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output {
869 self.generate_timestamp_sequence(seconds, subsec_nanos).0
870 }
871
872 fn generate_timestamp_sequence(
873 &self,
874 seconds: u64,
875 subsec_nanos: u32,
876 ) -> (Self::Output, u64, u32) {
877 let unix_nanos = self.adjust.apply(parts_to_nanos(seconds, subsec_nanos));
878
879 let mut counter;
880 let (mut timestamp, should_reseed) = self.timestamp.get().advance(unix_nanos);
881
882 if should_reseed {
883 counter = Counter::reseed(&self.precision, ×tamp);
885 } else {
886 counter = self.counter.get().increment(&self.precision, ×tamp);
893
894 if counter.has_overflowed() {
898 timestamp = timestamp.increment();
900 counter = Counter::reseed(&self.precision, ×tamp);
901 }
902 };
903
904 self.timestamp.set(timestamp);
905 self.counter.set(counter);
906
907 let (seconds, subsec_nanos) = timestamp.to_parts();
908
909 (counter.value, seconds, subsec_nanos)
910 }
911
912 fn usable_bits(&self) -> usize {
913 USABLE_BITS
914 }
915 }
916
917 #[derive(Debug, Default, Clone, Copy)]
919 struct ReseedingTimestamp {
920 last_seed: u64,
921 unix_nanos: u128,
922 }
923
924 impl ReseedingTimestamp {
925 #[inline]
926 fn saturating_from_unix_nanos(unix_nanos: u128) -> Self {
927 const MAX_UNIX_NANOS: u128 = (u64::MAX as u128) * 1_000_000 + 999_999;
928
929 let unix_nanos = cmp::min(unix_nanos, MAX_UNIX_NANOS);
930
931 let last_seed = (unix_nanos / 1_000_000) as u64;
933
934 ReseedingTimestamp {
935 last_seed,
936 unix_nanos,
937 }
938 }
939
940 #[inline]
941 fn to_parts(&self) -> (u64, u32) {
942 (
944 (self.unix_nanos / 1_000_000_000) as u64,
945 (self.unix_nanos % 1_000_000_000) as u32,
946 )
947 }
948
949 #[inline]
951 fn advance(&self, unix_nanos: u128) -> (Self, bool) {
952 let incoming = ReseedingTimestamp::saturating_from_unix_nanos(unix_nanos);
953
954 (
955 ReseedingTimestamp::saturating_from_unix_nanos(cmp::max(
956 self.unix_nanos,
957 unix_nanos,
958 )),
959 incoming.last_seed > self.last_seed,
960 )
961 }
962
963 #[inline]
965 fn increment(&self) -> Self {
966 ReseedingTimestamp::saturating_from_unix_nanos(
967 Adjust::by_millis(1).apply(self.unix_nanos),
968 )
969 }
970 }
971
972 #[derive(Debug, Default, Clone, Copy)]
974 struct Counter {
975 value: u64,
976 }
977
978 impl Counter {
979 #[inline]
980 fn reseed(precision: &Precision, timestamp: &ReseedingTimestamp) -> Self {
981 Counter {
982 value: precision.apply(crate::rng::u64() & RESEED_MASK, timestamp),
983 }
984 }
985
986 #[inline]
992 fn increment(&self, precision: &Precision, timestamp: &ReseedingTimestamp) -> Self {
993 let next = self.value + 1;
1000
1001 Counter {
1002 value: cmp::max(next, precision.apply(next, timestamp)),
1003 }
1004 }
1005
1006 #[inline]
1007 fn has_overflowed(&self) -> bool {
1008 self.value > MAX_COUNTER
1009 }
1010 }
1011
1012 #[derive(Debug, Default)]
1014 struct Adjust {
1015 by_ns: u128,
1016 }
1017
1018 impl Adjust {
1019 #[inline]
1020 fn by_millis(millis: u32) -> Self {
1021 Adjust {
1022 by_ns: (millis as u128).saturating_mul(1_000_000),
1023 }
1024 }
1025
1026 #[inline]
1028 fn apply(&self, nanos: u128) -> u128 {
1029 nanos.saturating_add(self.by_ns)
1030 }
1031 }
1032
1033 #[derive(Debug, Default)]
1035 struct Precision {
1036 bits: usize,
1037 factor: u64,
1038 mask: u64,
1039 shift: u64,
1040 }
1041
1042 impl Precision {
1043 fn new(bits: usize) -> Self {
1044 let mask = u64::MAX >> (64 - USABLE_BITS + bits);
1047 let shift = (USABLE_BITS - bits) as u64;
1048
1049 let factor = (999_999 / u64::pow(2, bits as u32)) + 1;
1052
1053 Precision {
1054 bits,
1055 factor,
1056 mask,
1057 shift,
1058 }
1059 }
1060
1061 #[inline]
1063 fn apply(&self, counter: u64, timestamp: &ReseedingTimestamp) -> u64 {
1064 if self.bits == 0 {
1065 return counter;
1067 }
1068
1069 let additional = (timestamp.unix_nanos % 1_000_000) as u64 / self.factor;
1070
1071 (counter & self.mask) | (additional << self.shift)
1072 }
1073 }
1074
1075 #[cfg(feature = "std")]
1076 pub(crate) struct SharedContextV7(std::sync::Mutex<ContextV7>);
1077
1078 #[cfg(feature = "std")]
1079 impl ClockSequence for SharedContextV7 {
1080 type Output = u64;
1081
1082 fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output {
1083 self.0.generate_sequence(seconds, subsec_nanos)
1084 }
1085
1086 fn generate_timestamp_sequence(
1087 &self,
1088 seconds: u64,
1089 subsec_nanos: u32,
1090 ) -> (Self::Output, u64, u32) {
1091 self.0.generate_timestamp_sequence(seconds, subsec_nanos)
1092 }
1093
1094 fn usable_bits(&self) -> usize
1095 where
1096 Self::Output: Sized,
1097 {
1098 USABLE_BITS
1099 }
1100 }
1101
1102 #[cfg(test)]
1103 mod tests {
1104 use core::time::Duration;
1105 use std::boxed::Box;
1106
1107 use super::*;
1108
1109 use crate::{Timestamp, Uuid};
1110
1111 fn builder(f: impl Fn() -> ContextV7 + 'static) -> Box<dyn Fn() -> ContextV7> {
1112 Box::new(f)
1113 }
1114
1115 #[test]
1116 fn context() {
1117 let seconds = 1_496_854_535;
1118 let subsec_nanos = 812_946_000;
1119
1120 let context = ContextV7::new();
1121
1122 let ts1 = Timestamp::from_unix(&context, seconds, subsec_nanos);
1123 assert_eq!(42, ts1.usable_counter_bits);
1124
1125 let seconds = 1_496_854_534;
1127
1128 let ts2 = Timestamp::from_unix(&context, seconds, subsec_nanos);
1129
1130 assert_eq!(ts1.unix_nanos, ts2.unix_nanos);
1133 assert_eq!(ts1.counter + 1, ts2.counter);
1134
1135 let seconds = 1_496_854_536;
1137
1138 let ts3 = Timestamp::from_unix(&context, seconds, subsec_nanos);
1139
1140 assert_ne!(ts2.counter + 1, ts3.counter);
1142 assert_ne!(0, ts3.counter);
1143 }
1144
1145 #[test]
1146 fn context_wrap() {
1147 let seconds = 1_496_854_535u64;
1148 let subsec_nanos = 812_946_000u32;
1149
1150 let context = ContextV7 {
1152 timestamp: Cell::new(ReseedingTimestamp::saturating_from_unix_nanos(
1153 parts_to_nanos(seconds, subsec_nanos),
1154 )),
1155 adjust: Adjust::by_millis(0),
1156 precision: Precision {
1157 bits: 0,
1158 mask: 0,
1159 factor: 0,
1160 shift: 0,
1161 },
1162 counter: Cell::new(Counter {
1163 value: u64::MAX >> 22,
1164 }),
1165 };
1166
1167 let ts = Timestamp::from_unix(&context, seconds, subsec_nanos);
1168
1169 let expected_ts = Duration::new(seconds, subsec_nanos) + Duration::from_millis(1);
1171 assert_eq!(expected_ts.as_secs(), ts.to_unix().0);
1172 assert_eq!(expected_ts.subsec_nanos(), ts.to_unix().1);
1173
1174 assert!(ts.counter < (u64::MAX >> 22) as u128);
1176 assert_ne!(0, ts.counter);
1177 }
1178
1179 #[test]
1180 fn context_shift() {
1181 let seconds = 1_496_854_535;
1182 let subsec_nanos = 812_946_000;
1183
1184 let context = ContextV7::new().with_adjust_by_millis(1);
1185
1186 let ts = Timestamp::from_unix(&context, seconds, subsec_nanos);
1187
1188 assert_eq!((1_496_854_535, 813_946_000), ts.to_unix());
1189 }
1190
1191 #[test]
1192 fn context_additional_precision() {
1193 let seconds = 1_496_854_535;
1194 let subsec_nanos = 812_946_000;
1195
1196 let context = ContextV7::new().with_additional_precision();
1197
1198 let ts1 = Timestamp::from_unix(&context, seconds, subsec_nanos);
1199
1200 assert_eq!(3861, ts1.counter >> 30);
1202
1203 assert!(ts1.counter < (u64::MAX >> 22) as u128);
1204
1205 let ts2 = Timestamp::from_unix(&context, seconds, subsec_nanos);
1207
1208 assert!(Uuid::new_v7(ts2) > Uuid::new_v7(ts1));
1209
1210 let subsec_nanos = subsec_nanos + 1;
1212
1213 let ts3 = Timestamp::from_unix(&context, seconds, subsec_nanos);
1214
1215 assert!(Uuid::new_v7(ts3) > Uuid::new_v7(ts2));
1216 }
1217
1218 #[test]
1219 fn context_additional_precision_bits() {
1220 let seconds = 1_496_854_535;
1221 let subsec_nanos = 812_946_000;
1222
1223 let context = ContextV7::new().with_additional_precision_bits(10);
1226
1227 let ts = Timestamp::from_unix(&context, seconds, subsec_nanos);
1228
1229 assert_eq!(968, ts.counter >> 32);
1232
1233 assert!(ts.counter < (u64::MAX >> 22) as u128);
1234
1235 let full = Timestamp::from_unix(
1237 &ContextV7::new().with_additional_precision(),
1238 seconds,
1239 subsec_nanos,
1240 );
1241 let bits12 = Timestamp::from_unix(
1242 &ContextV7::new().with_additional_precision_bits(12),
1243 seconds,
1244 subsec_nanos,
1245 );
1246 assert_eq!(full.counter >> 30, bits12.counter >> 30);
1247
1248 let capped = Timestamp::from_unix(
1250 &ContextV7::new().with_additional_precision_bits(64),
1251 seconds,
1252 subsec_nanos,
1253 );
1254 assert_eq!(bits12.counter >> 30, capped.counter >> 30);
1255
1256 let none = ContextV7::new().with_additional_precision_bits(0);
1258 assert_eq!(0, none.precision.bits);
1259 }
1260
1261 #[test]
1262 fn context_additional_precision_carry() {
1263 let seconds = 1_496_854_535;
1264 let subsec_nanos = 812_946_000;
1265
1266 for bits in 1..=12 {
1267 let precision = Precision::new(bits);
1268 let timestamp = ReseedingTimestamp::saturating_from_unix_nanos(parts_to_nanos(
1269 seconds,
1270 subsec_nanos,
1271 ));
1272
1273 let context = ContextV7 {
1275 counter: Cell::new(Counter {
1276 value: precision.apply(u64::MAX, ×tamp),
1277 }),
1278 timestamp: Cell::new(timestamp),
1279 adjust: Adjust::by_millis(0),
1280 precision,
1281 };
1282
1283 let a = Timestamp::from_unix(&context, seconds, subsec_nanos);
1284 let b = Timestamp::from_unix(&context, seconds, subsec_nanos);
1285 let c = Timestamp::from_unix(&context, seconds, subsec_nanos);
1286
1287 assert!(Uuid::new_v7(a) < Uuid::new_v7(b), "a: {a:?} < b: {b:?}");
1288 assert!(Uuid::new_v7(b) < Uuid::new_v7(c), "b: {b:?} < c: {c:?}");
1289 }
1290 }
1291
1292 #[test]
1293 fn context_overflow() {
1294 let seconds = u64::MAX;
1295 let subsec_nanos = u32::MAX;
1296
1297 for context in [
1299 builder(|| ContextV7::new()),
1300 builder(|| ContextV7::new().with_additional_precision()),
1301 builder(|| ContextV7::new().with_adjust_by_millis(u32::MAX)),
1302 builder(|| {
1303 ContextV7::new()
1304 .with_additional_precision()
1305 .with_adjust_by_millis(u32::MAX)
1306 }),
1307 ] {
1308 Timestamp::from_unix(&context(), seconds, subsec_nanos);
1309 }
1310 }
1311
1312 #[test]
1313 fn context_subsec_ordering() {
1314 for context in [
1315 builder(|| ContextV7::new()),
1316 builder(|| ContextV7::new().with_additional_precision()),
1317 builder(|| ContextV7::new().with_adjust_by_millis(u32::MAX)),
1318 builder(|| {
1319 ContextV7::new()
1320 .with_additional_precision()
1321 .with_adjust_by_millis(u32::MAX)
1322 }),
1323 ] {
1324 for (a, b, c) in [
1325 ((100, 0), (99, 2_000_000), (100, 1_000_000)),
1327 ((100, 0), (99, 1_000_900_000), (100, 1_000_000)),
1328 ] {
1329 let context = context();
1330
1331 let a = Timestamp::from_unix(&context, a.0, a.1);
1333 let b = Timestamp::from_unix(&context, b.0, b.1);
1334 let c = Timestamp::from_unix(&context, c.0, c.1);
1335
1336 assert!(Uuid::new_v7(a) < Uuid::new_v7(b), "a: {a:?} < b: {b:?}");
1337 assert!(Uuid::new_v7(b) < Uuid::new_v7(c), "b: {b:?} < c: {c:?}");
1338 }
1339 }
1340 }
1341
1342 #[test]
1343 fn context_subsec_saturated_ordering() {
1344 for context in [
1345 builder(|| ContextV7::new()),
1346 builder(|| ContextV7::new().with_additional_precision()),
1347 builder(|| ContextV7::new().with_adjust_by_millis(u32::MAX)),
1348 builder(|| {
1349 ContextV7::new()
1350 .with_additional_precision()
1351 .with_adjust_by_millis(u32::MAX)
1352 }),
1353 ] {
1354 let context = context();
1355
1356 let secs = (u64::MAX / 1_000) + 1;
1357
1358 let a = Timestamp::from_unix(&context, secs, 900_000);
1359 let b = Timestamp::from_unix(&context, secs, 1_000_000);
1360
1361 assert!(Uuid::new_v7(a) < Uuid::new_v7(b), "a: {a:?} < b: {b:?}");
1362 }
1363 }
1364
1365 #[test]
1366 fn context_additional_precision_within_millisecond() {
1367 let seconds = 1_496_854_535;
1368 let subsec_nanos = 812_100_000;
1369
1370 let context = ContextV7::new().with_additional_precision();
1371
1372 let ts1 = Timestamp::from_unix(&context, seconds, subsec_nanos);
1373
1374 let ts2 = Timestamp::from_unix(&context, seconds, subsec_nanos + 500_000);
1376
1377 assert!(
1378 ts2.counter >> 30 > ts1.counter >> 30,
1379 "ts1: {ts1:?}, ts2: {ts2:?}"
1380 );
1381
1382 let ts3 = Timestamp::from_unix(&context, seconds, subsec_nanos);
1384
1385 assert_eq!(
1386 ts2.counter >> 30,
1387 ts3.counter >> 30,
1388 "ts2: {ts2:?}, ts3: {ts3:?}"
1389 );
1390 assert_eq!(ts2.to_unix(), ts3.to_unix());
1391
1392 assert!(Uuid::new_v7(ts1) < Uuid::new_v7(ts2));
1393 assert!(Uuid::new_v7(ts2) < Uuid::new_v7(ts3));
1394 }
1395
1396 #[test]
1397 fn reseeding_timestamp_saturating() {
1398 const MAX_UNIX_NANOS: u128 = (u64::MAX as u128) * 1_000_000 + 999_999;
1399 const MAX_PARTS: (u64, u32) = (u64::MAX / 1_000, 615_999_999);
1400
1401 let below =
1403 ReseedingTimestamp::saturating_from_unix_nanos(MAX_UNIX_NANOS - 1_000_000);
1404 assert_eq!(MAX_UNIX_NANOS - 1_000_000, below.unix_nanos);
1405 assert_eq!(u64::MAX - 1, below.last_seed);
1406 assert_eq!((u64::MAX / 1_000, 614_999_999), below.to_parts());
1407
1408 for unix_nanos in [
1410 MAX_UNIX_NANOS,
1411 MAX_UNIX_NANOS + 1,
1412 parts_to_nanos(u64::MAX / 1_000 + 1, 0),
1413 parts_to_nanos(u64::MAX, 999_999_999),
1414 parts_to_nanos(u64::MAX, u32::MAX),
1415 u128::MAX,
1416 ] {
1417 let ts = ReseedingTimestamp::saturating_from_unix_nanos(unix_nanos);
1418
1419 assert_eq!(MAX_UNIX_NANOS, ts.unix_nanos, "{unix_nanos}");
1420 assert_eq!(u64::MAX, ts.last_seed, "{unix_nanos}");
1421 assert_eq!(MAX_PARTS, ts.to_parts(), "{unix_nanos}");
1422 }
1423
1424 let max = ReseedingTimestamp::saturating_from_unix_nanos(MAX_UNIX_NANOS);
1426 let incremented = max.increment();
1427 assert_eq!(MAX_UNIX_NANOS, incremented.unix_nanos);
1428 assert_eq!(u64::MAX, incremented.last_seed);
1429 }
1430
1431 #[test]
1432 fn context_saturated_parts() {
1433 const MAX_PARTS: (u64, u32) = (u64::MAX / 1_000, 615_999_999);
1434
1435 for context in [
1436 builder(|| ContextV7::new()),
1437 builder(|| ContextV7::new().with_adjust_by_millis(u32::MAX)),
1438 ] {
1439 for (seconds, subsec_nanos) in [
1440 MAX_PARTS,
1441 (u64::MAX / 1_000 + 1, 0),
1442 (u64::MAX, 999_999_999),
1443 (u64::MAX, u32::MAX),
1444 ] {
1445 let ts = Timestamp::from_unix(&context(), seconds, subsec_nanos);
1446
1447 assert_eq!(MAX_PARTS, ts.to_unix(), "{seconds}, {subsec_nanos}");
1448 }
1449 }
1450
1451 let context = ContextV7 {
1453 timestamp: Cell::new(ReseedingTimestamp::saturating_from_unix_nanos(u128::MAX)),
1454 adjust: Adjust::by_millis(0),
1455 precision: Precision::new(0),
1456 counter: Cell::new(Counter {
1457 value: u64::MAX >> 22,
1458 }),
1459 };
1460
1461 let ts = Timestamp::from_unix(&context, u64::MAX, u32::MAX);
1462
1463 assert_eq!(MAX_PARTS, ts.to_unix());
1464 }
1465 }
1466 }
1467
1468 #[cfg(feature = "v7")]
1469 pub use v7_support::*;
1470
1471 #[derive(#[automatically_derived]impl ::core::fmt::Debug for NoContext {
#[inline]
#[rustc_trivial_field_reads]
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]
#[rustc_trivial_field_reads]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]impl ::core::marker::Copy for NoContext { }Copy, #[automatically_derived]impl ::core::default::Default for NoContext {
#[inline]
fn default() -> Self { NoContext {} }
}Default)]
1482 pub struct NoContext;
1483
1484 impl ClockSequence for NoContext {
1485 type Output = u16;
1486
1487 fn generate_sequence(&self, _seconds: u64, _nanos: u32) -> Self::Output {
1488 0
1489 }
1490
1491 fn usable_bits(&self) -> usize {
1492 0
1493 }
1494 }
1495}
1496
1497#[cfg(all(test, any(feature = "v1", feature = "v6")))]
1498mod tests {
1499 use super::*;
1500
1501 #[cfg(all(target_family = "wasm", any(target_os = "unknown", target_os = "none")))]
1502 use wasm_bindgen_test::*;
1503
1504 #[test]
1505 #[cfg_attr(
1506 all(target_family = "wasm", any(target_os = "unknown", target_os = "none")),
1507 wasm_bindgen_test
1508 )]
1509 fn gregorian_unix_does_not_panic() {
1510 Timestamp::unix_to_gregorian_ticks(u64::MAX, 0);
1512 Timestamp::unix_to_gregorian_ticks(0, u32::MAX);
1513 Timestamp::unix_to_gregorian_ticks(u64::MAX, u32::MAX);
1514
1515 Timestamp::gregorian_to_unix(u64::MAX);
1516 }
1517
1518 #[test]
1519 #[cfg_attr(
1520 all(target_family = "wasm", any(target_os = "unknown", target_os = "none")),
1521 wasm_bindgen_test
1522 )]
1523 fn to_gregorian_truncates_to_usable_bits() {
1524 let ts = Timestamp::from_gregorian_time(123, u16::MAX);
1525
1526 assert_eq!((123, u16::MAX >> 2), ts.to_gregorian());
1527 }
1528
1529 #[test]
1530 #[cfg_attr(
1531 all(target_family = "wasm", any(target_os = "unknown", target_os = "none")),
1532 wasm_bindgen_test
1533 )]
1534 fn clock_sequence_usable_bits() {
1535 struct MyContext;
1536
1537 impl ClockSequence for MyContext {
1538 type Output = u16;
1539
1540 fn generate_sequence(&self, _: u64, _: u32) -> Self::Output {
1541 0
1542 }
1543 }
1544
1545 assert_eq!(16, MyContext.usable_bits());
1546 }
1547
1548 const MAX_PARTS_NANOS: u128 = (u64::MAX as u128) * 1_000_000_000 + 999_999_999;
1549
1550 #[test]
1551 fn nanos_to_parts_roundtrip() {
1552 for case in [
1553 0,
1554 1,
1555 999_999_999,
1556 1_000_000_000,
1557 u64::MAX as u128,
1558 u64::MAX as u128 + 1,
1559 u64::MAX as u128 + u32::MAX as u128,
1560 u64::MAX as u128 + u32::MAX as u128 + 1,
1561 (u64::MAX as u128) * 1_000_000 + 999_999,
1562 (u64::MAX as u128) * 1_000_000_000,
1563 MAX_PARTS_NANOS - 1,
1564 MAX_PARTS_NANOS,
1565 ] {
1566 let (seconds, subsec_nanos) = nanos_to_parts(case);
1567
1568 assert!(subsec_nanos < 1_000_000_000, "{case}");
1569 assert_eq!(case, parts_to_nanos(seconds, subsec_nanos), "{case}");
1570 }
1571 }
1572
1573 #[test]
1574 fn nanos_to_parts_unnormalized_roundtrip() {
1575 for (case, expected) in [
1578 (MAX_PARTS_NANOS + 1, (u64::MAX, 1_000_000_000)),
1579 (MAX_PARTS_NANOS + 2, (u64::MAX, 1_000_000_001)),
1580 (
1581 parts_to_nanos(u64::MAX, u32::MAX) - 1,
1582 (u64::MAX, u32::MAX - 1),
1583 ),
1584 (parts_to_nanos(u64::MAX, u32::MAX), (u64::MAX, u32::MAX)),
1585 ] {
1586 let (seconds, subsec_nanos) = nanos_to_parts(case);
1587
1588 assert_eq!(expected, (seconds, subsec_nanos), "{case}");
1589 assert_eq!(case, parts_to_nanos(seconds, subsec_nanos), "{case}");
1590 }
1591 }
1592
1593 #[test]
1594 fn nanos_to_parts_saturating() {
1595 for case in [parts_to_nanos(u64::MAX, u32::MAX) + 1, u128::MAX] {
1596 let (seconds, subsec_nanos) = nanos_to_parts(case);
1597
1598 assert_eq!(u64::MAX, seconds, "{case}");
1599 assert_eq!(u32::MAX, subsec_nanos, "{case}");
1600 }
1601 }
1602
1603 #[test]
1604 fn parts_to_nanos_unnormalized() {
1605 assert_eq!(2_500_000_000, parts_to_nanos(1, 1_500_000_000));
1606 assert_eq!(
1607 parts_to_nanos(2, 500_000_000),
1608 parts_to_nanos(1, 1_500_000_000)
1609 );
1610
1611 assert_eq!(
1613 (u64::MAX as u128) * 1_000_000_000 + u32::MAX as u128,
1614 parts_to_nanos(u64::MAX, u32::MAX)
1615 );
1616 }
1617
1618 #[test]
1619 fn timestamp_unix_parts_boundaries() {
1620 for (seconds, subsec_nanos) in [
1622 (0, 0),
1623 (1, 999_999_999),
1624 (u64::MAX, 0),
1625 (u64::MAX, 999_999_999),
1626 ] {
1627 let ts = Timestamp::from_unix_time(seconds, subsec_nanos, 0, 0);
1628
1629 assert_eq!((seconds, subsec_nanos), ts.to_unix());
1630 }
1631
1632 let ts = Timestamp::from_unix_time(1, 1_500_000_000, 0, 0);
1634 assert_eq!((2, 500_000_000), ts.to_unix());
1635
1636 for (seconds, subsec_nanos) in [(u64::MAX, 1_000_000_000), (u64::MAX, u32::MAX)] {
1638 let ts = Timestamp::from_unix_time(seconds, subsec_nanos, 0, 0);
1639
1640 assert_eq!((seconds, subsec_nanos), ts.to_unix());
1641 }
1642
1643 let ts = Timestamp::from_unix_time(u64::MAX - 1, u32::MAX, 0, 0);
1644 assert_eq!((u64::MAX, u32::MAX - 1_000_000_000), ts.to_unix());
1645 }
1646
1647 #[cfg(all(test, feature = "std", not(miri)))]
1648 mod std_support {
1649 use super::*;
1650
1651 use std::time::{Duration, SystemTime};
1652
1653 const KNOWN_SECONDS: u64 = 1_501_520_400;
1655 const KNOWN_NANOS: u32 = 1_000;
1656
1657 fn known_system_time() -> SystemTime {
1658 SystemTime::UNIX_EPOCH
1659 .checked_add(Duration::new(KNOWN_SECONDS, KNOWN_NANOS))
1660 .unwrap()
1661 }
1662
1663 fn known_timestamp() -> Timestamp {
1664 Timestamp::from_unix_time(KNOWN_SECONDS, KNOWN_NANOS, 0, 0)
1665 }
1666
1667 #[test]
1668 fn to_system_time() {
1669 let st: SystemTime = known_timestamp().into();
1670
1671 assert_eq!(known_system_time(), st);
1672 }
1673
1674 #[test]
1675 fn from_system_time() {
1676 let ts: Timestamp = known_system_time().try_into().unwrap();
1677
1678 assert_eq!(known_timestamp(), ts);
1679 }
1680
1681 #[test]
1682 fn from_system_time_before_epoch() {
1683 let before_epoch = match SystemTime::UNIX_EPOCH.checked_sub(Duration::from_nanos(1_000))
1684 {
1685 Some(st) => st,
1686 None => return,
1687 };
1688
1689 Timestamp::try_from(before_epoch)
1690 .expect_err("Timestamp should not be created from before epoch");
1691 }
1692
1693 #[test]
1694 fn from_system_time_max() {
1695 for (seconds, subsec_nanos) in [
1696 (u64::MAX, 999_999_999),
1697 (u64::MAX, 1_000_000_000),
1698 (u64::MAX, u32::MAX),
1699 ] {
1700 let ts = Timestamp::from_unix_time(seconds, subsec_nanos, 0, 0);
1701
1702 let _: SystemTime = ts.into();
1704 }
1705 }
1706 }
1707}