1
1
use std:: { fmt, ops} ;
2
- use libc:: { time_t, suseconds_t, timeval} ;
2
+ use libc:: { time_t, c_long , suseconds_t, timeval, timespec } ;
3
3
4
+ const NANOS_PER_SEC : i64 = 1_000_000_000 ;
4
5
const MICROS_PER_SEC : i64 = 1_000_000 ;
5
6
const SECS_PER_MINUTE : i64 = 60 ;
6
7
const SECS_PER_HOUR : i64 = 3600 ;
@@ -181,6 +182,191 @@ impl PartialEq for TimeVal {
181
182
182
183
impl Eq for TimeVal { }
183
184
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
+
184
370
#[ inline]
185
371
fn div_mod_floor_64 ( this : i64 , other : i64 ) -> ( i64 , i64 ) {
186
372
( div_floor_64 ( this, other) , mod_floor_64 ( this, other) )
@@ -211,7 +397,7 @@ fn div_rem_64(this: i64, other: i64) -> (i64, i64) {
211
397
212
398
#[ cfg( test) ]
213
399
mod test {
214
- use super :: TimeVal ;
400
+ use super :: { TimeVal , TimeSpec } ;
215
401
216
402
#[ test]
217
403
pub fn test_time_val ( ) {
@@ -236,4 +422,29 @@ mod test {
236
422
assert_eq ! ( TimeVal :: microseconds( 42 ) . to_string( ) , "0.000042 seconds" ) ;
237
423
assert_eq ! ( TimeVal :: seconds( -86401 ) . to_string( ) , "-86401 seconds" ) ;
238
424
}
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
+ }
239
450
}
0 commit comments