rkyv/time.rs
1//! Archived versions of `time` types.
2
3use crate::{
4 primitive::{ArchivedU32, ArchivedU64},
5 Portable,
6};
7
8/// An archived [`Duration`](core::time::Duration).
9#[derive(
10 Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Portable,
11)]
12#[cfg_attr(
13 feature = "bytecheck",
14 derive(bytecheck::CheckBytes),
15 bytecheck(verify)
16)]
17#[rkyv(crate)]
18#[repr(C)]
19pub struct ArchivedDuration {
20 secs: ArchivedU64,
21 nanos: ArchivedU32,
22}
23
24const NANOS_PER_SEC: u32 = 1_000_000_000;
25const NANOS_PER_MILLI: u32 = 1_000_000;
26const NANOS_PER_MICRO: u32 = 1_000;
27const MILLIS_PER_SEC: u64 = 1_000;
28const MICROS_PER_SEC: u64 = 1_000_000;
29
30impl ArchivedDuration {
31 /// Returns the number of _whole_ seconds contained by this
32 /// `ArchivedDuration`.
33 ///
34 /// The returned value does not include the fractional (nanosecond) part of
35 /// the duration, which can be obtained using [`subsec_nanos`].
36 ///
37 /// [`subsec_nanos`]: ArchivedDuration::subsec_nanos
38 #[inline]
39 pub const fn as_secs(&self) -> u64 {
40 self.secs.to_native()
41 }
42
43 /// Returns the fractional part of this `ArchivedDuration`, in whole
44 /// milliseconds.
45 ///
46 /// This method does **not** return the length of the duration when
47 /// represented by milliseconds. The returned number always represents a
48 /// fractional portion of a second (i.e., it is less than one thousand).
49 #[inline]
50 pub const fn subsec_millis(&self) -> u32 {
51 self.nanos.to_native() / NANOS_PER_MILLI
52 }
53
54 /// Returns the fractional part of this `ArchivedDuration`, in whole
55 /// microseconds.
56 ///
57 /// This method does **not** return the length of the duration when
58 /// represented by microseconds. The returned number always represents a
59 /// fractional portion of a second (i.e., it is less than one million).
60 #[inline]
61 pub const fn subsec_micros(&self) -> u32 {
62 self.nanos.to_native() / NANOS_PER_MICRO
63 }
64
65 /// Returns the fractional part of this `Duration`, in nanoseconds.
66 ///
67 /// This method does **not** return the length of the duration when
68 /// represented by nanoseconds. The returned number always represents a
69 /// fractional portion of a second (i.e., it is less than one billion).
70 #[inline]
71 pub const fn subsec_nanos(&self) -> u32 {
72 self.nanos.to_native()
73 }
74
75 /// Returns the total number of whole milliseconds contained by this
76 /// `ArchivedDuration`.
77 #[inline]
78 pub const fn as_millis(&self) -> u128 {
79 self.as_secs() as u128 * MILLIS_PER_SEC as u128
80 + (self.subsec_nanos() / NANOS_PER_MILLI) as u128
81 }
82
83 /// Returns the total number of whole microseconds contained by this
84 /// `ArchivedDuration`.
85 #[inline]
86 pub const fn as_micros(&self) -> u128 {
87 self.as_secs() as u128 * MICROS_PER_SEC as u128
88 + (self.subsec_nanos() / NANOS_PER_MICRO) as u128
89 }
90
91 /// Returns the total number of nanoseconds contained by this
92 /// `ArchivedDuration`.
93 #[inline]
94 pub const fn as_nanos(&self) -> u128 {
95 self.as_secs() as u128 * NANOS_PER_SEC as u128
96 + self.subsec_nanos() as u128
97 }
98
99 /// Returns the number of seconds contained by this `ArchivedDuration` as
100 /// `f64`.
101 ///
102 /// The returned value does include the fractional (nanosecond) part of the
103 /// duration.
104 #[inline]
105 pub fn as_secs_f64(&self) -> f64 {
106 (self.as_secs() as f64)
107 + (self.subsec_nanos() as f64) / (NANOS_PER_SEC as f64)
108 }
109
110 /// Returns the number of seconds contained by this `ArchivedDuration` as
111 /// `f32`.
112 ///
113 /// The returned value does include the fractional (nanosecond) part of the
114 /// duration.
115 #[inline]
116 pub fn as_secs_f32(&self) -> f32 {
117 (self.as_secs() as f32)
118 + (self.subsec_nanos() as f32) / (NANOS_PER_SEC as f32)
119 }
120
121 /// Constructs an archived duration at the given position.
122 ///
123 /// This function is guaranteed not to write any uninitialized bytes to
124 /// `out`.
125 ///
126 /// # Safety
127 ///
128 /// `out` must point to memory suitable for holding an `ArchivedDuration`.
129 #[inline]
130 pub unsafe fn emplace(secs: u64, nanos: u32, out: *mut ArchivedDuration) {
131 use core::ptr::addr_of_mut;
132
133 let out_secs = unsafe { addr_of_mut!((*out).secs) };
134 unsafe {
135 out_secs.write(ArchivedU64::from_native(secs));
136 }
137 let out_nanos = unsafe { addr_of_mut!((*out).nanos) };
138 unsafe {
139 out_nanos.write(ArchivedU32::from_native(nanos));
140 }
141 }
142}
143
144#[cfg(feature = "bytecheck")]
145mod verify {
146 use core::{error::Error, fmt};
147
148 use bytecheck::{
149 rancor::{Fallible, Source},
150 Verify,
151 };
152 use rancor::fail;
153
154 use super::ArchivedDuration;
155
156 /// An error resulting from an invalid duration.
157 ///
158 /// Durations must have a `nanos` field that is less than one billion.
159 #[derive(Debug)]
160 pub struct DurationError {
161 nanos: u32,
162 }
163
164 impl fmt::Display for DurationError {
165 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
166 write!(
167 f,
168 "`nanos` field of `Duration` is greater than 1 billion: {}",
169 self.nanos,
170 )
171 }
172 }
173
174 impl Error for DurationError {}
175
176 unsafe impl<C> Verify<C> for ArchivedDuration
177 where
178 C: Fallible + ?Sized,
179 C::Error: Source,
180 {
181 fn verify(&self, _: &mut C) -> Result<(), C::Error> {
182 let nanos = self.nanos.to_native();
183 if nanos >= 1_000_000_000 {
184 fail!(DurationError { nanos });
185 } else {
186 Ok(())
187 }
188 }
189 }
190}