Skip to content

Commit c2f9605

Browse files
committed
time: add TimeSpec
1 parent f0cfd1e commit c2f9605

File tree

1 file changed

+213
-2
lines changed

1 file changed

+213
-2
lines changed

src/sys/time.rs

+213-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::{fmt, ops};
2-
use libc::{time_t, suseconds_t, timeval};
2+
use libc::{time_t, c_long, suseconds_t, timeval, timespec};
33

4+
const NANOS_PER_SEC: i64 = 1_000_000_000;
45
const MICROS_PER_SEC: i64 = 1_000_000;
56
const SECS_PER_MINUTE: i64 = 60;
67
const SECS_PER_HOUR: i64 = 3600;
@@ -181,6 +182,191 @@ impl PartialEq for TimeVal {
181182

182183
impl Eq for TimeVal { }
183184

185+
#[derive(Clone, Copy)]
186+
pub struct TimeSpec(pub timespec);
187+
188+
impl AsRef<timespec> for TimeSpec {
189+
fn as_ref(&self) -> &timespec {
190+
&self.0
191+
}
192+
}
193+
194+
impl TimeSpec {
195+
#[inline]
196+
pub fn zero() -> TimeSpec {
197+
TimeSpec::nanoseconds(0)
198+
}
199+
200+
#[inline]
201+
pub fn hours(hours: i64) -> TimeSpec {
202+
let secs = hours.checked_mul(SECS_PER_HOUR)
203+
.expect("TimeSpec::hours ouf of bounds");
204+
205+
TimeSpec::seconds(secs)
206+
}
207+
208+
#[inline]
209+
pub fn minutes(minutes: i64) -> TimeSpec {
210+
let secs = minutes.checked_mul(SECS_PER_MINUTE)
211+
.expect("TimeSpec::minutes out of bounds");
212+
213+
TimeSpec::seconds(secs)
214+
}
215+
216+
#[inline]
217+
pub fn seconds(seconds: i64) -> TimeSpec {
218+
assert!(seconds >= time_t::min_value() && seconds <= time_t::max_value(), "TimeSpec out of bounds; seconds={}", seconds);
219+
TimeSpec(timespec { tv_sec: seconds as time_t, tv_nsec: 0 })
220+
}
221+
222+
#[inline]
223+
pub fn milliseconds(milliseconds: i64) -> TimeSpec {
224+
let nanoseconds = milliseconds.checked_mul(1_000_000)
225+
.expect("TimeSpec::milliseconds out of bounds");
226+
227+
TimeSpec::nanoseconds(nanoseconds)
228+
}
229+
230+
#[inline]
231+
pub fn microseconds(microseconds: i64) -> TimeSpec {
232+
let nanoseconds = microseconds.checked_mul(1_000)
233+
.expect("TimeSpec::microseconds out of bounds");
234+
235+
TimeSpec::nanoseconds(nanoseconds)
236+
}
237+
238+
239+
/// Makes a new `TimeSpec` with given number of nanoseconds.
240+
#[inline]
241+
pub fn nanoseconds(nanoseconds: i64) -> TimeSpec {
242+
let (secs, nanos) = div_mod_floor_64(nanoseconds, NANOS_PER_SEC);
243+
assert!(secs >= time_t::min_value() && secs <= time_t::max_value(), "TimeSpec out of bounds; seconds={}", secs);
244+
TimeSpec(timespec { tv_sec: secs as time_t, tv_nsec: nanos as c_long })
245+
}
246+
247+
pub fn num_hours(&self) -> i64 {
248+
self.num_seconds() / 3600
249+
}
250+
251+
pub fn num_minutes(&self) -> i64 {
252+
self.num_seconds() / 60
253+
}
254+
255+
pub fn num_seconds(&self) -> i64 {
256+
if self.0.tv_sec < 0 && self.0.tv_nsec > 0 {
257+
(self.0.tv_sec + 1) as i64
258+
} else {
259+
self.0.tv_sec as i64
260+
}
261+
}
262+
263+
pub fn num_milliseconds(&self) -> i64 {
264+
self.num_nanoseconds() / 1_000_000
265+
}
266+
267+
pub fn num_microseconds(&self) -> i64 {
268+
self.num_nanoseconds() / 1_000
269+
}
270+
271+
pub fn num_nanoseconds(&self) -> i64 {
272+
let secs = self.num_seconds() * NANOS_PER_SEC;
273+
let nsec = self.nanos_mod_sec();
274+
secs + nsec as i64
275+
}
276+
277+
fn nanos_mod_sec(&self) -> suseconds_t {
278+
if self.0.tv_sec < 0 && self.0.tv_nsec > 0 {
279+
self.0.tv_nsec - NANOS_PER_SEC as c_long
280+
} else {
281+
self.0.tv_nsec
282+
}
283+
}
284+
}
285+
286+
impl ops::Neg for TimeSpec {
287+
type Output = TimeSpec;
288+
289+
fn neg(self) -> TimeSpec {
290+
TimeSpec::nanoseconds(-self.num_nanoseconds())
291+
}
292+
}
293+
294+
impl ops::Add for TimeSpec {
295+
type Output = TimeSpec;
296+
297+
fn add(self, rhs: TimeSpec) -> TimeSpec {
298+
TimeSpec::nanoseconds(
299+
self.num_nanoseconds() + rhs.num_nanoseconds())
300+
}
301+
}
302+
303+
impl ops::Sub for TimeSpec {
304+
type Output = TimeSpec;
305+
306+
fn sub(self, rhs: TimeSpec) -> TimeSpec {
307+
TimeSpec::nanoseconds(
308+
self.num_nanoseconds() - rhs.num_nanoseconds())
309+
}
310+
}
311+
312+
impl ops::Mul<i32> for TimeSpec {
313+
type Output = TimeSpec;
314+
315+
fn mul(self, rhs: i32) -> TimeSpec {
316+
let nsec = self.num_nanoseconds().checked_mul(rhs as i64)
317+
.expect("TimeSpec multiply out of bounds");
318+
319+
TimeSpec::nanoseconds(nsec)
320+
}
321+
}
322+
323+
impl ops::Div<i32> for TimeSpec {
324+
type Output = TimeSpec;
325+
326+
fn div(self, rhs: i32) -> TimeSpec {
327+
let nsec = self.num_nanoseconds() / rhs as i64;
328+
TimeSpec::nanoseconds(nsec)
329+
}
330+
}
331+
332+
impl fmt::Display for TimeSpec {
333+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
334+
let (abs, sign) = if self.0.tv_sec < 0 {
335+
(-*self, "-")
336+
} else {
337+
(*self, "")
338+
};
339+
340+
let sec = abs.0.tv_sec;
341+
342+
try!(write!(f, "{}", sign));
343+
344+
if abs.0.tv_nsec == 0 {
345+
if abs.0.tv_sec == 1 {
346+
try!(write!(f, "{} second", sec));
347+
} else {
348+
try!(write!(f, "{} seconds", sec));
349+
}
350+
} else if abs.0.tv_nsec % 1_000_000 == 0 {
351+
try!(write!(f, "{}.{:03} seconds", sec, abs.0.tv_nsec / 1_000_000));
352+
} else if abs.0.tv_nsec % 1_000 == 0 {
353+
try!(write!(f, "{}.{:06} seconds", sec, abs.0.tv_nsec / 1_000));
354+
} else {
355+
try!(write!(f, "{}.{:09} seconds", sec, abs.0.tv_nsec));
356+
}
357+
358+
Ok(())
359+
}
360+
}
361+
362+
impl PartialEq for TimeSpec {
363+
fn eq(&self, rhs: &TimeSpec) -> bool {
364+
self.0.tv_sec == rhs.0.tv_sec && self.0.tv_nsec == rhs.0.tv_nsec
365+
}
366+
}
367+
368+
impl Eq for TimeSpec { }
369+
184370
#[inline]
185371
fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) {
186372
(div_floor_64(this, other), mod_floor_64(this, other))
@@ -211,7 +397,7 @@ fn div_rem_64(this: i64, other: i64) -> (i64, i64) {
211397

212398
#[cfg(test)]
213399
mod test {
214-
use super::TimeVal;
400+
use super::{TimeVal, TimeSpec};
215401

216402
#[test]
217403
pub fn test_time_val() {
@@ -236,4 +422,29 @@ mod test {
236422
assert_eq!(TimeVal::microseconds(42).to_string(), "0.000042 seconds");
237423
assert_eq!(TimeVal::seconds(-86401).to_string(), "-86401 seconds");
238424
}
425+
426+
#[test]
427+
pub fn test_time_spec() {
428+
assert!(TimeSpec::seconds(1) != TimeSpec::zero());
429+
assert!(TimeSpec::seconds(1) + TimeSpec::seconds(2) == TimeSpec::seconds(3));
430+
assert!(TimeSpec::minutes(3) + TimeSpec::seconds(2) == TimeSpec::seconds(182));
431+
}
432+
433+
#[test]
434+
pub fn test_time_spec_neg() {
435+
let a = TimeSpec::seconds(1) + TimeSpec::nanoseconds(123);
436+
let b = TimeSpec::seconds(-1) + TimeSpec::nanoseconds(-123);
437+
438+
assert!(a == -b);
439+
}
440+
441+
#[test]
442+
pub fn test_time_spec_fmt() {
443+
assert_eq!(TimeSpec::zero().to_string(), "0 seconds");
444+
assert_eq!(TimeSpec::seconds(42).to_string(), "42 seconds");
445+
assert_eq!(TimeSpec::milliseconds(42).to_string(), "0.042 seconds");
446+
assert_eq!(TimeSpec::microseconds(42).to_string(), "0.000042 seconds");
447+
assert_eq!(TimeSpec::nanoseconds(42).to_string(), "0.000000042 seconds");
448+
assert_eq!(TimeSpec::seconds(-86401).to_string(), "-86401 seconds");
449+
}
239450
}

0 commit comments

Comments
 (0)