ros_message/
time.rs

1use serde_derive::{Deserialize, Serialize};
2use std::cmp;
3use std::convert::TryInto;
4use std::fmt::Formatter;
5use std::fmt;
6use std::hash::{Hash, Hasher};
7use std::ops;
8use std::time;
9
10const BILLION: i64 = 1_000_000_000;
11
12/// ROS representation of time, with nanosecond precision
13#[derive(Copy, Clone, Default, Serialize, Deserialize, Debug, Eq)]
14pub struct Time {
15    /// Number of seconds.
16    pub sec: u32,
17    /// Number of nanoseconds inside the current second.
18    pub nsec: u32,
19}
20
21impl Hash for Time {
22    fn hash<H: Hasher>(&self, state: &mut H) {
23        self.nanos().hash(state)
24    }
25}
26
27impl Time {
28    /// Creates a new time of zero value.
29    ///
30    /// # Examples
31    ///
32    /// ```
33    /// # use ros_message::Time;
34    /// assert_eq!(Time::new(), Time { sec: 0, nsec: 0 });
35    /// ```
36    #[inline]
37    pub fn new() -> Time {
38        Self::default()
39    }
40
41    /// Creates a time of the given number of nanoseconds.
42    ///
43    /// # Examples
44    ///
45    /// ```
46    /// # use ros_message::Time;
47    /// assert_eq!(Time::from_nanos(0), Time { sec: 0, nsec: 0 });
48    /// assert_eq!(Time::from_nanos(12_000_000_123), Time { sec: 12, nsec: 123 });
49    /// ```
50    #[inline]
51    pub fn from_nanos(t: i64) -> Time {
52        Time {
53            sec: (t / BILLION) as u32,
54            nsec: (t % BILLION) as u32,
55        }
56    }
57
58    /// Creates a time of the given number of seconds.
59    ///
60    /// # Examples
61    ///
62    /// ```
63    /// # use ros_message::Time;
64    /// assert_eq!(Time::from_seconds(0), Time { sec: 0, nsec: 0 });
65    /// assert_eq!(Time::from_seconds(12), Time { sec: 12, nsec: 0 });
66    /// ```
67    #[inline]
68    pub fn from_seconds(sec: u32) -> Time {
69        Time { sec, nsec: 0 }
70    }
71
72    /// Returns the number of nanoseconds in the time.
73    ///
74    /// # Examples
75    ///
76    /// ```
77    /// # use ros_message::Time;
78    /// assert_eq!(Time { sec: 0, nsec: 0 }.nanos(), 0);
79    /// assert_eq!(Time { sec: 12, nsec: 123 }.nanos(), 12_000_000_123);
80    /// ```
81    #[inline]
82    pub fn nanos(self) -> i64 {
83        i64::from(self.sec) * BILLION + i64::from(self.nsec)
84    }
85
86    /// Returns the number of seconds in the time.
87    ///
88    /// # Examples
89    ///
90    /// ```
91    /// # use ros_message::Time;
92    /// assert_eq!(Time { sec: 0, nsec: 0 }.seconds(), 0.0);
93    /// assert_eq!(Time { sec: 12, nsec: 123 }.seconds(), 12.000_000_123);
94    /// ```
95    #[inline]
96    pub fn seconds(self) -> f64 {
97        f64::from(self.sec) + f64::from(self.nsec) / BILLION as f64
98    }
99}
100
101fn display_nanos(nanos: &str, f: &mut Formatter<'_>) -> fmt::Result {
102    // Special display function to handle edge cases like
103    // Duration { sec: -1, nsec: 1 } and Duration { sec: -1, nsec: -1 }
104    let split_point = nanos.len() - 9;
105    let characters = nanos.chars();
106    let (left, right) = characters.as_str().split_at(split_point);
107    write!(f, "{}.{}", left, right)
108}
109
110impl fmt::Display for Time {
111    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
112        display_nanos(&format!("{:010}", self.nanos()), f)
113    }
114}
115
116impl cmp::PartialEq for Time {
117    fn eq(&self, other: &Self) -> bool {
118        self.nanos() == other.nanos()
119    }
120}
121
122impl cmp::PartialOrd for Time {
123    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
124        self.nanos().partial_cmp(&other.nanos())
125    }
126}
127
128impl cmp::Ord for Time {
129    fn cmp(&self, other: &Self) -> cmp::Ordering {
130        self.nanos().cmp(&other.nanos())
131    }
132}
133
134impl From<time::SystemTime> for Time {
135    fn from(other: time::SystemTime) -> Self {
136        let epoch = time::SystemTime::UNIX_EPOCH;
137        let elapsed = other.duration_since(epoch)
138            .expect("Dates before 1970 are not supported by the ROS time format");
139        let sec = elapsed.as_secs()
140            .try_into()
141            .expect("Dates after 2100 are not supported by the ROS time format");
142        Self {
143            sec,
144            nsec: elapsed.subsec_nanos(),
145        }
146    }
147}
148
149impl From<Time> for time::SystemTime {
150    fn from(other: Time) -> Self {
151        let elapsed = time::Duration::new(other.sec.into(), other.nsec);
152        time::SystemTime::UNIX_EPOCH + elapsed
153    }
154}
155
156/// ROS representation of duration, with nanosecond precision
157#[derive(Copy, Clone, Default, Serialize, Deserialize, Debug, Eq)]
158pub struct Duration {
159    /// Number of seconds. Negative for negative durations.
160    pub sec: i32,
161    /// Number of nanoseconds inside the current second. Negative for negative durations.
162    pub nsec: i32,
163}
164
165impl Hash for Duration {
166    fn hash<H: Hasher>(&self, state: &mut H) {
167        self.nanos().hash(state)
168    }
169}
170
171impl fmt::Display for Duration {
172    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
173        let data = self.nanos();
174        display_nanos(
175            &format!(
176                "{}{:010}",
177                if data.is_negative() { "-" } else { "" },
178                data.abs()
179            ),
180            f,
181        )
182    }
183}
184
185impl Duration {
186    /// Creates a new duration of zero value.
187    ///
188    /// # Examples
189    ///
190    /// ```
191    /// # use ros_message::Duration;
192    /// assert_eq!(Duration::new(), Duration { sec: 0, nsec: 0 });
193    /// ```
194    #[inline]
195    pub fn new() -> Duration {
196        Self::default()
197    }
198
199    /// Creates a duration of the given number of nanoseconds.
200    ///
201    /// # Examples
202    ///
203    /// ```
204    /// # use ros_message::Duration;
205    /// assert_eq!(Duration::from_nanos(0), Duration { sec: 0, nsec: 0 });
206    /// assert_eq!(Duration::from_nanos(12_000_000_123), Duration { sec: 12, nsec: 123 });
207    /// assert_eq!(Duration::from_nanos(-12_000_000_123), Duration { sec: -12, nsec: -123 });
208    /// ```
209    #[inline]
210    pub fn from_nanos(t: i64) -> Duration {
211        Duration {
212            sec: (t / BILLION) as i32,
213            nsec: (t % BILLION) as i32,
214        }
215    }
216
217    /// Creates a duration of the given number of seconds.
218    ///
219    /// # Examples
220    ///
221    /// ```
222    /// # use ros_message::Duration;
223    /// assert_eq!(Duration::from_seconds(0), Duration { sec: 0, nsec: 0 });
224    /// assert_eq!(Duration::from_seconds(12), Duration { sec: 12, nsec: 0 });
225    /// assert_eq!(Duration::from_seconds(-12), Duration { sec: -12, nsec: 0 });
226    /// ```
227    #[inline]
228    pub fn from_seconds(sec: i32) -> Duration {
229        Duration { sec, nsec: 0 }
230    }
231
232    /// Returns the number of nanoseconds in the duration.
233    ///
234    /// # Examples
235    ///
236    /// ```
237    /// # use ros_message::Duration;
238    /// assert_eq!(Duration { sec: 0, nsec: 0 }.nanos(), 0);
239    /// assert_eq!(Duration { sec: 12, nsec: 123 }.nanos(), 12_000_000_123);
240    /// assert_eq!(Duration { sec: -12, nsec: -123 }.nanos(), -12_000_000_123);
241    /// ```
242    #[inline]
243    pub fn nanos(self) -> i64 {
244        i64::from(self.sec) * BILLION + i64::from(self.nsec)
245    }
246
247    /// Returns the number of seconds in the duration.
248    ///
249    /// # Examples
250    ///
251    /// ```
252    /// # use ros_message::Duration;
253    /// assert_eq!(Duration { sec: 0, nsec: 0 }.seconds(), 0.0);
254    /// assert_eq!(Duration { sec: 12, nsec: 123 }.seconds(), 12.000_000_123);
255    /// assert_eq!(Duration { sec: -12, nsec: -123 }.seconds(), -12.000_000_123);
256    /// ```
257    #[inline]
258    pub fn seconds(self) -> f64 {
259        f64::from(self.sec) + f64::from(self.nsec) / BILLION as f64
260    }
261}
262
263impl cmp::PartialEq for Duration {
264    fn eq(&self, other: &Self) -> bool {
265        self.nanos() == other.nanos()
266    }
267}
268
269impl cmp::PartialOrd for Duration {
270    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
271        self.nanos().partial_cmp(&other.nanos())
272    }
273}
274
275impl cmp::Ord for Duration {
276    fn cmp(&self, other: &Self) -> cmp::Ordering {
277        self.nanos().cmp(&other.nanos())
278    }
279}
280
281impl ops::Add<Duration> for Time {
282    type Output = Time;
283    fn add(self, rhs: Duration) -> Self::Output {
284        Time::from_nanos(self.nanos() + rhs.nanos())
285    }
286}
287
288impl ops::Add<Duration> for Duration {
289    type Output = Duration;
290    fn add(self, rhs: Duration) -> Self::Output {
291        Duration::from_nanos(self.nanos() + rhs.nanos())
292    }
293}
294
295impl ops::Sub<Time> for Time {
296    type Output = Duration;
297    fn sub(self, rhs: Time) -> Self::Output {
298        Duration::from_nanos(self.nanos() - rhs.nanos())
299    }
300}
301
302impl ops::Sub<Duration> for Time {
303    type Output = Time;
304    fn sub(self, rhs: Duration) -> Self::Output {
305        Time::from_nanos(self.nanos() - rhs.nanos())
306    }
307}
308
309impl ops::Sub<Duration> for Duration {
310    type Output = Duration;
311    fn sub(self, rhs: Duration) -> Self::Output {
312        Duration::from_nanos(self.nanos() - rhs.nanos())
313    }
314}
315
316impl ops::Neg for Duration {
317    type Output = Duration;
318    fn neg(self) -> Self::Output {
319        Duration {
320            sec: -self.sec,
321            nsec: -self.nsec,
322        }
323    }
324}
325
326impl From<time::Duration> for Duration {
327    fn from(std_duration: time::Duration) -> Self {
328        let sec = std_duration.as_secs()
329            .try_into()
330            .expect("Durations longer than 68 years are not supported by the ROS time format");
331        Duration {
332            sec,
333            nsec: std_duration.subsec_nanos() as i32,
334        }
335    }
336}
337
338impl From<Duration> for time::Duration {
339    fn from(other: Duration) -> Self {
340        let mut extra_sec = other.nsec / 1_000_000_000;
341        let mut nsec = other.nsec % 1_000_000_000;
342        if nsec < 0 {
343            extra_sec -= 1;
344            nsec += 1_000_000_000;
345        }
346
347        Self::new(
348            (other.sec + extra_sec).try_into().unwrap(),
349            nsec as u32,
350        )
351    }
352}