]>
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. | |
c1a9b12d | 54 | #[stable(feature = "duration", since = "1.3.0")] |
54a0048b | 55 | #[inline] |
d9579d0f AL |
56 | pub fn new(secs: u64, nanos: u32) -> Duration { |
57 | let secs = secs + (nanos / NANOS_PER_SEC) as u64; | |
58 | let nanos = nanos % NANOS_PER_SEC; | |
1a4d82fc JJ |
59 | Duration { secs: secs, nanos: nanos } |
60 | } | |
61 | ||
d9579d0f | 62 | /// Creates a new `Duration` from the specified number of seconds. |
c1a9b12d | 63 | #[stable(feature = "duration", since = "1.3.0")] |
54a0048b | 64 | #[inline] |
d9579d0f AL |
65 | pub fn from_secs(secs: u64) -> Duration { |
66 | Duration { secs: secs, nanos: 0 } | |
1a4d82fc JJ |
67 | } |
68 | ||
d9579d0f | 69 | /// Creates a new `Duration` from the specified number of milliseconds. |
c1a9b12d | 70 | #[stable(feature = "duration", since = "1.3.0")] |
54a0048b | 71 | #[inline] |
d9579d0f AL |
72 | pub fn from_millis(millis: u64) -> Duration { |
73 | let secs = millis / MILLIS_PER_SEC; | |
74 | let nanos = ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI; | |
75 | Duration { secs: secs, nanos: nanos } | |
1a4d82fc | 76 | } |
1a4d82fc | 77 | |
d9579d0f AL |
78 | /// Returns the number of whole seconds represented by this duration. |
79 | /// | |
80 | /// The extra precision represented by this duration is ignored (e.g. extra | |
81 | /// nanoseconds are not represented in the returned value). | |
c1a9b12d | 82 | #[stable(feature = "duration", since = "1.3.0")] |
54a0048b | 83 | #[inline] |
c1a9b12d SL |
84 | pub fn as_secs(&self) -> u64 { self.secs } |
85 | ||
c1a9b12d SL |
86 | /// Returns the nanosecond precision represented by this duration. |
87 | /// | |
88 | /// This method does **not** return the length of the duration when | |
89 | /// represented by nanoseconds. The returned number always represents a | |
90 | /// fractional portion of a second (e.g. it is less than one billion). | |
91 | #[stable(feature = "duration", since = "1.3.0")] | |
54a0048b | 92 | #[inline] |
c1a9b12d | 93 | pub fn subsec_nanos(&self) -> u32 { self.nanos } |
1a4d82fc JJ |
94 | } |
95 | ||
92a42be0 | 96 | #[stable(feature = "duration", since = "1.3.0")] |
1a4d82fc JJ |
97 | impl Add for Duration { |
98 | type Output = Duration; | |
99 | ||
100 | fn add(self, rhs: Duration) -> Duration { | |
d9579d0f AL |
101 | let mut secs = self.secs.checked_add(rhs.secs) |
102 | .expect("overflow when adding durations"); | |
1a4d82fc JJ |
103 | let mut nanos = self.nanos + rhs.nanos; |
104 | if nanos >= NANOS_PER_SEC { | |
105 | nanos -= NANOS_PER_SEC; | |
d9579d0f | 106 | secs = secs.checked_add(1).expect("overflow when adding durations"); |
1a4d82fc | 107 | } |
d9579d0f | 108 | debug_assert!(nanos < NANOS_PER_SEC); |
1a4d82fc JJ |
109 | Duration { secs: secs, nanos: nanos } |
110 | } | |
111 | } | |
112 | ||
54a0048b SL |
113 | #[stable(feature = "time_augmented_assignment", since = "1.9.0")] |
114 | impl AddAssign for Duration { | |
115 | fn add_assign(&mut self, rhs: Duration) { | |
116 | *self = *self + rhs; | |
117 | } | |
118 | } | |
119 | ||
92a42be0 | 120 | #[stable(feature = "duration", since = "1.3.0")] |
1a4d82fc JJ |
121 | impl Sub for Duration { |
122 | type Output = Duration; | |
123 | ||
124 | fn sub(self, rhs: Duration) -> Duration { | |
d9579d0f AL |
125 | let mut secs = self.secs.checked_sub(rhs.secs) |
126 | .expect("overflow when subtracting durations"); | |
127 | let nanos = if self.nanos >= rhs.nanos { | |
128 | self.nanos - rhs.nanos | |
129 | } else { | |
130 | secs = secs.checked_sub(1) | |
131 | .expect("overflow when subtracting durations"); | |
132 | self.nanos + NANOS_PER_SEC - rhs.nanos | |
133 | }; | |
134 | debug_assert!(nanos < NANOS_PER_SEC); | |
1a4d82fc JJ |
135 | Duration { secs: secs, nanos: nanos } |
136 | } | |
137 | } | |
138 | ||
54a0048b SL |
139 | #[stable(feature = "time_augmented_assignment", since = "1.9.0")] |
140 | impl SubAssign for Duration { | |
141 | fn sub_assign(&mut self, rhs: Duration) { | |
142 | *self = *self - rhs; | |
143 | } | |
144 | } | |
145 | ||
92a42be0 | 146 | #[stable(feature = "duration", since = "1.3.0")] |
d9579d0f | 147 | impl Mul<u32> for Duration { |
1a4d82fc JJ |
148 | type Output = Duration; |
149 | ||
d9579d0f AL |
150 | fn mul(self, rhs: u32) -> Duration { |
151 | // Multiply nanoseconds as u64, because it cannot overflow that way. | |
152 | let total_nanos = self.nanos as u64 * rhs as u64; | |
153 | let extra_secs = total_nanos / (NANOS_PER_SEC as u64); | |
154 | let nanos = (total_nanos % (NANOS_PER_SEC as u64)) as u32; | |
155 | let secs = self.secs.checked_mul(rhs as u64) | |
156 | .and_then(|s| s.checked_add(extra_secs)) | |
157 | .expect("overflow when multiplying duration"); | |
158 | debug_assert!(nanos < NANOS_PER_SEC); | |
159 | Duration { secs: secs, nanos: nanos } | |
1a4d82fc JJ |
160 | } |
161 | } | |
162 | ||
54a0048b SL |
163 | #[stable(feature = "time_augmented_assignment", since = "1.9.0")] |
164 | impl MulAssign<u32> for Duration { | |
165 | fn mul_assign(&mut self, rhs: u32) { | |
166 | *self = *self * rhs; | |
167 | } | |
168 | } | |
169 | ||
92a42be0 | 170 | #[stable(feature = "duration", since = "1.3.0")] |
d9579d0f | 171 | impl Div<u32> for Duration { |
1a4d82fc JJ |
172 | type Output = Duration; |
173 | ||
d9579d0f AL |
174 | fn div(self, rhs: u32) -> Duration { |
175 | let secs = self.secs / (rhs as u64); | |
176 | let carry = self.secs - secs * (rhs as u64); | |
177 | let extra_nanos = carry * (NANOS_PER_SEC as u64) / (rhs as u64); | |
178 | let nanos = self.nanos / rhs + (extra_nanos as u32); | |
179 | debug_assert!(nanos < NANOS_PER_SEC); | |
1a4d82fc JJ |
180 | Duration { secs: secs, nanos: nanos } |
181 | } | |
182 | } | |
183 | ||
54a0048b SL |
184 | #[stable(feature = "time_augmented_assignment", since = "1.9.0")] |
185 | impl DivAssign<u32> for Duration { | |
186 | fn div_assign(&mut self, rhs: u32) { | |
187 | *self = *self / rhs; | |
188 | } | |
189 | } | |
190 | ||
1a4d82fc JJ |
191 | #[cfg(test)] |
192 | mod tests { | |
d9579d0f | 193 | use super::Duration; |
1a4d82fc JJ |
194 | |
195 | #[test] | |
d9579d0f AL |
196 | fn creation() { |
197 | assert!(Duration::from_secs(1) != Duration::from_secs(0)); | |
198 | assert_eq!(Duration::from_secs(1) + Duration::from_secs(2), | |
199 | Duration::from_secs(3)); | |
200 | assert_eq!(Duration::from_millis(10) + Duration::from_secs(4), | |
201 | Duration::new(4, 10 * 1_000_000)); | |
202 | assert_eq!(Duration::from_millis(4000), Duration::new(4, 0)); | |
1a4d82fc JJ |
203 | } |
204 | ||
205 | #[test] | |
d9579d0f | 206 | fn secs() { |
c1a9b12d SL |
207 | assert_eq!(Duration::new(0, 0).as_secs(), 0); |
208 | assert_eq!(Duration::from_secs(1).as_secs(), 1); | |
209 | assert_eq!(Duration::from_millis(999).as_secs(), 0); | |
210 | assert_eq!(Duration::from_millis(1001).as_secs(), 1); | |
1a4d82fc JJ |
211 | } |
212 | ||
213 | #[test] | |
d9579d0f | 214 | fn nanos() { |
c1a9b12d SL |
215 | assert_eq!(Duration::new(0, 0).subsec_nanos(), 0); |
216 | assert_eq!(Duration::new(0, 5).subsec_nanos(), 5); | |
217 | assert_eq!(Duration::new(0, 1_000_000_001).subsec_nanos(), 1); | |
218 | assert_eq!(Duration::from_secs(1).subsec_nanos(), 0); | |
219 | assert_eq!(Duration::from_millis(999).subsec_nanos(), 999 * 1_000_000); | |
220 | assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1 * 1_000_000); | |
1a4d82fc JJ |
221 | } |
222 | ||
223 | #[test] | |
d9579d0f AL |
224 | fn add() { |
225 | assert_eq!(Duration::new(0, 0) + Duration::new(0, 1), | |
226 | Duration::new(0, 1)); | |
227 | assert_eq!(Duration::new(0, 500_000_000) + Duration::new(0, 500_000_001), | |
228 | Duration::new(1, 1)); | |
1a4d82fc JJ |
229 | } |
230 | ||
231 | #[test] | |
d9579d0f AL |
232 | fn sub() { |
233 | assert_eq!(Duration::new(0, 1) - Duration::new(0, 0), | |
234 | Duration::new(0, 1)); | |
235 | assert_eq!(Duration::new(0, 500_000_001) - Duration::new(0, 500_000_000), | |
236 | Duration::new(0, 1)); | |
237 | assert_eq!(Duration::new(1, 0) - Duration::new(0, 1), | |
238 | Duration::new(0, 999_999_999)); | |
1a4d82fc JJ |
239 | } |
240 | ||
d9579d0f AL |
241 | #[test] #[should_panic] |
242 | fn sub_bad1() { | |
243 | Duration::new(0, 0) - Duration::new(0, 1); | |
1a4d82fc JJ |
244 | } |
245 | ||
d9579d0f AL |
246 | #[test] #[should_panic] |
247 | fn sub_bad2() { | |
248 | Duration::new(0, 0) - Duration::new(1, 0); | |
1a4d82fc JJ |
249 | } |
250 | ||
251 | #[test] | |
d9579d0f AL |
252 | fn mul() { |
253 | assert_eq!(Duration::new(0, 1) * 2, Duration::new(0, 2)); | |
254 | assert_eq!(Duration::new(1, 1) * 3, Duration::new(3, 3)); | |
255 | assert_eq!(Duration::new(0, 500_000_001) * 4, Duration::new(2, 4)); | |
256 | assert_eq!(Duration::new(0, 500_000_001) * 4000, | |
257 | Duration::new(2000, 4000)); | |
1a4d82fc JJ |
258 | } |
259 | ||
260 | #[test] | |
d9579d0f AL |
261 | fn div() { |
262 | assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0)); | |
263 | assert_eq!(Duration::new(1, 1) / 3, Duration::new(0, 333_333_333)); | |
264 | assert_eq!(Duration::new(99, 999_999_000) / 100, | |
265 | Duration::new(0, 999_999_990)); | |
1a4d82fc | 266 | } |
1a4d82fc | 267 | } |