]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2012-2014 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 | ||
54a0048b | 11 | use ops::{Add, Sub, Mul, Div, AddAssign, SubAssign, MulAssign, DivAssign}; |
d9579d0f AL |
12 | |
13 | const NANOS_PER_SEC: u32 = 1_000_000_000; | |
14 | const NANOS_PER_MILLI: u32 = 1_000_000; | |
15 | const MILLIS_PER_SEC: u64 = 1_000; | |
16 | ||
17 | /// A duration type to represent a span of time, typically used for system | |
18 | /// timeouts. | |
19 | /// | |
20 | /// Each duration is composed of a number of seconds and nanosecond precision. | |
21 | /// APIs binding a system timeout will typically round up the nanosecond | |
22 | /// precision if the underlying system does not support that level of precision. | |
23 | /// | |
24 | /// Durations implement many common traits, including `Add`, `Sub`, and other | |
25 | /// ops traits. Currently a duration may only be inspected for its number of | |
26 | /// seconds and its nanosecond precision. | |
27 | /// | |
28 | /// # Examples | |
29 | /// | |
30 | /// ``` | |
d9579d0f AL |
31 | /// use std::time::Duration; |
32 | /// | |
33 | /// let five_seconds = Duration::new(5, 0); | |
34 | /// let five_seconds_and_five_nanos = five_seconds + Duration::new(0, 5); | |
35 | /// | |
c1a9b12d SL |
36 | /// assert_eq!(five_seconds_and_five_nanos.as_secs(), 5); |
37 | /// assert_eq!(five_seconds_and_five_nanos.subsec_nanos(), 5); | |
d9579d0f AL |
38 | /// |
39 | /// let ten_millis = Duration::from_millis(10); | |
40 | /// ``` | |
c1a9b12d | 41 | #[stable(feature = "duration", since = "1.3.0")] |
9cc50fc6 | 42 | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] |
1a4d82fc | 43 | pub struct Duration { |
d9579d0f AL |
44 | secs: u64, |
45 | nanos: u32, // Always 0 <= nanos < NANOS_PER_SEC | |
1a4d82fc JJ |
46 | } |
47 | ||
1a4d82fc | 48 | impl Duration { |
b039eaaf | 49 | /// Creates a new `Duration` from the specified number of seconds and |
d9579d0f AL |
50 | /// additional nanosecond precision. |
51 | /// | |
52 | /// If the nanoseconds is greater than 1 billion (the number of nanoseconds | |
53 | /// in a second), then it will carry over into the seconds provided. | |
a7813a04 XL |
54 | /// |
55 | /// # Panics | |
56 | /// | |
57 | /// This constructor will panic if the carry from the nanoseconds overflows | |
58 | /// the seconds counter. | |
c1a9b12d | 59 | #[stable(feature = "duration", since = "1.3.0")] |
54a0048b | 60 | #[inline] |
d9579d0f | 61 | pub fn new(secs: u64, nanos: u32) -> Duration { |
a7813a04 XL |
62 | let secs = secs.checked_add((nanos / NANOS_PER_SEC) as u64) |
63 | .expect("overflow in Duration::new"); | |
d9579d0f | 64 | let nanos = nanos % NANOS_PER_SEC; |
1a4d82fc JJ |
65 | Duration { secs: secs, nanos: nanos } |
66 | } | |
67 | ||
d9579d0f | 68 | /// Creates a new `Duration` from the specified number of seconds. |
c1a9b12d | 69 | #[stable(feature = "duration", since = "1.3.0")] |
54a0048b | 70 | #[inline] |
d9579d0f AL |
71 | pub fn from_secs(secs: u64) -> Duration { |
72 | Duration { secs: secs, nanos: 0 } | |
1a4d82fc JJ |
73 | } |
74 | ||
d9579d0f | 75 | /// Creates a new `Duration` from the specified number of milliseconds. |
c1a9b12d | 76 | #[stable(feature = "duration", since = "1.3.0")] |
54a0048b | 77 | #[inline] |
d9579d0f AL |
78 | pub fn from_millis(millis: u64) -> Duration { |
79 | let secs = millis / MILLIS_PER_SEC; | |
80 | let nanos = ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI; | |
81 | Duration { secs: secs, nanos: nanos } | |
1a4d82fc | 82 | } |
1a4d82fc | 83 | |
d9579d0f AL |
84 | /// Returns the number of whole seconds represented by this duration. |
85 | /// | |
9e0c209e | 86 | /// The extra precision represented by this duration is ignored (i.e. extra |
d9579d0f | 87 | /// nanoseconds are not represented in the returned value). |
c1a9b12d | 88 | #[stable(feature = "duration", since = "1.3.0")] |
54a0048b | 89 | #[inline] |
c1a9b12d SL |
90 | pub fn as_secs(&self) -> u64 { self.secs } |
91 | ||
c1a9b12d SL |
92 | /// Returns the nanosecond precision represented by this duration. |
93 | /// | |
94 | /// This method does **not** return the length of the duration when | |
95 | /// represented by nanoseconds. The returned number always represents a | |
9e0c209e | 96 | /// fractional portion of a second (i.e. it is less than one billion). |
c1a9b12d | 97 | #[stable(feature = "duration", since = "1.3.0")] |
54a0048b | 98 | #[inline] |
c1a9b12d | 99 | pub fn subsec_nanos(&self) -> u32 { self.nanos } |
9e0c209e SL |
100 | |
101 | /// Checked duration addition. Computes `self + other`, returning `None` | |
102 | /// if overflow occurred. | |
103 | /// | |
104 | /// # Examples | |
105 | /// | |
106 | /// Basic usage: | |
107 | /// | |
108 | /// ``` | |
109 | /// #![feature(duration_checked_ops)] | |
110 | /// | |
111 | /// use std::time::Duration; | |
112 | /// | |
113 | /// assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), Some(Duration::new(0, 1))); | |
114 | /// assert_eq!(Duration::new(1, 0).checked_add(Duration::new(std::u64::MAX, 0)), None); | |
115 | /// ``` | |
116 | #[unstable(feature = "duration_checked_ops", issue = "35774")] | |
117 | #[inline] | |
118 | pub fn checked_add(self, rhs: Duration) -> Option<Duration> { | |
119 | if let Some(mut secs) = self.secs.checked_add(rhs.secs) { | |
120 | let mut nanos = self.nanos + rhs.nanos; | |
121 | if nanos >= NANOS_PER_SEC { | |
122 | nanos -= NANOS_PER_SEC; | |
123 | if let Some(new_secs) = secs.checked_add(1) { | |
124 | secs = new_secs; | |
125 | } else { | |
126 | return None; | |
127 | } | |
128 | } | |
129 | debug_assert!(nanos < NANOS_PER_SEC); | |
130 | Some(Duration { | |
131 | secs: secs, | |
132 | nanos: nanos, | |
133 | }) | |
134 | } else { | |
135 | None | |
136 | } | |
137 | } | |
138 | ||
139 | /// Checked duration subtraction. Computes `self + other`, returning `None` | |
140 | /// if the result would be negative or if underflow occurred. | |
141 | /// | |
142 | /// # Examples | |
143 | /// | |
144 | /// Basic usage: | |
145 | /// | |
146 | /// ``` | |
147 | /// #![feature(duration_checked_ops)] | |
148 | /// | |
149 | /// use std::time::Duration; | |
150 | /// | |
151 | /// assert_eq!(Duration::new(0, 1).checked_sub(Duration::new(0, 0)), Some(Duration::new(0, 1))); | |
152 | /// assert_eq!(Duration::new(0, 0).checked_sub(Duration::new(0, 1)), None); | |
153 | /// ``` | |
154 | #[unstable(feature = "duration_checked_ops", issue = "35774")] | |
155 | #[inline] | |
156 | pub fn checked_sub(self, rhs: Duration) -> Option<Duration> { | |
157 | if let Some(mut secs) = self.secs.checked_sub(rhs.secs) { | |
158 | let nanos = if self.nanos >= rhs.nanos { | |
159 | self.nanos - rhs.nanos | |
160 | } else { | |
161 | if let Some(sub_secs) = secs.checked_sub(1) { | |
162 | secs = sub_secs; | |
163 | self.nanos + NANOS_PER_SEC - rhs.nanos | |
164 | } else { | |
165 | return None; | |
166 | } | |
167 | }; | |
168 | debug_assert!(nanos < NANOS_PER_SEC); | |
169 | Some(Duration { secs: secs, nanos: nanos }) | |
170 | } else { | |
171 | None | |
172 | } | |
173 | } | |
174 | ||
175 | /// Checked duration multiplication. Computes `self * other`, returning | |
176 | /// `None` if underflow or overflow occurred. | |
177 | /// | |
178 | /// # Examples | |
179 | /// | |
180 | /// Basic usage: | |
181 | /// | |
182 | /// ``` | |
183 | /// #![feature(duration_checked_ops)] | |
184 | /// | |
185 | /// use std::time::Duration; | |
186 | /// | |
187 | /// assert_eq!(Duration::new(0, 500_000_001).checked_mul(2), Some(Duration::new(1, 2))); | |
188 | /// assert_eq!(Duration::new(std::u64::MAX - 1, 0).checked_mul(2), None); | |
189 | /// ``` | |
190 | #[unstable(feature = "duration_checked_ops", issue = "35774")] | |
191 | #[inline] | |
192 | pub fn checked_mul(self, rhs: u32) -> Option<Duration> { | |
193 | // Multiply nanoseconds as u64, because it cannot overflow that way. | |
194 | let total_nanos = self.nanos as u64 * rhs as u64; | |
195 | let extra_secs = total_nanos / (NANOS_PER_SEC as u64); | |
196 | let nanos = (total_nanos % (NANOS_PER_SEC as u64)) as u32; | |
197 | if let Some(secs) = self.secs | |
198 | .checked_mul(rhs as u64) | |
199 | .and_then(|s| s.checked_add(extra_secs)) { | |
200 | debug_assert!(nanos < NANOS_PER_SEC); | |
201 | Some(Duration { | |
202 | secs: secs, | |
203 | nanos: nanos, | |
204 | }) | |
205 | } else { | |
206 | None | |
207 | } | |
208 | } | |
209 | ||
210 | /// Checked duration division. Computes `self / other`, returning `None` | |
211 | /// if `other == 0` or the operation results in underflow or overflow. | |
212 | /// | |
213 | /// # Examples | |
214 | /// | |
215 | /// Basic usage: | |
216 | /// | |
217 | /// ``` | |
218 | /// #![feature(duration_checked_ops)] | |
219 | /// | |
220 | /// use std::time::Duration; | |
221 | /// | |
222 | /// assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0))); | |
223 | /// assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000))); | |
224 | /// assert_eq!(Duration::new(2, 0).checked_div(0), None); | |
225 | /// ``` | |
226 | #[unstable(feature = "duration_checked_ops", issue = "35774")] | |
227 | #[inline] | |
228 | pub fn checked_div(self, rhs: u32) -> Option<Duration> { | |
229 | if rhs != 0 { | |
230 | let secs = self.secs / (rhs as u64); | |
231 | let carry = self.secs - secs * (rhs as u64); | |
232 | let extra_nanos = carry * (NANOS_PER_SEC as u64) / (rhs as u64); | |
233 | let nanos = self.nanos / rhs + (extra_nanos as u32); | |
234 | debug_assert!(nanos < NANOS_PER_SEC); | |
235 | Some(Duration { secs: secs, nanos: nanos }) | |
236 | } else { | |
237 | None | |
238 | } | |
239 | } | |
1a4d82fc JJ |
240 | } |
241 | ||
92a42be0 | 242 | #[stable(feature = "duration", since = "1.3.0")] |
1a4d82fc JJ |
243 | impl Add for Duration { |
244 | type Output = Duration; | |
245 | ||
246 | fn add(self, rhs: Duration) -> Duration { | |
9e0c209e | 247 | self.checked_add(rhs).expect("overflow when adding durations") |
1a4d82fc JJ |
248 | } |
249 | } | |
250 | ||
54a0048b SL |
251 | #[stable(feature = "time_augmented_assignment", since = "1.9.0")] |
252 | impl AddAssign for Duration { | |
253 | fn add_assign(&mut self, rhs: Duration) { | |
254 | *self = *self + rhs; | |
255 | } | |
256 | } | |
257 | ||
92a42be0 | 258 | #[stable(feature = "duration", since = "1.3.0")] |
1a4d82fc JJ |
259 | impl Sub for Duration { |
260 | type Output = Duration; | |
261 | ||
262 | fn sub(self, rhs: Duration) -> Duration { | |
9e0c209e | 263 | self.checked_sub(rhs).expect("overflow when subtracting durations") |
1a4d82fc JJ |
264 | } |
265 | } | |
266 | ||
54a0048b SL |
267 | #[stable(feature = "time_augmented_assignment", since = "1.9.0")] |
268 | impl SubAssign for Duration { | |
269 | fn sub_assign(&mut self, rhs: Duration) { | |
270 | *self = *self - rhs; | |
271 | } | |
272 | } | |
273 | ||
92a42be0 | 274 | #[stable(feature = "duration", since = "1.3.0")] |
d9579d0f | 275 | impl Mul<u32> for Duration { |
1a4d82fc JJ |
276 | type Output = Duration; |
277 | ||
d9579d0f | 278 | fn mul(self, rhs: u32) -> Duration { |
9e0c209e | 279 | self.checked_mul(rhs).expect("overflow when multiplying duration by scalar") |
1a4d82fc JJ |
280 | } |
281 | } | |
282 | ||
54a0048b SL |
283 | #[stable(feature = "time_augmented_assignment", since = "1.9.0")] |
284 | impl MulAssign<u32> for Duration { | |
285 | fn mul_assign(&mut self, rhs: u32) { | |
286 | *self = *self * rhs; | |
287 | } | |
288 | } | |
289 | ||
92a42be0 | 290 | #[stable(feature = "duration", since = "1.3.0")] |
d9579d0f | 291 | impl Div<u32> for Duration { |
1a4d82fc JJ |
292 | type Output = Duration; |
293 | ||
d9579d0f | 294 | fn div(self, rhs: u32) -> Duration { |
9e0c209e | 295 | self.checked_div(rhs).expect("divide by zero error when dividing duration by scalar") |
1a4d82fc JJ |
296 | } |
297 | } | |
298 | ||
54a0048b SL |
299 | #[stable(feature = "time_augmented_assignment", since = "1.9.0")] |
300 | impl DivAssign<u32> for Duration { | |
301 | fn div_assign(&mut self, rhs: u32) { | |
302 | *self = *self / rhs; | |
303 | } | |
304 | } | |
305 | ||
1a4d82fc JJ |
306 | #[cfg(test)] |
307 | mod tests { | |
d9579d0f | 308 | use super::Duration; |
1a4d82fc JJ |
309 | |
310 | #[test] | |
d9579d0f AL |
311 | fn creation() { |
312 | assert!(Duration::from_secs(1) != Duration::from_secs(0)); | |
313 | assert_eq!(Duration::from_secs(1) + Duration::from_secs(2), | |
314 | Duration::from_secs(3)); | |
315 | assert_eq!(Duration::from_millis(10) + Duration::from_secs(4), | |
316 | Duration::new(4, 10 * 1_000_000)); | |
317 | assert_eq!(Duration::from_millis(4000), Duration::new(4, 0)); | |
1a4d82fc JJ |
318 | } |
319 | ||
320 | #[test] | |
d9579d0f | 321 | fn secs() { |
c1a9b12d SL |
322 | assert_eq!(Duration::new(0, 0).as_secs(), 0); |
323 | assert_eq!(Duration::from_secs(1).as_secs(), 1); | |
324 | assert_eq!(Duration::from_millis(999).as_secs(), 0); | |
325 | assert_eq!(Duration::from_millis(1001).as_secs(), 1); | |
1a4d82fc JJ |
326 | } |
327 | ||
328 | #[test] | |
d9579d0f | 329 | fn nanos() { |
c1a9b12d SL |
330 | assert_eq!(Duration::new(0, 0).subsec_nanos(), 0); |
331 | assert_eq!(Duration::new(0, 5).subsec_nanos(), 5); | |
332 | assert_eq!(Duration::new(0, 1_000_000_001).subsec_nanos(), 1); | |
333 | assert_eq!(Duration::from_secs(1).subsec_nanos(), 0); | |
334 | assert_eq!(Duration::from_millis(999).subsec_nanos(), 999 * 1_000_000); | |
335 | assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1 * 1_000_000); | |
1a4d82fc JJ |
336 | } |
337 | ||
338 | #[test] | |
d9579d0f AL |
339 | fn add() { |
340 | assert_eq!(Duration::new(0, 0) + Duration::new(0, 1), | |
341 | Duration::new(0, 1)); | |
342 | assert_eq!(Duration::new(0, 500_000_000) + Duration::new(0, 500_000_001), | |
343 | Duration::new(1, 1)); | |
1a4d82fc JJ |
344 | } |
345 | ||
9e0c209e SL |
346 | #[test] |
347 | fn checked_add() { | |
348 | assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), | |
349 | Some(Duration::new(0, 1))); | |
350 | assert_eq!(Duration::new(0, 500_000_000).checked_add(Duration::new(0, 500_000_001)), | |
351 | Some(Duration::new(1, 1))); | |
352 | assert_eq!(Duration::new(1, 0).checked_add(Duration::new(::u64::MAX, 0)), None); | |
353 | } | |
354 | ||
1a4d82fc | 355 | #[test] |
d9579d0f AL |
356 | fn sub() { |
357 | assert_eq!(Duration::new(0, 1) - Duration::new(0, 0), | |
358 | Duration::new(0, 1)); | |
359 | assert_eq!(Duration::new(0, 500_000_001) - Duration::new(0, 500_000_000), | |
360 | Duration::new(0, 1)); | |
361 | assert_eq!(Duration::new(1, 0) - Duration::new(0, 1), | |
362 | Duration::new(0, 999_999_999)); | |
1a4d82fc JJ |
363 | } |
364 | ||
9e0c209e SL |
365 | #[test] |
366 | fn checked_sub() { | |
367 | let zero = Duration::new(0, 0); | |
368 | let one_nano = Duration::new(0, 1); | |
369 | let one_sec = Duration::new(1, 0); | |
370 | assert_eq!(one_nano.checked_sub(zero), Some(Duration::new(0, 1))); | |
371 | assert_eq!(one_sec.checked_sub(one_nano), | |
372 | Some(Duration::new(0, 999_999_999))); | |
373 | assert_eq!(zero.checked_sub(one_nano), None); | |
374 | assert_eq!(zero.checked_sub(one_sec), None); | |
375 | } | |
376 | ||
d9579d0f AL |
377 | #[test] #[should_panic] |
378 | fn sub_bad1() { | |
379 | Duration::new(0, 0) - Duration::new(0, 1); | |
1a4d82fc JJ |
380 | } |
381 | ||
d9579d0f AL |
382 | #[test] #[should_panic] |
383 | fn sub_bad2() { | |
384 | Duration::new(0, 0) - Duration::new(1, 0); | |
1a4d82fc JJ |
385 | } |
386 | ||
387 | #[test] | |
d9579d0f AL |
388 | fn mul() { |
389 | assert_eq!(Duration::new(0, 1) * 2, Duration::new(0, 2)); | |
390 | assert_eq!(Duration::new(1, 1) * 3, Duration::new(3, 3)); | |
391 | assert_eq!(Duration::new(0, 500_000_001) * 4, Duration::new(2, 4)); | |
392 | assert_eq!(Duration::new(0, 500_000_001) * 4000, | |
393 | Duration::new(2000, 4000)); | |
1a4d82fc JJ |
394 | } |
395 | ||
9e0c209e SL |
396 | #[test] |
397 | fn checked_mul() { | |
398 | assert_eq!(Duration::new(0, 1).checked_mul(2), Some(Duration::new(0, 2))); | |
399 | assert_eq!(Duration::new(1, 1).checked_mul(3), Some(Duration::new(3, 3))); | |
400 | assert_eq!(Duration::new(0, 500_000_001).checked_mul(4), Some(Duration::new(2, 4))); | |
401 | assert_eq!(Duration::new(0, 500_000_001).checked_mul(4000), | |
402 | Some(Duration::new(2000, 4000))); | |
403 | assert_eq!(Duration::new(::u64::MAX - 1, 0).checked_mul(2), None); | |
404 | } | |
405 | ||
1a4d82fc | 406 | #[test] |
d9579d0f AL |
407 | fn div() { |
408 | assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0)); | |
409 | assert_eq!(Duration::new(1, 1) / 3, Duration::new(0, 333_333_333)); | |
410 | assert_eq!(Duration::new(99, 999_999_000) / 100, | |
411 | Duration::new(0, 999_999_990)); | |
1a4d82fc | 412 | } |
9e0c209e SL |
413 | |
414 | #[test] | |
415 | fn checked_div() { | |
416 | assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0))); | |
417 | assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000))); | |
418 | assert_eq!(Duration::new(2, 0).checked_div(0), None); | |
419 | } | |
1a4d82fc | 420 | } |