1 #![doc(html_root_url = "https://docs.rs/prost-types/0.8.0")]
2 
3 //! Protocol Buffers well-known types.
4 //!
5 //! Note that the documentation for the types defined in this crate are generated from the Protobuf
6 //! definitions, so code examples are not in Rust.
7 //!
8 //! See the [Protobuf reference][1] for more information about well-known types.
9 //!
10 //! [1]: https://developers.google.com/protocol-buffers/docs/reference/google.protobuf
11 
12 #![cfg_attr(not(feature = "std"), no_std)]
13 
14 use core::convert::TryFrom;
15 use core::i32;
16 use core::i64;
17 use core::time;
18 
19 include!("protobuf.rs");
20 pub mod compiler {
21     include!("compiler.rs");
22 }
23 
24 // The Protobuf `Duration` and `Timestamp` types can't delegate to the standard library equivalents
25 // because the Protobuf versions are signed. To make them easier to work with, `From` conversions
26 // are defined in both directions.
27 
28 const NANOS_PER_SECOND: i32 = 1_000_000_000;
29 const NANOS_MAX: i32 = NANOS_PER_SECOND - 1;
30 
31 impl Duration {
32     /// Normalizes the duration to a canonical format.
33     ///
34     /// Based on [`google::protobuf::util::CreateNormalized`][1].
35     /// [1]: https://github.com/google/protobuf/blob/v3.3.2/src/google/protobuf/util/time_util.cc#L79-L100
normalize(&mut self)36     pub fn normalize(&mut self) {
37         // Make sure nanos is in the range.
38         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                 // Negative overflow! Set to the least normal value.
47                 self.seconds = i64::MIN;
48                 self.nanos = -NANOS_MAX;
49             } else {
50                 // Positive overflow! Set to the greatest normal value.
51                 self.seconds = i64::MAX;
52                 self.nanos = NANOS_MAX;
53             }
54         }
55 
56         // nanos should have the same sign as seconds.
57         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                 // Positive overflow! Set to the greatest normal value.
63                 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                 // Negative overflow! Set to the least normal value.
72                 debug_assert_eq!(self.seconds, i64::MIN);
73                 self.nanos = -NANOS_MAX;
74             }
75         }
76         // TODO: should this be checked?
77         // debug_assert!(self.seconds >= -315_576_000_000 && self.seconds <= 315_576_000_000,
78         //               "invalid duration: {:?}", self);
79     }
80 }
81 
82 /// Converts a `std::time::Duration` to a `Duration`.
83 impl From<time::Duration> for Duration {
from(duration: time::Duration) -> Duration84     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 
103 impl TryFrom<Duration> for time::Duration {
104     type Error = time::Duration;
105 
106     /// Converts a `Duration` to a result containing a positive (`Ok`) or negative (`Err`)
107     /// `std::time::Duration`.
try_from(mut duration: Duration) -> Result<time::Duration, time::Duration>108     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 
124 impl Timestamp {
125     /// Normalizes the timestamp to a canonical format.
126     ///
127     /// Based on [`google::protobuf::util::CreateNormalized`][1].
128     /// [1]: https://github.com/google/protobuf/blob/v3.3.2/src/google/protobuf/util/time_util.cc#L59-L77
129     #[cfg(feature = "std")]
normalize(&mut self)130     pub fn normalize(&mut self) {
131         // Make sure nanos is in the range.
132         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                 // Negative overflow! Set to the earliest normal value.
141                 self.seconds = i64::MIN;
142                 self.nanos = 0;
143             } else {
144                 // Positive overflow! Set to the latest normal value.
145                 self.seconds = i64::MAX;
146                 self.nanos = 999_999_999;
147             }
148         }
149 
150         // For Timestamp nanos should be in the range [0, 999999999].
151         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                 // Negative overflow! Set to the earliest normal value.
157                 debug_assert_eq!(self.seconds, i64::MIN);
158                 self.nanos = 0;
159             }
160         }
161 
162         // TODO: should this be checked?
163         // debug_assert!(self.seconds >= -62_135_596_800 && self.seconds <= 253_402_300_799,
164         //               "invalid timestamp: {:?}", self);
165     }
166 }
167 
168 #[cfg(feature = "std")]
169 impl From<std::time::SystemTime> for Timestamp {
from(system_time: std::time::SystemTime) -> Timestamp170     fn from(system_time: std::time::SystemTime) -> Timestamp {
171         let (seconds, nanos) = match system_time.duration_since(std::time::UNIX_EPOCH) {
172             Ok(duration) => {
173                 let seconds = i64::try_from(duration.as_secs()).unwrap();
174                 (seconds, duration.subsec_nanos() as i32)
175             }
176             Err(error) => {
177                 let duration = error.duration();
178                 let seconds = i64::try_from(duration.as_secs()).unwrap();
179                 let nanos = duration.subsec_nanos() as i32;
180                 if nanos == 0 {
181                     (-seconds, 0)
182                 } else {
183                     (-seconds - 1, 1_000_000_000 - nanos)
184                 }
185             }
186         };
187         Timestamp { seconds, nanos }
188     }
189 }
190 
191 /// Indicates that a [`Timestamp`] could not be converted to
192 /// [`SystemTime`][std::time::SystemTime] because it is out of range.
193 ///
194 /// The range of times that can be represented by `SystemTime` depends on the platform.
195 /// All `Timestamp`s are likely representable on 64-bit Unix-like platforms, but
196 /// other platforms, such as Windows and 32-bit Linux, may not be able to represent
197 /// the full range of `Timestamp`s.
198 #[cfg(feature = "std")]
199 #[derive(Debug)]
200 #[non_exhaustive]
201 pub struct TimestampOutOfSystemRangeError {
202     pub timestamp: Timestamp,
203 }
204 
205 #[cfg(feature = "std")]
206 impl core::fmt::Display for TimestampOutOfSystemRangeError {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result207     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
208         write!(
209             f,
210             "{:?} is not representable as a `SystemTime` because it is out of range",
211             self
212         )
213     }
214 }
215 
216 #[cfg(feature = "std")]
217 impl std::error::Error for TimestampOutOfSystemRangeError {}
218 
219 #[cfg(feature = "std")]
220 impl TryFrom<Timestamp> for std::time::SystemTime {
221     type Error = TimestampOutOfSystemRangeError;
222 
try_from(mut timestamp: Timestamp) -> Result<std::time::SystemTime, Self::Error>223     fn try_from(mut timestamp: Timestamp) -> Result<std::time::SystemTime, Self::Error> {
224         let orig_timestamp = timestamp.clone();
225         timestamp.normalize();
226 
227         let system_time = if timestamp.seconds >= 0 {
228             std::time::UNIX_EPOCH.checked_add(time::Duration::from_secs(timestamp.seconds as u64))
229         } else {
230             std::time::UNIX_EPOCH
231                 .checked_sub(time::Duration::from_secs((-timestamp.seconds) as u64))
232         };
233 
234         let system_time = system_time.and_then(|system_time| {
235             system_time.checked_add(time::Duration::from_nanos(timestamp.nanos as u64))
236         });
237 
238         system_time.ok_or(TimestampOutOfSystemRangeError {
239             timestamp: orig_timestamp,
240         })
241     }
242 }
243 
244 #[cfg(test)]
245 mod tests {
246     use std::time::{Duration, SystemTime, UNIX_EPOCH};
247 
248     use proptest::prelude::*;
249 
250     use super::*;
251 
252     #[cfg(feature = "std")]
253     proptest! {
254         #[test]
255         fn check_system_time_roundtrip(
256             system_time in SystemTime::arbitrary(),
257         ) {
258             prop_assert_eq!(SystemTime::try_from(Timestamp::from(system_time)).unwrap(), system_time);
259         }
260 
261         #[test]
262         fn check_timestamp_roundtrip_via_system_time(
263             seconds in i64::arbitrary(),
264             nanos in i32::arbitrary(),
265         ) {
266             let mut timestamp = Timestamp { seconds, nanos };
267             timestamp.normalize();
268             if let Ok(system_time) = SystemTime::try_from(timestamp.clone()) {
269                 prop_assert_eq!(Timestamp::from(system_time), timestamp);
270             }
271         }
272     }
273 
274     #[cfg(feature = "std")]
275     #[test]
check_timestamp_negative_seconds()276     fn check_timestamp_negative_seconds() {
277         // Representative tests for the case of timestamps before the UTC Epoch time:
278         // validate the expected behaviour that "negative second values with fractions
279         // must still have non-negative nanos values that count forward in time"
280         // https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#google.protobuf.Timestamp
281         //
282         // To ensure cross-platform compatibility, all nanosecond values in these
283         // tests are in minimum 100 ns increments.  This does not affect the general
284         // character of the behaviour being tested, but ensures that the tests are
285         // valid for both POSIX (1 ns precision) and Windows (100 ns precision).
286         assert_eq!(
287             Timestamp::from(UNIX_EPOCH - Duration::new(1_001, 0)),
288             Timestamp {
289                 seconds: -1_001,
290                 nanos: 0
291             }
292         );
293         assert_eq!(
294             Timestamp::from(UNIX_EPOCH - Duration::new(0, 999_999_900)),
295             Timestamp {
296                 seconds: -1,
297                 nanos: 100
298             }
299         );
300         assert_eq!(
301             Timestamp::from(UNIX_EPOCH - Duration::new(2_001_234, 12_300)),
302             Timestamp {
303                 seconds: -2_001_235,
304                 nanos: 999_987_700
305             }
306         );
307         assert_eq!(
308             Timestamp::from(UNIX_EPOCH - Duration::new(768, 65_432_100)),
309             Timestamp {
310                 seconds: -769,
311                 nanos: 934_567_900
312             }
313         );
314     }
315 
316     #[cfg(all(unix, feature = "std"))]
317     #[test]
check_timestamp_negative_seconds_1ns()318     fn check_timestamp_negative_seconds_1ns() {
319         // UNIX-only test cases with 1 ns precision
320         assert_eq!(
321             Timestamp::from(UNIX_EPOCH - Duration::new(0, 999_999_999)),
322             Timestamp {
323                 seconds: -1,
324                 nanos: 1
325             }
326         );
327         assert_eq!(
328             Timestamp::from(UNIX_EPOCH - Duration::new(1_234_567, 123)),
329             Timestamp {
330                 seconds: -1_234_568,
331                 nanos: 999_999_877
332             }
333         );
334         assert_eq!(
335             Timestamp::from(UNIX_EPOCH - Duration::new(890, 987_654_321)),
336             Timestamp {
337                 seconds: -891,
338                 nanos: 12_345_679
339             }
340         );
341     }
342 
343     #[test]
check_duration_normalize()344     fn check_duration_normalize() {
345         #[rustfmt::skip] // Don't mangle the table formatting.
346         let cases = [
347             // --- Table of test cases ---
348             //        test seconds      test nanos  expected seconds  expected nanos
349             (line!(),            0,              0,                0,              0),
350             (line!(),            1,              1,                1,              1),
351             (line!(),           -1,             -1,               -1,             -1),
352             (line!(),            0,    999_999_999,                0,    999_999_999),
353             (line!(),            0,   -999_999_999,                0,   -999_999_999),
354             (line!(),            0,  1_000_000_000,                1,              0),
355             (line!(),            0, -1_000_000_000,               -1,              0),
356             (line!(),            0,  1_000_000_001,                1,              1),
357             (line!(),            0, -1_000_000_001,               -1,             -1),
358             (line!(),           -1,              1,                0,   -999_999_999),
359             (line!(),            1,             -1,                0,    999_999_999),
360             (line!(),           -1,  1_000_000_000,                0,              0),
361             (line!(),            1, -1_000_000_000,                0,              0),
362             (line!(), i64::MIN    ,              0,     i64::MIN    ,              0),
363             (line!(), i64::MIN + 1,              0,     i64::MIN + 1,              0),
364             (line!(), i64::MIN    ,              1,     i64::MIN + 1,   -999_999_999),
365             (line!(), i64::MIN    ,  1_000_000_000,     i64::MIN + 1,              0),
366             (line!(), i64::MIN    , -1_000_000_000,     i64::MIN    ,   -999_999_999),
367             (line!(), i64::MIN + 1, -1_000_000_000,     i64::MIN    ,              0),
368             (line!(), i64::MIN + 2, -1_000_000_000,     i64::MIN + 1,              0),
369             (line!(), i64::MIN    , -1_999_999_998,     i64::MIN    ,   -999_999_999),
370             (line!(), i64::MIN + 1, -1_999_999_998,     i64::MIN    ,   -999_999_998),
371             (line!(), i64::MIN + 2, -1_999_999_998,     i64::MIN + 1,   -999_999_998),
372             (line!(), i64::MIN    , -1_999_999_999,     i64::MIN    ,   -999_999_999),
373             (line!(), i64::MIN + 1, -1_999_999_999,     i64::MIN    ,   -999_999_999),
374             (line!(), i64::MIN + 2, -1_999_999_999,     i64::MIN + 1,   -999_999_999),
375             (line!(), i64::MIN    , -2_000_000_000,     i64::MIN    ,   -999_999_999),
376             (line!(), i64::MIN + 1, -2_000_000_000,     i64::MIN    ,   -999_999_999),
377             (line!(), i64::MIN + 2, -2_000_000_000,     i64::MIN    ,              0),
378             (line!(), i64::MIN    ,   -999_999_998,     i64::MIN    ,   -999_999_998),
379             (line!(), i64::MIN + 1,   -999_999_998,     i64::MIN + 1,   -999_999_998),
380             (line!(), i64::MAX    ,              0,     i64::MAX    ,              0),
381             (line!(), i64::MAX - 1,              0,     i64::MAX - 1,              0),
382             (line!(), i64::MAX    ,             -1,     i64::MAX - 1,    999_999_999),
383             (line!(), i64::MAX    ,  1_000_000_000,     i64::MAX    ,    999_999_999),
384             (line!(), i64::MAX - 1,  1_000_000_000,     i64::MAX    ,              0),
385             (line!(), i64::MAX - 2,  1_000_000_000,     i64::MAX - 1,              0),
386             (line!(), i64::MAX    ,  1_999_999_998,     i64::MAX    ,    999_999_999),
387             (line!(), i64::MAX - 1,  1_999_999_998,     i64::MAX    ,    999_999_998),
388             (line!(), i64::MAX - 2,  1_999_999_998,     i64::MAX - 1,    999_999_998),
389             (line!(), i64::MAX    ,  1_999_999_999,     i64::MAX    ,    999_999_999),
390             (line!(), i64::MAX - 1,  1_999_999_999,     i64::MAX    ,    999_999_999),
391             (line!(), i64::MAX - 2,  1_999_999_999,     i64::MAX - 1,    999_999_999),
392             (line!(), i64::MAX    ,  2_000_000_000,     i64::MAX    ,    999_999_999),
393             (line!(), i64::MAX - 1,  2_000_000_000,     i64::MAX    ,    999_999_999),
394             (line!(), i64::MAX - 2,  2_000_000_000,     i64::MAX    ,              0),
395             (line!(), i64::MAX    ,    999_999_998,     i64::MAX    ,    999_999_998),
396             (line!(), i64::MAX - 1,    999_999_998,     i64::MAX - 1,    999_999_998),
397         ];
398 
399         for case in cases.iter() {
400             let mut test_duration = crate::Duration {
401                 seconds: case.1,
402                 nanos: case.2,
403             };
404             test_duration.normalize();
405 
406             assert_eq!(
407                 test_duration,
408                 crate::Duration {
409                     seconds: case.3,
410                     nanos: case.4,
411                 },
412                 "test case on line {} doesn't match",
413                 case.0,
414             );
415         }
416     }
417 
418     #[cfg(feature = "std")]
419     #[test]
check_timestamp_normalize()420     fn check_timestamp_normalize() {
421         // Make sure that `Timestamp::normalize` behaves correctly on and near overflow.
422         #[rustfmt::skip] // Don't mangle the table formatting.
423         let cases = [
424             // --- Table of test cases ---
425             //        test seconds      test nanos  expected seconds  expected nanos
426             (line!(),            0,              0,                0,              0),
427             (line!(),            1,              1,                1,              1),
428             (line!(),           -1,             -1,               -2,    999_999_999),
429             (line!(),            0,    999_999_999,                0,    999_999_999),
430             (line!(),            0,   -999_999_999,               -1,              1),
431             (line!(),            0,  1_000_000_000,                1,              0),
432             (line!(),            0, -1_000_000_000,               -1,              0),
433             (line!(),            0,  1_000_000_001,                1,              1),
434             (line!(),            0, -1_000_000_001,               -2,    999_999_999),
435             (line!(),           -1,              1,               -1,              1),
436             (line!(),            1,             -1,                0,    999_999_999),
437             (line!(),           -1,  1_000_000_000,                0,              0),
438             (line!(),            1, -1_000_000_000,                0,              0),
439             (line!(), i64::MIN    ,              0,     i64::MIN    ,              0),
440             (line!(), i64::MIN + 1,              0,     i64::MIN + 1,              0),
441             (line!(), i64::MIN    ,              1,     i64::MIN    ,              1),
442             (line!(), i64::MIN    ,  1_000_000_000,     i64::MIN + 1,              0),
443             (line!(), i64::MIN    , -1_000_000_000,     i64::MIN    ,              0),
444             (line!(), i64::MIN + 1, -1_000_000_000,     i64::MIN    ,              0),
445             (line!(), i64::MIN + 2, -1_000_000_000,     i64::MIN + 1,              0),
446             (line!(), i64::MIN    , -1_999_999_998,     i64::MIN    ,              0),
447             (line!(), i64::MIN + 1, -1_999_999_998,     i64::MIN    ,              0),
448             (line!(), i64::MIN + 2, -1_999_999_998,     i64::MIN    ,              2),
449             (line!(), i64::MIN    , -1_999_999_999,     i64::MIN    ,              0),
450             (line!(), i64::MIN + 1, -1_999_999_999,     i64::MIN    ,              0),
451             (line!(), i64::MIN + 2, -1_999_999_999,     i64::MIN    ,              1),
452             (line!(), i64::MIN    , -2_000_000_000,     i64::MIN    ,              0),
453             (line!(), i64::MIN + 1, -2_000_000_000,     i64::MIN    ,              0),
454             (line!(), i64::MIN + 2, -2_000_000_000,     i64::MIN    ,              0),
455             (line!(), i64::MIN    ,   -999_999_998,     i64::MIN    ,              0),
456             (line!(), i64::MIN + 1,   -999_999_998,     i64::MIN    ,              2),
457             (line!(), i64::MAX    ,              0,     i64::MAX    ,              0),
458             (line!(), i64::MAX - 1,              0,     i64::MAX - 1,              0),
459             (line!(), i64::MAX    ,             -1,     i64::MAX - 1,    999_999_999),
460             (line!(), i64::MAX    ,  1_000_000_000,     i64::MAX    ,    999_999_999),
461             (line!(), i64::MAX - 1,  1_000_000_000,     i64::MAX    ,              0),
462             (line!(), i64::MAX - 2,  1_000_000_000,     i64::MAX - 1,              0),
463             (line!(), i64::MAX    ,  1_999_999_998,     i64::MAX    ,    999_999_999),
464             (line!(), i64::MAX - 1,  1_999_999_998,     i64::MAX    ,    999_999_998),
465             (line!(), i64::MAX - 2,  1_999_999_998,     i64::MAX - 1,    999_999_998),
466             (line!(), i64::MAX    ,  1_999_999_999,     i64::MAX    ,    999_999_999),
467             (line!(), i64::MAX - 1,  1_999_999_999,     i64::MAX    ,    999_999_999),
468             (line!(), i64::MAX - 2,  1_999_999_999,     i64::MAX - 1,    999_999_999),
469             (line!(), i64::MAX    ,  2_000_000_000,     i64::MAX    ,    999_999_999),
470             (line!(), i64::MAX - 1,  2_000_000_000,     i64::MAX    ,    999_999_999),
471             (line!(), i64::MAX - 2,  2_000_000_000,     i64::MAX    ,              0),
472             (line!(), i64::MAX    ,    999_999_998,     i64::MAX    ,    999_999_998),
473             (line!(), i64::MAX - 1,    999_999_998,     i64::MAX - 1,    999_999_998),
474         ];
475 
476         for case in cases.iter() {
477             let mut test_timestamp = crate::Timestamp {
478                 seconds: case.1,
479                 nanos: case.2,
480             };
481             test_timestamp.normalize();
482 
483             assert_eq!(
484                 test_timestamp,
485                 crate::Timestamp {
486                     seconds: case.3,
487                     nanos: case.4,
488                 },
489                 "test case on line {} doesn't match",
490                 case.0,
491             );
492         }
493     }
494 }
495