]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/unix/time.rs
Fix a copy-paste error in `Instant::sub_duration`
[rust.git] / src / libstd / sys / unix / time.rs
1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use cmp::Ordering;
12 use libc;
13 use time::Duration;
14
15 pub use self::inner::{Instant, SystemTime, UNIX_EPOCH};
16
17 const NSEC_PER_SEC: u64 = 1_000_000_000;
18
19 #[derive(Copy, Clone)]
20 struct Timespec {
21     t: libc::timespec,
22 }
23
24 impl Timespec {
25     fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
26         if self >= other {
27             Ok(if self.t.tv_nsec >= other.t.tv_nsec {
28                 Duration::new((self.t.tv_sec - other.t.tv_sec) as u64,
29                               (self.t.tv_nsec - other.t.tv_nsec) as u32)
30             } else {
31                 Duration::new((self.t.tv_sec - 1 - other.t.tv_sec) as u64,
32                               self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) -
33                               other.t.tv_nsec as u32)
34             })
35         } else {
36             match other.sub_timespec(self) {
37                 Ok(d) => Err(d),
38                 Err(d) => Ok(d),
39             }
40         }
41     }
42
43     fn add_duration(&self, other: &Duration) -> Timespec {
44         let secs = (self.t.tv_sec as i64).checked_add(other.as_secs() as i64);
45         let mut secs = secs.expect("overflow when adding duration to time");
46
47         // Nano calculations can't overflow because nanos are <1B which fit
48         // in a u32.
49         let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32;
50         if nsec >= NSEC_PER_SEC as u32 {
51             nsec -= NSEC_PER_SEC as u32;
52             secs = secs.checked_add(1).expect("overflow when adding \
53                                                duration to time");
54         }
55         Timespec {
56             t: libc::timespec {
57                 tv_sec: secs as libc::time_t,
58                 tv_nsec: nsec as libc::c_long,
59             },
60         }
61     }
62
63     fn sub_duration(&self, other: &Duration) -> Timespec {
64         let secs = (self.t.tv_sec as i64).checked_sub(other.as_secs() as i64);
65         let mut secs = secs.expect("overflow when subtracting duration \
66                                     from time");
67
68         // Similar to above, nanos can't overflow.
69         let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
70         if nsec < 0 {
71             nsec += NSEC_PER_SEC as i32;
72             secs = secs.checked_sub(1).expect("overflow when subtracting \
73                                                duration from time");
74         }
75         Timespec {
76             t: libc::timespec {
77                 tv_sec: secs as libc::time_t,
78                 tv_nsec: nsec as libc::c_long,
79             },
80         }
81     }
82 }
83
84 impl PartialEq for Timespec {
85     fn eq(&self, other: &Timespec) -> bool {
86         self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec
87     }
88 }
89
90 impl Eq for Timespec {}
91
92 impl PartialOrd for Timespec {
93     fn partial_cmp(&self, other: &Timespec) -> Option<Ordering> {
94         Some(self.cmp(other))
95     }
96 }
97
98 impl Ord for Timespec {
99     fn cmp(&self, other: &Timespec) -> Ordering {
100         let me = (self.t.tv_sec, self.t.tv_nsec);
101         let other = (other.t.tv_sec, other.t.tv_nsec);
102         me.cmp(&other)
103     }
104 }
105
106 #[cfg(any(target_os = "macos", target_os = "ios"))]
107 mod inner {
108     use fmt;
109     use libc;
110     use sync::Once;
111     use sys::cvt;
112     use sys_common::mul_div_u64;
113     use time::Duration;
114
115     use super::NSEC_PER_SEC;
116     use super::Timespec;
117
118     #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
119     pub struct Instant {
120         t: u64
121     }
122
123     #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
124     pub struct SystemTime {
125         t: Timespec,
126     }
127
128     pub const UNIX_EPOCH: SystemTime = SystemTime {
129         t: Timespec {
130             t: libc::timespec {
131                 tv_sec: 0,
132                 tv_nsec: 0,
133             },
134         },
135     };
136
137     impl Instant {
138         pub fn now() -> Instant {
139             Instant { t: unsafe { libc::mach_absolute_time() } }
140         }
141
142         pub fn sub_instant(&self, other: &Instant) -> Duration {
143             let info = info();
144             let diff = self.t.checked_sub(other.t)
145                            .expect("second instant is later than self");
146             let nanos = mul_div_u64(diff, info.numer as u64, info.denom as u64);
147             Duration::new(nanos / NSEC_PER_SEC, (nanos % NSEC_PER_SEC) as u32)
148         }
149
150         pub fn add_duration(&self, other: &Duration) -> Instant {
151             Instant {
152                 t: self.t.checked_add(dur2intervals(other))
153                        .expect("overflow when adding duration to instant"),
154             }
155         }
156
157         pub fn sub_duration(&self, other: &Duration) -> Instant {
158             Instant {
159                 t: self.t.checked_sub(dur2intervals(other))
160                        .expect("overflow when subtracting duration from instant"),
161             }
162         }
163     }
164
165     impl SystemTime {
166         pub fn now() -> SystemTime {
167             use ptr;
168
169             let mut s = libc::timeval {
170                 tv_sec: 0,
171                 tv_usec: 0,
172             };
173             cvt(unsafe {
174                 libc::gettimeofday(&mut s, ptr::null_mut())
175             }).unwrap();
176             return SystemTime::from(s)
177         }
178
179         pub fn sub_time(&self, other: &SystemTime)
180                         -> Result<Duration, Duration> {
181             self.t.sub_timespec(&other.t)
182         }
183
184         pub fn add_duration(&self, other: &Duration) -> SystemTime {
185             SystemTime { t: self.t.add_duration(other) }
186         }
187
188         pub fn sub_duration(&self, other: &Duration) -> SystemTime {
189             SystemTime { t: self.t.sub_duration(other) }
190         }
191     }
192
193     impl From<libc::timeval> for SystemTime {
194         fn from(t: libc::timeval) -> SystemTime {
195             SystemTime::from(libc::timespec {
196                 tv_sec: t.tv_sec,
197                 tv_nsec: (t.tv_usec * 1000) as libc::c_long,
198             })
199         }
200     }
201
202     impl From<libc::timespec> for SystemTime {
203         fn from(t: libc::timespec) -> SystemTime {
204             SystemTime { t: Timespec { t: t } }
205         }
206     }
207
208     impl fmt::Debug for SystemTime {
209         fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
210             f.debug_struct("SystemTime")
211              .field("tv_sec", &self.t.t.tv_sec)
212              .field("tv_nsec", &self.t.t.tv_nsec)
213              .finish()
214         }
215     }
216
217     fn dur2intervals(dur: &Duration) -> u64 {
218         let info = info();
219         let nanos = dur.as_secs().checked_mul(NSEC_PER_SEC).and_then(|nanos| {
220             nanos.checked_add(dur.subsec_nanos() as u64)
221         }).expect("overflow converting duration to nanoseconds");
222         mul_div_u64(nanos, info.denom as u64, info.numer as u64)
223     }
224
225     fn info() -> &'static libc::mach_timebase_info {
226         static mut INFO: libc::mach_timebase_info = libc::mach_timebase_info {
227             numer: 0,
228             denom: 0,
229         };
230         static ONCE: Once = Once::new();
231
232         unsafe {
233             ONCE.call_once(|| {
234                 libc::mach_timebase_info(&mut INFO);
235             });
236             &INFO
237         }
238     }
239 }
240
241 #[cfg(not(any(target_os = "macos", target_os = "ios")))]
242 mod inner {
243     use fmt;
244     use libc;
245     use sys::cvt;
246     use time::Duration;
247
248     use super::Timespec;
249
250     #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
251     pub struct Instant {
252         t: Timespec,
253     }
254
255     #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
256     pub struct SystemTime {
257         t: Timespec,
258     }
259
260     pub const UNIX_EPOCH: SystemTime = SystemTime {
261         t: Timespec {
262             t: libc::timespec {
263                 tv_sec: 0,
264                 tv_nsec: 0,
265             },
266         },
267     };
268
269     impl Instant {
270         pub fn now() -> Instant {
271             Instant { t: now(libc::CLOCK_MONOTONIC) }
272         }
273
274         pub fn sub_instant(&self, other: &Instant) -> Duration {
275             self.t.sub_timespec(&other.t).unwrap_or_else(|_| {
276                 panic!("other was less than the current instant")
277             })
278         }
279
280         pub fn add_duration(&self, other: &Duration) -> Instant {
281             Instant { t: self.t.add_duration(other) }
282         }
283
284         pub fn sub_duration(&self, other: &Duration) -> Instant {
285             Instant { t: self.t.sub_duration(other) }
286         }
287     }
288
289     impl fmt::Debug for Instant {
290         fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
291             f.debug_struct("Instant")
292              .field("tv_sec", &self.t.t.tv_sec)
293              .field("tv_nsec", &self.t.t.tv_nsec)
294              .finish()
295         }
296     }
297
298     impl SystemTime {
299         pub fn now() -> SystemTime {
300             SystemTime { t: now(libc::CLOCK_REALTIME) }
301         }
302
303         pub fn sub_time(&self, other: &SystemTime)
304                         -> Result<Duration, Duration> {
305             self.t.sub_timespec(&other.t)
306         }
307
308         pub fn add_duration(&self, other: &Duration) -> SystemTime {
309             SystemTime { t: self.t.add_duration(other) }
310         }
311
312         pub fn sub_duration(&self, other: &Duration) -> SystemTime {
313             SystemTime { t: self.t.sub_duration(other) }
314         }
315     }
316
317     impl From<libc::timespec> for SystemTime {
318         fn from(t: libc::timespec) -> SystemTime {
319             SystemTime { t: Timespec { t: t } }
320         }
321     }
322
323     impl fmt::Debug for SystemTime {
324         fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
325             f.debug_struct("SystemTime")
326              .field("tv_sec", &self.t.t.tv_sec)
327              .field("tv_nsec", &self.t.t.tv_nsec)
328              .finish()
329         }
330     }
331
332     #[cfg(not(target_os = "dragonfly"))]
333     pub type clock_t = libc::c_int;
334     #[cfg(target_os = "dragonfly")]
335     pub type clock_t = libc::c_ulong;
336
337     fn now(clock: clock_t) -> Timespec {
338         let mut t = Timespec {
339             t: libc::timespec {
340                 tv_sec: 0,
341                 tv_nsec: 0,
342             }
343         };
344         cvt(unsafe {
345             libc::clock_gettime(clock, &mut t.t)
346         }).unwrap();
347         t
348     }
349 }