1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 //! Type-safe bindings for Zircon timer objects.
6 
7 use {AsHandleRef, ClockId, HandleBased, Handle, HandleRef, Status};
8 use {sys, ok};
9 use std::ops;
10 use std::time as stdtime;
11 
12 #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
13 pub struct Duration(sys::zx_duration_t);
14 
15 #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
16 pub struct Time(sys::zx_time_t);
17 
18 impl From<stdtime::Duration> for Duration {
19     fn from(dur: stdtime::Duration) -> Self {
20         Duration::from_seconds(dur.as_secs()) +
21         Duration::from_nanos(dur.subsec_nanos() as u64)
22     }
23 }
24 
25 impl From<Duration> for stdtime::Duration {
26     fn from(dur: Duration) -> Self {
27         let secs = dur.seconds();
28         let nanos = (dur.nanos() - (secs * 1_000_000_000)) as u32;
29         stdtime::Duration::new(secs, nanos)
30     }
31 }
32 
33 impl ops::Add<Duration> for Time {
34     type Output = Time;
35     fn add(self, dur: Duration) -> Time {
36         Time::from_nanos(dur.nanos() + self.nanos())
37     }
38 }
39 
40 impl ops::Add<Time> for Duration {
41     type Output = Time;
42     fn add(self, time: Time) -> Time {
GeneratePluralRanges(SupplementalDataInfo supplementalDataInfo)43         Time::from_nanos(self.nanos() + time.nanos())
44     }
45 }
46 
47 impl ops::Add for Duration {
48     type Output = Duration;
49     fn add(self, dur: Duration) -> Duration {
50         Duration::from_nanos(self.nanos() + dur.nanos())
51     }
52 }
53 
54 impl ops::Sub for Duration {
55     type Output = Duration;
56     fn sub(self, dur: Duration) -> Duration {
generateSamples(CLDRFile english, Factory factory)57         Duration::from_nanos(self.nanos() - dur.nanos())
58     }
59 }
60 
61 impl ops::Sub<Duration> for Time {
62     type Output = Time;
63     fn sub(self, dur: Duration) -> Time {
64         Time::from_nanos(self.nanos() - dur.nanos())
65     }
66 }
67 
68 impl ops::AddAssign for Duration {
69     fn add_assign(&mut self, dur: Duration) {
70         self.0 += dur.nanos()
71     }
72 }
73 
74 impl ops::SubAssign for Duration {
75     fn sub_assign(&mut self, dur: Duration) {
76         self.0 -= dur.nanos()
77     }
78 }
79 
80 impl ops::AddAssign<Duration> for Time {
81     fn add_assign(&mut self, dur: Duration) {
82         self.0 += dur.nanos()
83     }
84 }
85 
86 impl ops::SubAssign<Duration> for Time {
87     fn sub_assign(&mut self, dur: Duration) {
88         self.0 -= dur.nanos()
89     }
90 }
91 
92 impl<T> ops::Mul<T> for Duration
93     where T: Into<u64>
94 {
95     type Output = Self;
96     fn mul(self, mul: T) -> Self {
97         Duration::from_nanos(self.0 * mul.into())
98     }
99 }
100 
101 impl<T> ops::Div<T> for Duration
102     where T: Into<u64>
103 {
104     type Output = Self;
105     fn div(self, div: T) -> Self {
106         Duration::from_nanos(self.0 / div.into())
107     }
getRangeInfo(CLDRFile cldrFile)108 }
109 
110 impl Duration {
111     /// Sleep for the given amount of time.
112     pub fn sleep(self) {
113         Time::after(self).sleep()
114     }
115 
116     pub fn nanos(self) -> u64 {
117         self.0
118     }
119 
120     pub fn millis(self) -> u64 {
121         self.0 / 1_000_000
122     }
123 
124     pub fn seconds(self) -> u64 {
125         self.millis() / 1_000
126     }
127 
128     pub fn minutes(self) -> u64 {
129         self.seconds() / 60
130     }
131 
132     pub fn hours(self) -> u64 {
133         self.minutes() / 60
134     }
135 
136     pub fn from_nanos(nanos: u64) -> Self {
137         Duration(nanos)
138     }
139 
140     pub fn from_millis(millis: u64) -> Self {
141         Duration(millis * 1_000_000)
142     }
143 
144     pub fn from_seconds(secs: u64) -> Self {
145         Duration::from_millis(secs * 1_000)
146     }
147 
148     pub fn from_minutes(min: u64) -> Self {
149         Duration::from_seconds(min * 60)
150     }
151 
152     pub fn from_hours(hours: u64) -> Self {
153         Duration::from_minutes(hours * 60)
154     }
155 
156     /// Returns a `Time` which is a `Duration` after the current time.
157     /// `duration.after_now()` is equivalent to `Time::after(duration)`.
158     pub fn after_now(self) -> Time {
159         Time::after(self)
160     }
161 }
162 
163 pub trait DurationNum: Sized {
164     fn nanos(self) -> Duration;
165     fn millis(self) -> Duration;
166     fn seconds(self) -> Duration;
167     fn minutes(self) -> Duration;
168     fn hours(self) -> Duration;
169 
170     // Singular versions to allow for `1.milli()` and `1.second()`, etc.
171     fn milli(self) -> Duration { self.millis() }
172     fn second(self) -> Duration { self.seconds() }
RangeSample(Count start, Count end, Count result, FixedDecimal min, FixedDecimal max, String startExample, String endExample, String resultExample)173     fn minute(self) -> Duration { self.minutes() }
174     fn hour(self) -> Duration { self.hours() }
175 }
176 
177 // Note: this could be implemented for other unsized integer types, but it doesn't seem
178 // necessary to support the usual case.
179 impl DurationNum for u64 {
180     fn nanos(self) -> Duration {
181         Duration::from_nanos(self)
182     }
183 
184     fn millis(self) -> Duration {
185         Duration::from_millis(self)
186     }
187 
188     fn seconds(self) -> Duration {
189         Duration::from_seconds(self)
190     }
191 
192     fn minutes(self) -> Duration {
193         Duration::from_minutes(self)
194     }
195 
format(DecimalFormat nf, FixedDecimal minSample)196     fn hours(self) -> Duration {
197         Duration::from_hours(self)
198     }
199 }
200 
201 impl Time {
202     pub const INFINITE: Time = Time(sys::ZX_TIME_INFINITE);
203 
204     /// Get the current time, from the specific clock id.
205     ///
getExample(String locale, PluralMinimalPairs samplePatterns, Count r, String numString)206     /// Wraps the
207     /// [zx_time_get](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/time_get.md)
208     /// syscall.
209     pub fn get(clock_id: ClockId) -> Time {
210         unsafe { Time(sys::zx_time_get(clock_id as u32)) }
211     }
212 
213     /// Compute a deadline for the time in the future that is the given `Duration` away.
214     ///
215     /// Wraps the
216     /// [zx_deadline_after](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/deadline_after.md)
217     /// syscall.
218     pub fn after(duration: Duration) -> Time {
219         unsafe { Time(sys::zx_deadline_after(duration.0)) }
220     }
221 
222     /// Sleep until the given time.
223     ///
224     /// Wraps the
225     /// [zx_nanosleep](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/nanosleep.md)
226     /// syscall.
227     pub fn sleep(self) {
228         unsafe { sys::zx_nanosleep(self.0); }
229     }
230 
231     pub fn nanos(self) -> u64 {
232         self.0
reformatPluralRanges()233     }
234 
235     pub fn from_nanos(nanos: u64) -> Self {
236         Time(nanos)
237     }
238 }
239 
240 /// Read the number of high-precision timer ticks since boot. These ticks may be processor cycles,
241 /// high speed timer, profiling timer, etc. They are not guaranteed to continue advancing when the
242 /// system is asleep.
243 ///
244 /// Wraps the
245 /// [zx_ticks_get](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/ticks_get.md)
246 /// syscall.
247 pub fn ticks_get() -> u64 {
248     unsafe { sys::zx_ticks_get() }
249 }
250 
251 /// Return the number of high-precision timer ticks in a second.
252 ///
253 /// Wraps the
254 /// [zx_ticks_per_second](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/ticks_per_second.md)
255 /// syscall.
256 pub fn ticks_per_second() -> u64 {
257     unsafe { sys::zx_ticks_per_second() }
258 }
259 
260 /// An object representing a Zircon timer, such as the one returned by
261 /// [zx_timer_create](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/timer_create.md).
262 ///
263 /// As essentially a subtype of `Handle`, it can be freely interconverted.
264 #[derive(Debug, Eq, PartialEq)]
265 pub struct Timer(Handle);
266 impl_handle_based!(Timer);
267 
268 impl Timer {
269     /// Create a timer, an object that can signal when a specified point in time has been reached.
270     /// Wraps the
271     /// [zx_timer_create](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/timer_create.md)
272     /// syscall.
273     pub fn create(clock_id: ClockId) -> Result<Timer, Status> {
274         let mut out = 0;
275         let opts = 0;
276         let status = unsafe { sys::zx_timer_create(opts, clock_id as u32, &mut out) };
277         ok(status)?;
278         unsafe {
279             Ok(Self::from(Handle::from_raw(out)))
280         }
reformat(PluralRanges pluralRanges, Set<Count> counts)281     }
282 
283     /// Start a one-shot timer that will fire when `deadline` passes. Wraps the
284     /// [zx_timer_set](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/timer_set.md)
285     /// syscall.
286     pub fn set(&self, deadline: Time, slack: Duration) -> Result<(), Status> {
287         let status = unsafe {
288             sys::zx_timer_set(self.raw_handle(), deadline.nanos(), slack.nanos())
289         };
290         ok(status)
291     }
292 
293     /// Cancels a pending timer that was started with start(). Wraps the
294     /// [zx_timer_cancel](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/timer_cancel.md)
295     /// syscall.
296     pub fn cancel(&self) -> Result<(), Status> {
297         let status = unsafe { sys::zx_timer_cancel(self.raw_handle()) };
298         ok(status)
299     }
300 }
301 
302 #[cfg(test)]
303 mod tests {
304     use super::*;
305     use Signals;
306 
307     #[test]
308     fn create_timer_invalid_clock() {
309         assert_eq!(Timer::create(ClockId::UTC).unwrap_err(), Status::INVALID_ARGS);
310         assert_eq!(Timer::create(ClockId::Thread), Err(Status::INVALID_ARGS));
311     }
312 
313     #[test]
314     fn into_from_std() {
315         let std_dur = stdtime::Duration::new(25, 25);
316         assert_eq!(std_dur, stdtime::Duration::from(Duration::from(std_dur)));
317     }
318 
319     #[test]
320     fn timer_basic() {
minimize(PluralRanges pluralRanges, PluralInfo pluralInfo)321         let slack = 0.millis();
322         let ten_ms = 10.millis();
323         let five_secs = 5.seconds();
324         let six_secs = 6.seconds();
325 
326         // Create a timer
327         let timer = Timer::create(ClockId::Monotonic).unwrap();
328 
329         // Should not signal yet.
330         assert_eq!(
331             timer.wait_handle(Signals::TIMER_SIGNALED, ten_ms.after_now()),
332             Err(Status::TIMED_OUT));
333 
334         // Set it, and soon it should signal.
335         assert_eq!(timer.set(five_secs.after_now(), slack), Ok(()));
336         assert_eq!(
337             timer.wait_handle(Signals::TIMER_SIGNALED, six_secs.after_now()),
338             Ok(Signals::TIMER_SIGNALED));
339 
340         // Cancel it, and it should stop signalling.
341         assert_eq!(timer.cancel(), Ok(()));
342         assert_eq!(
343             timer.wait_handle(Signals::TIMER_SIGNALED, ten_ms.after_now()),
344             Err(Status::TIMED_OUT));
345     }
346 }
347