Skip to content

Commit

Permalink
time: use libc::timeval for TimeVal
Browse files Browse the repository at this point in the history
  • Loading branch information
abbradar committed Feb 19, 2016
1 parent dbce477 commit c4a38ec
Showing 1 changed file with 43 additions and 34 deletions.
77 changes: 43 additions & 34 deletions src/sys/time.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
use std::{fmt, ops};
use libc::{time_t, suseconds_t};

#[repr(C)]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct TimeVal {
pub tv_sec: time_t,
pub tv_usec: suseconds_t,
}
use libc::{time_t, suseconds_t, timeval};

const MICROS_PER_SEC: i64 = 1_000_000;
const SECS_PER_MINUTE: i64 = 60;
const SECS_PER_HOUR: i64 = 3600;

#[cfg(target_pointer_width = "64")]
const MAX_SECONDS: i64 = (::std::i64::MAX / MICROS_PER_SEC) - 1;
#[derive(Clone, Copy)]
pub struct TimeVal {
pub val: timeval,

This comment has been minimized.

Copy link
@kamalmarhubi

kamalmarhubi Feb 20, 2016

can you use the newtype pattern here:

pub struct TimeVal(pub timeval);
}

#[cfg(target_pointer_width = "32")]
const MAX_SECONDS: i64 = ::std::isize::MAX as i64;
impl AsRef<timeval> for TimeVal {
fn as_ref(&self) -> &timeval {
&self.val
}
}

const MIN_SECONDS: i64 = -MAX_SECONDS;
impl AsMut<timeval> for TimeVal {
fn as_mut(&mut self) -> &mut timeval {
&mut self.val
}
}

impl TimeVal {
#[inline]
Expand All @@ -44,8 +46,8 @@ impl TimeVal {

#[inline]
pub fn seconds(seconds: i64) -> TimeVal {
assert!(seconds >= MIN_SECONDS && seconds <= MAX_SECONDS, "TimeVal out of bounds; seconds={}", seconds);
TimeVal { tv_sec: seconds as time_t, tv_usec: 0 }
assert!(seconds >= time_t::min_value() && seconds <= time_t::max_value(), "TimeVal out of bounds; seconds={}", seconds);
TimeVal { val: timeval { tv_sec: seconds as time_t, tv_usec: 0 } }
}

#[inline]
Expand All @@ -60,8 +62,8 @@ impl TimeVal {
#[inline]
pub fn microseconds(microseconds: i64) -> TimeVal {
let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
assert!(secs >= MIN_SECONDS && secs <= MAX_SECONDS, "TimeVal out of bounds");
TimeVal { tv_sec: secs as time_t, tv_usec: micros as suseconds_t }
assert!(secs >= time_t::min_value() && secs <= time_t::max_value(), "TimeVal out of bounds; seconds={}", secs);
TimeVal { val: timeval { tv_sec: secs as time_t, tv_usec: micros as suseconds_t } }
}

pub fn num_hours(&self) -> i64 {
Expand All @@ -73,10 +75,10 @@ impl TimeVal {
}

pub fn num_seconds(&self) -> i64 {
if self.tv_sec < 0 && self.tv_usec > 0 {
(self.tv_sec + 1) as i64
if self.val.tv_sec < 0 && self.val.tv_usec > 0 {
(self.val.tv_sec + 1) as i64
} else {
self.tv_sec as i64
self.val.tv_sec as i64
}
}

Expand All @@ -91,10 +93,10 @@ impl TimeVal {
}

fn micros_mod_sec(&self) -> suseconds_t {
if self.tv_sec < 0 && self.tv_usec > 0 {
self.tv_usec - MICROS_PER_SEC as suseconds_t
if self.val.tv_sec < 0 && self.val.tv_usec > 0 {
self.val.tv_usec - MICROS_PER_SEC as suseconds_t
} else {
self.tv_usec
self.val.tv_usec
}
}
}
Expand Down Expand Up @@ -147,32 +149,40 @@ impl ops::Div<i32> for TimeVal {

impl fmt::Display for TimeVal {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let (abs, sign) = if self.tv_sec < 0 {
let (abs, sign) = if self.val.tv_sec < 0 {
(-*self, "-")
} else {
(*self, "")
};

let sec = abs.tv_sec;
let sec = abs.val.tv_sec;

try!(write!(f, "{}", sign));

if abs.tv_usec == 0 {
if abs.tv_sec == 1 {
if abs.val.tv_usec == 0 {
if abs.val.tv_sec == 1 {
try!(write!(f, "{} second", sec));
} else {
try!(write!(f, "{} seconds", sec));
}
} else if abs.tv_usec % 1000 == 0 {
try!(write!(f, "{}.{:03} seconds", sec, abs.tv_usec / 1000));
} else if abs.val.tv_usec % 1_000 == 0 {
try!(write!(f, "{}.{:03} seconds", sec, abs.val.tv_usec / 1_000));
} else {
try!(write!(f, "{}.{:06} seconds", sec, abs.tv_usec));
try!(write!(f, "{}.{:06} seconds", sec, abs.val.tv_usec));
}

Ok(())
}
}

impl PartialEq for TimeVal {
fn eq(&self, rhs: &TimeVal) -> bool {
self.val.tv_sec == rhs.val.tv_sec && self.val.tv_usec == rhs.val.tv_usec
}
}

impl Eq for TimeVal { }

#[inline]
fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) {
(div_floor_64(this, other), mod_floor_64(this, other))
Expand Down Expand Up @@ -208,17 +218,16 @@ mod test {
#[test]
pub fn test_time_val() {
assert!(TimeVal::seconds(1) != TimeVal::zero());
assert_eq!(TimeVal::seconds(1) + TimeVal::seconds(2), TimeVal::seconds(3));
assert_eq!(TimeVal::minutes(3) + TimeVal::seconds(2),
TimeVal::seconds(182));
assert!(TimeVal::seconds(1) + TimeVal::seconds(2) == TimeVal::seconds(3));
assert!(TimeVal::minutes(3) + TimeVal::seconds(2) == TimeVal::seconds(182));
}

#[test]
pub fn test_time_val_neg() {
let a = TimeVal::seconds(1) + TimeVal::microseconds(123);
let b = TimeVal::seconds(-1) + TimeVal::microseconds(-123);

assert_eq!(a, -b);
assert!(a == -b);

This comment has been minimized.

Copy link
@kamalmarhubi

kamalmarhubi Feb 20, 2016

prefer assert_eq because it will print left and right hand sides if they differ

This comment has been minimized.

Copy link
@abbradar

abbradar Feb 20, 2016

Author Owner

Unfortunately timeval and timespec don't have Debug derived, so we can't use assert_eq. Well, I can try to make a PR to libc for it -- what do you think?

This comment has been minimized.

Copy link
@kamalmarhubi

kamalmarhubi Feb 20, 2016

oh I tried this already in the past with some other traits... not sure they'll accept it:

Currently, however, the libc crate is intended to be as thin a wrapper as possible around the system libc, for example it only provides the guarantee that structs are Copy (which also forces a Clone impl).

At this time we're not looking for higher level abstractions in libc (e.g. any other form of "Rust code" like Eq or Hash). That's in general left to higher level libraries.

rust-lang/libc#159 (comment)

}

#[test]
Expand Down

1 comment on commit c4a38ec

@kamalmarhubi
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not know about this module before, and I don't like it! But the changes make sense to me. :-)

Please sign in to comment.