]>
Commit | Line | Data |
---|---|---|
85aaf69f SL |
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. | |
92a42be0 SL |
10 | |
11 | use cmp::Ordering; | |
12 | use fmt; | |
13 | use mem; | |
62682a34 | 14 | use sync::Once; |
92a42be0 SL |
15 | use sys::c; |
16 | use sys::cvt; | |
17 | use sys_common::mul_div_u64; | |
18 | use time::Duration; | |
85aaf69f | 19 | |
d9579d0f | 20 | const NANOS_PER_SEC: u64 = 1_000_000_000; |
92a42be0 | 21 | const INTERVALS_PER_SEC: u64 = NANOS_PER_SEC / 100; |
c34b1796 | 22 | |
92a42be0 SL |
23 | #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] |
24 | pub struct Instant { | |
25 | t: c::LARGE_INTEGER, | |
85aaf69f SL |
26 | } |
27 | ||
92a42be0 SL |
28 | #[derive(Copy, Clone)] |
29 | pub struct SystemTime { | |
30 | t: c::FILETIME, | |
31 | } | |
32 | ||
33 | const INTERVALS_TO_UNIX_EPOCH: u64 = 11_644_473_600 * INTERVALS_PER_SEC; | |
34 | ||
35 | pub const UNIX_EPOCH: SystemTime = SystemTime { | |
36 | t: c::FILETIME { | |
37 | dwLowDateTime: INTERVALS_TO_UNIX_EPOCH as u32, | |
38 | dwHighDateTime: (INTERVALS_TO_UNIX_EPOCH >> 32) as u32, | |
39 | }, | |
40 | }; | |
41 | ||
42 | impl Instant { | |
43 | pub fn now() -> Instant { | |
44 | let mut t = Instant { t: 0 }; | |
45 | cvt(unsafe { | |
46 | c::QueryPerformanceCounter(&mut t.t) | |
47 | }).unwrap(); | |
85aaf69f SL |
48 | t |
49 | } | |
92a42be0 SL |
50 | |
51 | pub fn sub_instant(&self, other: &Instant) -> Duration { | |
52 | // Values which are +- 1 need to be considered as basically the same | |
53 | // units in time due to various measurement oddities, according to | |
54 | // Windows [1] | |
55 | // | |
56 | // [1]: | |
57 | // https://msdn.microsoft.com/en-us/library/windows/desktop | |
58 | // /dn553408%28v=vs.85%29.aspx#guidance | |
59 | if other.t > self.t && other.t - self.t == 1 { | |
60 | return Duration::new(0, 0) | |
61 | } | |
62 | let diff = (self.t as u64).checked_sub(other.t as u64) | |
63 | .expect("specified instant was later than \ | |
64 | self"); | |
65 | let nanos = mul_div_u64(diff, NANOS_PER_SEC, frequency() as u64); | |
66 | Duration::new(nanos / NANOS_PER_SEC, (nanos % NANOS_PER_SEC) as u32) | |
67 | } | |
68 | ||
69 | pub fn add_duration(&self, other: &Duration) -> Instant { | |
70 | let freq = frequency() as u64; | |
71 | let t = other.as_secs().checked_mul(freq).and_then(|i| { | |
72 | (self.t as u64).checked_add(i) | |
73 | }).and_then(|i| { | |
74 | i.checked_add(mul_div_u64(other.subsec_nanos() as u64, freq, | |
75 | NANOS_PER_SEC)) | |
76 | }).expect("overflow when adding duration to time"); | |
77 | Instant { | |
78 | t: t as c::LARGE_INTEGER, | |
79 | } | |
80 | } | |
81 | ||
82 | pub fn sub_duration(&self, other: &Duration) -> Instant { | |
83 | let freq = frequency() as u64; | |
84 | let t = other.as_secs().checked_mul(freq).and_then(|i| { | |
85 | (self.t as u64).checked_sub(i) | |
86 | }).and_then(|i| { | |
87 | i.checked_sub(mul_div_u64(other.subsec_nanos() as u64, freq, | |
88 | NANOS_PER_SEC)) | |
89 | }).expect("overflow when subtracting duration from time"); | |
90 | Instant { | |
91 | t: t as c::LARGE_INTEGER, | |
92 | } | |
93 | } | |
85aaf69f SL |
94 | } |
95 | ||
92a42be0 SL |
96 | impl SystemTime { |
97 | pub fn now() -> SystemTime { | |
98 | unsafe { | |
99 | let mut t: SystemTime = mem::zeroed(); | |
100 | c::GetSystemTimeAsFileTime(&mut t.t); | |
101 | return t | |
102 | } | |
103 | } | |
85aaf69f | 104 | |
92a42be0 SL |
105 | fn from_intervals(intervals: i64) -> SystemTime { |
106 | SystemTime { | |
107 | t: c::FILETIME { | |
108 | dwLowDateTime: intervals as c::DWORD, | |
109 | dwHighDateTime: (intervals >> 32) as c::DWORD, | |
110 | } | |
111 | } | |
112 | } | |
113 | ||
114 | fn intervals(&self) -> i64 { | |
115 | (self.t.dwLowDateTime as i64) | ((self.t.dwHighDateTime as i64) << 32) | |
116 | } | |
117 | ||
118 | pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> { | |
119 | let me = self.intervals(); | |
120 | let other = other.intervals(); | |
121 | if me >= other { | |
122 | Ok(intervals2dur((me - other) as u64)) | |
123 | } else { | |
124 | Err(intervals2dur((other - me) as u64)) | |
125 | } | |
126 | } | |
127 | ||
128 | pub fn add_duration(&self, other: &Duration) -> SystemTime { | |
129 | let intervals = self.intervals().checked_add(dur2intervals(other)) | |
130 | .expect("overflow when adding duration to time"); | |
131 | SystemTime::from_intervals(intervals) | |
132 | } | |
133 | ||
134 | pub fn sub_duration(&self, other: &Duration) -> SystemTime { | |
135 | let intervals = self.intervals().checked_sub(dur2intervals(other)) | |
136 | .expect("overflow when subtracting from time"); | |
137 | SystemTime::from_intervals(intervals) | |
138 | } | |
139 | } | |
140 | ||
141 | impl PartialEq for SystemTime { | |
142 | fn eq(&self, other: &SystemTime) -> bool { | |
143 | self.intervals() == other.intervals() | |
85aaf69f SL |
144 | } |
145 | } | |
146 | ||
92a42be0 | 147 | impl Eq for SystemTime {} |
85aaf69f | 148 | |
92a42be0 SL |
149 | impl PartialOrd for SystemTime { |
150 | fn partial_cmp(&self, other: &SystemTime) -> Option<Ordering> { | |
151 | Some(self.cmp(other)) | |
152 | } | |
153 | } | |
154 | ||
155 | impl Ord for SystemTime { | |
156 | fn cmp(&self, other: &SystemTime) -> Ordering { | |
157 | self.intervals().cmp(&other.intervals()) | |
85aaf69f SL |
158 | } |
159 | } | |
c34b1796 | 160 | |
92a42be0 SL |
161 | impl fmt::Debug for SystemTime { |
162 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
163 | f.debug_struct("SystemTime") | |
164 | .field("intervals", &self.intervals()) | |
165 | .finish() | |
166 | } | |
167 | } | |
168 | ||
169 | fn dur2intervals(d: &Duration) -> i64 { | |
170 | d.as_secs().checked_mul(INTERVALS_PER_SEC).and_then(|i| { | |
171 | i.checked_add(d.subsec_nanos() as u64 / 100) | |
172 | }).expect("overflow when converting duration to intervals") as i64 | |
c34b1796 AL |
173 | } |
174 | ||
92a42be0 SL |
175 | fn intervals2dur(intervals: u64) -> Duration { |
176 | Duration::new(intervals / INTERVALS_PER_SEC, | |
177 | ((intervals % INTERVALS_PER_SEC) * 100) as u32) | |
178 | } | |
179 | ||
180 | fn frequency() -> c::LARGE_INTEGER { | |
181 | static mut FREQUENCY: c::LARGE_INTEGER = 0; | |
182 | static ONCE: Once = Once::new(); | |
183 | ||
184 | unsafe { | |
185 | ONCE.call_once(|| { | |
186 | cvt(c::QueryPerformanceFrequency(&mut FREQUENCY)).unwrap(); | |
187 | }); | |
188 | FREQUENCY | |
189 | } | |
c34b1796 | 190 | } |