1#![doc(html_root_url = "https://docs.rs/prost-types/0.9.0")]
2
3#![cfg_attr(not(feature = "std"), no_std)]
13
14use core::convert::TryFrom;
15use core::i32;
16use core::i64;
17use core::time;
18
19include!("protobuf.rs");
20pub mod compiler {
21 include!("compiler.rs");
22}
23
24const NANOS_PER_SECOND: i32 = 1_000_000_000;
29const NANOS_MAX: i32 = NANOS_PER_SECOND - 1;
30
31impl Duration {
32 pub fn normalize(&mut self) {
37 if self.nanos <= -NANOS_PER_SECOND || self.nanos >= NANOS_PER_SECOND {
39 if let Some(seconds) = self
40 .seconds
41 .checked_add((self.nanos / NANOS_PER_SECOND) as i64)
42 {
43 self.seconds = seconds;
44 self.nanos %= NANOS_PER_SECOND;
45 } else if self.nanos < 0 {
46 self.seconds = i64::MIN;
48 self.nanos = -NANOS_MAX;
49 } else {
50 self.seconds = i64::MAX;
52 self.nanos = NANOS_MAX;
53 }
54 }
55
56 if self.seconds < 0 && self.nanos > 0 {
58 if let Some(seconds) = self.seconds.checked_add(1) {
59 self.seconds = seconds;
60 self.nanos -= NANOS_PER_SECOND;
61 } else {
62 debug_assert_eq!(self.seconds, i64::MAX);
64 self.nanos = NANOS_MAX;
65 }
66 } else if self.seconds > 0 && self.nanos < 0 {
67 if let Some(seconds) = self.seconds.checked_sub(1) {
68 self.seconds = seconds;
69 self.nanos += NANOS_PER_SECOND;
70 } else {
71 debug_assert_eq!(self.seconds, i64::MIN);
73 self.nanos = -NANOS_MAX;
74 }
75 }
76 }
80}
81
82impl From<time::Duration> for Duration {
84 fn from(duration: time::Duration) -> Duration {
85 let seconds = duration.as_secs();
86 let seconds = if seconds > i64::MAX as u64 {
87 i64::MAX
88 } else {
89 seconds as i64
90 };
91 let nanos = duration.subsec_nanos();
92 let nanos = if nanos > i32::MAX as u32 {
93 i32::MAX
94 } else {
95 nanos as i32
96 };
97 let mut duration = Duration { seconds, nanos };
98 duration.normalize();
99 duration
100 }
101}
102
103impl TryFrom<Duration> for time::Duration {
104 type Error = time::Duration;
105
106 fn try_from(mut duration: Duration) -> Result<time::Duration, time::Duration> {
109 duration.normalize();
110 if duration.seconds >= 0 {
111 Ok(time::Duration::new(
112 duration.seconds as u64,
113 duration.nanos as u32,
114 ))
115 } else {
116 Err(time::Duration::new(
117 (-duration.seconds) as u64,
118 (-duration.nanos) as u32,
119 ))
120 }
121 }
122}
123
124impl Timestamp {
125 #[cfg(feature = "std")]
130 pub fn normalize(&mut self) {
131 if self.nanos <= -NANOS_PER_SECOND || self.nanos >= NANOS_PER_SECOND {
133 if let Some(seconds) = self
134 .seconds
135 .checked_add((self.nanos / NANOS_PER_SECOND) as i64)
136 {
137 self.seconds = seconds;
138 self.nanos %= NANOS_PER_SECOND;
139 } else if self.nanos < 0 {
140 self.seconds = i64::MIN;
142 self.nanos = 0;
143 } else {
144 self.seconds = i64::MAX;
146 self.nanos = 999_999_999;
147 }
148 }
149
150 if self.nanos < 0 {
152 if let Some(seconds) = self.seconds.checked_sub(1) {
153 self.seconds = seconds;
154 self.nanos += NANOS_PER_SECOND;
155 } else {
156 debug_assert_eq!(self.seconds, i64::MIN);
158 self.nanos = 0;
159 }
160 }
161
162 }
166}
167
168#[cfg(feature = "std")]
171impl Eq for Timestamp {}
172
173#[cfg(feature = "std")]
174#[allow(clippy::derive_hash_xor_eq)] impl std::hash::Hash for Timestamp {
176 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
177 self.seconds.hash(state);
178 self.nanos.hash(state);
179 }
180}
181
182#[cfg(feature = "std")]
183impl From<std::time::SystemTime> for Timestamp {
184 fn from(system_time: std::time::SystemTime) -> Timestamp {
185 let (seconds, nanos) = match system_time.duration_since(std::time::UNIX_EPOCH) {
186 Ok(duration) => {
187 let seconds = i64::try_from(duration.as_secs()).unwrap();
188 (seconds, duration.subsec_nanos() as i32)
189 }
190 Err(error) => {
191 let duration = error.duration();
192 let seconds = i64::try_from(duration.as_secs()).unwrap();
193 let nanos = duration.subsec_nanos() as i32;
194 if nanos == 0 {
195 (-seconds, 0)
196 } else {
197 (-seconds - 1, 1_000_000_000 - nanos)
198 }
199 }
200 };
201 Timestamp { seconds, nanos }
202 }
203}
204
205#[cfg(feature = "std")]
213#[derive(Debug)]
214#[non_exhaustive]
215pub struct TimestampOutOfSystemRangeError {
216 pub timestamp: Timestamp,
217}
218
219#[cfg(feature = "std")]
220impl core::fmt::Display for TimestampOutOfSystemRangeError {
221 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
222 write!(
223 f,
224 "{:?} is not representable as a `SystemTime` because it is out of range",
225 self
226 )
227 }
228}
229
230#[cfg(feature = "std")]
231impl std::error::Error for TimestampOutOfSystemRangeError {}
232
233#[cfg(feature = "std")]
234impl TryFrom<Timestamp> for std::time::SystemTime {
235 type Error = TimestampOutOfSystemRangeError;
236
237 fn try_from(mut timestamp: Timestamp) -> Result<std::time::SystemTime, Self::Error> {
238 let orig_timestamp = timestamp.clone();
239 timestamp.normalize();
240
241 let system_time = if timestamp.seconds >= 0 {
242 std::time::UNIX_EPOCH.checked_add(time::Duration::from_secs(timestamp.seconds as u64))
243 } else {
244 std::time::UNIX_EPOCH
245 .checked_sub(time::Duration::from_secs((-timestamp.seconds) as u64))
246 };
247
248 let system_time = system_time.and_then(|system_time| {
249 system_time.checked_add(time::Duration::from_nanos(timestamp.nanos as u64))
250 });
251
252 system_time.ok_or(TimestampOutOfSystemRangeError {
253 timestamp: orig_timestamp,
254 })
255 }
256}
257
258#[cfg(test)]
259mod tests {
260 use std::time::{Duration, SystemTime, UNIX_EPOCH};
261
262 use proptest::prelude::*;
263
264 use super::*;
265
266 #[cfg(feature = "std")]
267 proptest! {
268 #[test]
269 fn check_system_time_roundtrip(
270 system_time in SystemTime::arbitrary(),
271 ) {
272 prop_assert_eq!(SystemTime::try_from(Timestamp::from(system_time)).unwrap(), system_time);
273 }
274
275 #[test]
276 fn check_timestamp_roundtrip_via_system_time(
277 seconds in i64::arbitrary(),
278 nanos in i32::arbitrary(),
279 ) {
280 let mut timestamp = Timestamp { seconds, nanos };
281 timestamp.normalize();
282 if let Ok(system_time) = SystemTime::try_from(timestamp.clone()) {
283 prop_assert_eq!(Timestamp::from(system_time), timestamp);
284 }
285 }
286 }
287
288 #[cfg(feature = "std")]
289 #[test]
290 fn check_timestamp_negative_seconds() {
291 assert_eq!(
301 Timestamp::from(UNIX_EPOCH - Duration::new(1_001, 0)),
302 Timestamp {
303 seconds: -1_001,
304 nanos: 0
305 }
306 );
307 assert_eq!(
308 Timestamp::from(UNIX_EPOCH - Duration::new(0, 999_999_900)),
309 Timestamp {
310 seconds: -1,
311 nanos: 100
312 }
313 );
314 assert_eq!(
315 Timestamp::from(UNIX_EPOCH - Duration::new(2_001_234, 12_300)),
316 Timestamp {
317 seconds: -2_001_235,
318 nanos: 999_987_700
319 }
320 );
321 assert_eq!(
322 Timestamp::from(UNIX_EPOCH - Duration::new(768, 65_432_100)),
323 Timestamp {
324 seconds: -769,
325 nanos: 934_567_900
326 }
327 );
328 }
329
330 #[cfg(all(unix, feature = "std"))]
331 #[test]
332 fn check_timestamp_negative_seconds_1ns() {
333 assert_eq!(
335 Timestamp::from(UNIX_EPOCH - Duration::new(0, 999_999_999)),
336 Timestamp {
337 seconds: -1,
338 nanos: 1
339 }
340 );
341 assert_eq!(
342 Timestamp::from(UNIX_EPOCH - Duration::new(1_234_567, 123)),
343 Timestamp {
344 seconds: -1_234_568,
345 nanos: 999_999_877
346 }
347 );
348 assert_eq!(
349 Timestamp::from(UNIX_EPOCH - Duration::new(890, 987_654_321)),
350 Timestamp {
351 seconds: -891,
352 nanos: 12_345_679
353 }
354 );
355 }
356
357 #[test]
358 fn check_duration_normalize() {
359 #[rustfmt::skip] let cases = [
361 (line!(), 0, 0, 0, 0),
364 (line!(), 1, 1, 1, 1),
365 (line!(), -1, -1, -1, -1),
366 (line!(), 0, 999_999_999, 0, 999_999_999),
367 (line!(), 0, -999_999_999, 0, -999_999_999),
368 (line!(), 0, 1_000_000_000, 1, 0),
369 (line!(), 0, -1_000_000_000, -1, 0),
370 (line!(), 0, 1_000_000_001, 1, 1),
371 (line!(), 0, -1_000_000_001, -1, -1),
372 (line!(), -1, 1, 0, -999_999_999),
373 (line!(), 1, -1, 0, 999_999_999),
374 (line!(), -1, 1_000_000_000, 0, 0),
375 (line!(), 1, -1_000_000_000, 0, 0),
376 (line!(), i64::MIN , 0, i64::MIN , 0),
377 (line!(), i64::MIN + 1, 0, i64::MIN + 1, 0),
378 (line!(), i64::MIN , 1, i64::MIN + 1, -999_999_999),
379 (line!(), i64::MIN , 1_000_000_000, i64::MIN + 1, 0),
380 (line!(), i64::MIN , -1_000_000_000, i64::MIN , -999_999_999),
381 (line!(), i64::MIN + 1, -1_000_000_000, i64::MIN , 0),
382 (line!(), i64::MIN + 2, -1_000_000_000, i64::MIN + 1, 0),
383 (line!(), i64::MIN , -1_999_999_998, i64::MIN , -999_999_999),
384 (line!(), i64::MIN + 1, -1_999_999_998, i64::MIN , -999_999_998),
385 (line!(), i64::MIN + 2, -1_999_999_998, i64::MIN + 1, -999_999_998),
386 (line!(), i64::MIN , -1_999_999_999, i64::MIN , -999_999_999),
387 (line!(), i64::MIN + 1, -1_999_999_999, i64::MIN , -999_999_999),
388 (line!(), i64::MIN + 2, -1_999_999_999, i64::MIN + 1, -999_999_999),
389 (line!(), i64::MIN , -2_000_000_000, i64::MIN , -999_999_999),
390 (line!(), i64::MIN + 1, -2_000_000_000, i64::MIN , -999_999_999),
391 (line!(), i64::MIN + 2, -2_000_000_000, i64::MIN , 0),
392 (line!(), i64::MIN , -999_999_998, i64::MIN , -999_999_998),
393 (line!(), i64::MIN + 1, -999_999_998, i64::MIN + 1, -999_999_998),
394 (line!(), i64::MAX , 0, i64::MAX , 0),
395 (line!(), i64::MAX - 1, 0, i64::MAX - 1, 0),
396 (line!(), i64::MAX , -1, i64::MAX - 1, 999_999_999),
397 (line!(), i64::MAX , 1_000_000_000, i64::MAX , 999_999_999),
398 (line!(), i64::MAX - 1, 1_000_000_000, i64::MAX , 0),
399 (line!(), i64::MAX - 2, 1_000_000_000, i64::MAX - 1, 0),
400 (line!(), i64::MAX , 1_999_999_998, i64::MAX , 999_999_999),
401 (line!(), i64::MAX - 1, 1_999_999_998, i64::MAX , 999_999_998),
402 (line!(), i64::MAX - 2, 1_999_999_998, i64::MAX - 1, 999_999_998),
403 (line!(), i64::MAX , 1_999_999_999, i64::MAX , 999_999_999),
404 (line!(), i64::MAX - 1, 1_999_999_999, i64::MAX , 999_999_999),
405 (line!(), i64::MAX - 2, 1_999_999_999, i64::MAX - 1, 999_999_999),
406 (line!(), i64::MAX , 2_000_000_000, i64::MAX , 999_999_999),
407 (line!(), i64::MAX - 1, 2_000_000_000, i64::MAX , 999_999_999),
408 (line!(), i64::MAX - 2, 2_000_000_000, i64::MAX , 0),
409 (line!(), i64::MAX , 999_999_998, i64::MAX , 999_999_998),
410 (line!(), i64::MAX - 1, 999_999_998, i64::MAX - 1, 999_999_998),
411 ];
412
413 for case in cases.iter() {
414 let mut test_duration = crate::Duration {
415 seconds: case.1,
416 nanos: case.2,
417 };
418 test_duration.normalize();
419
420 assert_eq!(
421 test_duration,
422 crate::Duration {
423 seconds: case.3,
424 nanos: case.4,
425 },
426 "test case on line {} doesn't match",
427 case.0,
428 );
429 }
430 }
431
432 #[cfg(feature = "std")]
433 #[test]
434 fn check_timestamp_normalize() {
435 #[rustfmt::skip] let cases = [
438 (line!(), 0, 0, 0, 0),
441 (line!(), 1, 1, 1, 1),
442 (line!(), -1, -1, -2, 999_999_999),
443 (line!(), 0, 999_999_999, 0, 999_999_999),
444 (line!(), 0, -999_999_999, -1, 1),
445 (line!(), 0, 1_000_000_000, 1, 0),
446 (line!(), 0, -1_000_000_000, -1, 0),
447 (line!(), 0, 1_000_000_001, 1, 1),
448 (line!(), 0, -1_000_000_001, -2, 999_999_999),
449 (line!(), -1, 1, -1, 1),
450 (line!(), 1, -1, 0, 999_999_999),
451 (line!(), -1, 1_000_000_000, 0, 0),
452 (line!(), 1, -1_000_000_000, 0, 0),
453 (line!(), i64::MIN , 0, i64::MIN , 0),
454 (line!(), i64::MIN + 1, 0, i64::MIN + 1, 0),
455 (line!(), i64::MIN , 1, i64::MIN , 1),
456 (line!(), i64::MIN , 1_000_000_000, i64::MIN + 1, 0),
457 (line!(), i64::MIN , -1_000_000_000, i64::MIN , 0),
458 (line!(), i64::MIN + 1, -1_000_000_000, i64::MIN , 0),
459 (line!(), i64::MIN + 2, -1_000_000_000, i64::MIN + 1, 0),
460 (line!(), i64::MIN , -1_999_999_998, i64::MIN , 0),
461 (line!(), i64::MIN + 1, -1_999_999_998, i64::MIN , 0),
462 (line!(), i64::MIN + 2, -1_999_999_998, i64::MIN , 2),
463 (line!(), i64::MIN , -1_999_999_999, i64::MIN , 0),
464 (line!(), i64::MIN + 1, -1_999_999_999, i64::MIN , 0),
465 (line!(), i64::MIN + 2, -1_999_999_999, i64::MIN , 1),
466 (line!(), i64::MIN , -2_000_000_000, i64::MIN , 0),
467 (line!(), i64::MIN + 1, -2_000_000_000, i64::MIN , 0),
468 (line!(), i64::MIN + 2, -2_000_000_000, i64::MIN , 0),
469 (line!(), i64::MIN , -999_999_998, i64::MIN , 0),
470 (line!(), i64::MIN + 1, -999_999_998, i64::MIN , 2),
471 (line!(), i64::MAX , 0, i64::MAX , 0),
472 (line!(), i64::MAX - 1, 0, i64::MAX - 1, 0),
473 (line!(), i64::MAX , -1, i64::MAX - 1, 999_999_999),
474 (line!(), i64::MAX , 1_000_000_000, i64::MAX , 999_999_999),
475 (line!(), i64::MAX - 1, 1_000_000_000, i64::MAX , 0),
476 (line!(), i64::MAX - 2, 1_000_000_000, i64::MAX - 1, 0),
477 (line!(), i64::MAX , 1_999_999_998, i64::MAX , 999_999_999),
478 (line!(), i64::MAX - 1, 1_999_999_998, i64::MAX , 999_999_998),
479 (line!(), i64::MAX - 2, 1_999_999_998, i64::MAX - 1, 999_999_998),
480 (line!(), i64::MAX , 1_999_999_999, i64::MAX , 999_999_999),
481 (line!(), i64::MAX - 1, 1_999_999_999, i64::MAX , 999_999_999),
482 (line!(), i64::MAX - 2, 1_999_999_999, i64::MAX - 1, 999_999_999),
483 (line!(), i64::MAX , 2_000_000_000, i64::MAX , 999_999_999),
484 (line!(), i64::MAX - 1, 2_000_000_000, i64::MAX , 999_999_999),
485 (line!(), i64::MAX - 2, 2_000_000_000, i64::MAX , 0),
486 (line!(), i64::MAX , 999_999_998, i64::MAX , 999_999_998),
487 (line!(), i64::MAX - 1, 999_999_998, i64::MAX - 1, 999_999_998),
488 ];
489
490 for case in cases.iter() {
491 let mut test_timestamp = crate::Timestamp {
492 seconds: case.1,
493 nanos: case.2,
494 };
495 test_timestamp.normalize();
496
497 assert_eq!(
498 test_timestamp,
499 crate::Timestamp {
500 seconds: case.3,
501 nanos: case.4,
502 },
503 "test case on line {} doesn't match",
504 case.0,
505 );
506 }
507 }
508}