Skip to content

Commit 57f67e2

Browse files
committed
Add TimeVal and helpers
1 parent 67d6580 commit 57f67e2

File tree

2 files changed

+241
-0
lines changed

2 files changed

+241
-0
lines changed

src/sys/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,5 @@ pub mod wait;
3131
pub mod mman;
3232

3333
pub mod uio;
34+
35+
pub mod time;

src/sys/time.rs

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
use std::{fmt, ops};
2+
use std::num::Int;
3+
use std::i64;
4+
use libc::{time_t, suseconds_t};
5+
6+
#[repr(C)]
7+
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
8+
pub struct TimeVal {
9+
pub tv_sec: time_t,
10+
pub tv_usec: suseconds_t,
11+
}
12+
13+
const MICROS_PER_SEC: i64 = 1_000_000;
14+
const SECS_PER_MINUTE: i64 = 60;
15+
const SECS_PER_HOUR: i64 = 3600;
16+
17+
const MIN: TimeVal = TimeVal {
18+
tv_sec: -(i64::MAX / MICROS_PER_SEC - 1),
19+
tv_usec: (-(MICROS_PER_SEC - 1)) as suseconds_t,
20+
};
21+
22+
const MAX: TimeVal = TimeVal {
23+
tv_sec: i64::MAX / MICROS_PER_SEC - 1,
24+
tv_usec: (MICROS_PER_SEC - 1) as suseconds_t,
25+
};
26+
27+
impl TimeVal {
28+
#[inline]
29+
pub fn zero() -> TimeVal {
30+
TimeVal::microseconds(0)
31+
}
32+
33+
#[inline]
34+
pub fn hours(hours: i64) -> TimeVal {
35+
let secs = hours.checked_mul(SECS_PER_HOUR)
36+
.expect("TimeVal::hours ouf of bounds");
37+
38+
TimeVal::seconds(secs)
39+
}
40+
41+
#[inline]
42+
pub fn minutes(minutes: i64) -> TimeVal {
43+
let secs = minutes.checked_mul(SECS_PER_MINUTE)
44+
.expect("TimeVal::minutes out of bounds");
45+
46+
TimeVal::seconds(secs)
47+
}
48+
49+
#[inline]
50+
pub fn seconds(seconds: i64) -> TimeVal {
51+
let ret = TimeVal { tv_sec: seconds, tv_usec: 0 };
52+
assert!(ret >= MIN && ret <= MAX, "TimeVal out of bounds");
53+
ret
54+
}
55+
56+
#[inline]
57+
pub fn milliseconds(milliseconds: i64) -> TimeVal {
58+
let microseconds = milliseconds.checked_mul(1_000)
59+
.expect("TimeVal::milliseconds out of bounds");
60+
61+
TimeVal::microseconds(microseconds)
62+
}
63+
64+
/// Makes a new `TimeVal` with given number of microseconds.
65+
#[inline]
66+
#[unstable(feature = "std_misc")]
67+
pub fn microseconds(microseconds: i64) -> TimeVal {
68+
let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
69+
let ret = TimeVal { tv_sec: secs, tv_usec: micros as suseconds_t };
70+
assert!(ret >= MIN && ret <= MAX, "TimeVal out of bounds");
71+
ret
72+
}
73+
74+
pub fn num_hours(&self) -> i64 {
75+
self.num_seconds() / 3600
76+
}
77+
78+
pub fn num_minutes(&self) -> i64 {
79+
self.num_seconds() / 60
80+
}
81+
82+
pub fn num_seconds(&self) -> i64 {
83+
if self.tv_sec < 0 && self.tv_usec > 0 {
84+
self.tv_sec + 1
85+
} else {
86+
self.tv_sec
87+
}
88+
}
89+
90+
pub fn num_milliseconds(&self) -> i64 {
91+
self.num_microseconds() / 1_000
92+
}
93+
94+
pub fn num_microseconds(&self) -> i64 {
95+
let secs = self.num_seconds() * 1_000_000;
96+
let usec = self.micros_mod_sec();
97+
secs + usec as i64
98+
}
99+
100+
fn micros_mod_sec(&self) -> suseconds_t {
101+
if self.tv_sec < 0 && self.tv_usec > 0 {
102+
self.tv_usec - MICROS_PER_SEC as suseconds_t
103+
} else {
104+
self.tv_usec
105+
}
106+
}
107+
}
108+
109+
impl ops::Neg for TimeVal {
110+
type Output = TimeVal;
111+
112+
fn neg(self) -> TimeVal {
113+
TimeVal::microseconds(-self.num_microseconds())
114+
}
115+
}
116+
117+
impl ops::Add for TimeVal {
118+
type Output = TimeVal;
119+
120+
fn add(self, rhs: TimeVal) -> TimeVal {
121+
TimeVal::microseconds(
122+
self.num_microseconds() + rhs.num_microseconds())
123+
}
124+
}
125+
126+
impl ops::Sub for TimeVal {
127+
type Output = TimeVal;
128+
129+
fn sub(self, rhs: TimeVal) -> TimeVal {
130+
TimeVal::microseconds(
131+
self.num_microseconds() - rhs.num_microseconds())
132+
}
133+
}
134+
135+
impl ops::Mul<i32> for TimeVal {
136+
type Output = TimeVal;
137+
138+
fn mul(self, rhs: i32) -> TimeVal {
139+
let usec = self.num_microseconds().checked_mul(rhs as i64)
140+
.expect("TimeVal multiply out of bounds");
141+
142+
TimeVal::microseconds(usec)
143+
}
144+
}
145+
146+
impl ops::Div<i32> for TimeVal {
147+
type Output = TimeVal;
148+
149+
fn div(self, rhs: i32) -> TimeVal {
150+
let usec = self.num_microseconds() / rhs as i64;
151+
TimeVal::microseconds(usec)
152+
}
153+
}
154+
155+
impl fmt::Display for TimeVal {
156+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
157+
let (abs, sign) = if self.tv_sec < 0 {
158+
(-*self, "-")
159+
} else {
160+
(*self, "")
161+
};
162+
163+
let sec = abs.tv_sec;
164+
165+
try!(write!(f, "{}", sign));
166+
167+
if abs.tv_usec == 0 {
168+
if abs.tv_sec == 1 {
169+
try!(write!(f, "{} second", sec));
170+
} else {
171+
try!(write!(f, "{} seconds", sec));
172+
}
173+
} else if abs.tv_usec % 1000 == 0 {
174+
try!(write!(f, "{}.{:03} seconds", sec, abs.tv_usec / 1000));
175+
} else {
176+
try!(write!(f, "{}.{:06} seconds", sec, abs.tv_usec));
177+
}
178+
179+
Ok(())
180+
}
181+
}
182+
183+
#[inline]
184+
fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) {
185+
(div_floor_64(this, other), mod_floor_64(this, other))
186+
}
187+
188+
#[inline]
189+
fn div_floor_64(this: i64, other: i64) -> i64 {
190+
match div_rem_64(this, other) {
191+
(d, r) if (r > 0 && other < 0)
192+
|| (r < 0 && other > 0) => d - 1,
193+
(d, _) => d,
194+
}
195+
}
196+
197+
#[inline]
198+
fn mod_floor_64(this: i64, other: i64) -> i64 {
199+
match this % other {
200+
r if (r > 0 && other < 0)
201+
|| (r < 0 && other > 0) => r + other,
202+
r => r,
203+
}
204+
}
205+
206+
#[inline]
207+
fn div_rem_64(this: i64, other: i64) -> (i64, i64) {
208+
(this / other, this % other)
209+
}
210+
211+
#[cfg(test)]
212+
mod test {
213+
use super::TimeVal;
214+
215+
#[test]
216+
pub fn test_time_val() {
217+
assert!(TimeVal::seconds(1) != TimeVal::zero());
218+
assert_eq!(TimeVal::seconds(1) + TimeVal::seconds(2), TimeVal::seconds(3));
219+
assert_eq!(TimeVal::minutes(3) + TimeVal::seconds(2),
220+
TimeVal::seconds(182));
221+
}
222+
223+
#[test]
224+
pub fn test_time_val_neg() {
225+
let a = TimeVal::seconds(1) + TimeVal::microseconds(123);
226+
let b = TimeVal::seconds(-1) + TimeVal::microseconds(-123);
227+
228+
assert_eq!(a, -b);
229+
}
230+
231+
#[test]
232+
pub fn test_time_val_fmt() {
233+
assert_eq!(TimeVal::zero().to_string(), "0 seconds");
234+
assert_eq!(TimeVal::seconds(42).to_string(), "42 seconds");
235+
assert_eq!(TimeVal::milliseconds(42).to_string(), "0.042 seconds");
236+
assert_eq!(TimeVal::microseconds(42).to_string(), "0.000042 seconds");
237+
assert_eq!(TimeVal::seconds(-86401).to_string(), "-86401 seconds");
238+
}
239+
}

0 commit comments

Comments
 (0)