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 ;
@@ -183,6 +184,193 @@ impl PartialEq for TimeVal {
183
184
184
185
impl Eq for TimeVal { }
185
186
187
+ #[ derive( Clone , Copy ) ]
188
+ pub struct TimeSpec {
189
+ spec : timespec ,
190
+ }
191
+
192
+ impl AsRef < timespec > for TimeSpec {
193
+ fn as_ref ( & self ) -> & timespec {
194
+ & self . spec
195
+ }
196
+ }
197
+
198
+ impl TimeSpec {
199
+ #[ inline]
200
+ pub fn zero ( ) -> TimeSpec {
201
+ TimeSpec :: nanoseconds ( 0 )
202
+ }
203
+
204
+ #[ inline]
205
+ pub fn hours ( hours : i64 ) -> TimeSpec {
206
+ let secs = hours. checked_mul ( SECS_PER_HOUR )
207
+ . expect ( "TimeSpec::hours ouf of bounds" ) ;
208
+
209
+ TimeSpec :: seconds ( secs)
210
+ }
211
+
212
+ #[ inline]
213
+ pub fn minutes ( minutes : i64 ) -> TimeSpec {
214
+ let secs = minutes. checked_mul ( SECS_PER_MINUTE )
215
+ . expect ( "TimeSpec::minutes out of bounds" ) ;
216
+
217
+ TimeSpec :: seconds ( secs)
218
+ }
219
+
220
+ #[ inline]
221
+ pub fn seconds ( seconds : i64 ) -> TimeSpec {
222
+ assert ! ( seconds >= time_t:: min_value( ) && seconds <= time_t:: max_value( ) , "TimeSpec out of bounds; seconds={}" , seconds) ;
223
+ TimeSpec { spec : timespec { tv_sec : seconds as time_t , tv_nsec : 0 } }
224
+ }
225
+
226
+ #[ inline]
227
+ pub fn milliseconds ( milliseconds : i64 ) -> TimeSpec {
228
+ let nanoseconds = milliseconds. checked_mul ( 1_000_000 )
229
+ . expect ( "TimeSpec::milliseconds out of bounds" ) ;
230
+
231
+ TimeSpec :: nanoseconds ( nanoseconds)
232
+ }
233
+
234
+ #[ inline]
235
+ pub fn microseconds ( microseconds : i64 ) -> TimeSpec {
236
+ let nanoseconds = microseconds. checked_mul ( 1_000 )
237
+ . expect ( "TimeSpec::microseconds out of bounds" ) ;
238
+
239
+ TimeSpec :: nanoseconds ( nanoseconds)
240
+ }
241
+
242
+
243
+ /// Makes a new `TimeSpec` with given number of nanoseconds.
244
+ #[ inline]
245
+ pub fn nanoseconds ( nanoseconds : i64 ) -> TimeSpec {
246
+ let ( secs, nanos) = div_mod_floor_64 ( nanoseconds, NANOS_PER_SEC ) ;
247
+ assert ! ( secs >= time_t:: min_value( ) && secs <= time_t:: max_value( ) , "TimeSpec out of bounds; seconds={}" , secs) ;
248
+ TimeSpec { spec : timespec { tv_sec : secs as time_t , tv_nsec : nanos as c_long } }
249
+ }
250
+
251
+ pub fn num_hours ( & self ) -> i64 {
252
+ self . num_seconds ( ) / 3600
253
+ }
254
+
255
+ pub fn num_minutes ( & self ) -> i64 {
256
+ self . num_seconds ( ) / 60
257
+ }
258
+
259
+ pub fn num_seconds ( & self ) -> i64 {
260
+ if self . spec . tv_sec < 0 && self . spec . tv_nsec > 0 {
261
+ ( self . spec . tv_sec + 1 ) as i64
262
+ } else {
263
+ self . spec . tv_sec as i64
264
+ }
265
+ }
266
+
267
+ pub fn num_milliseconds ( & self ) -> i64 {
268
+ self . num_nanoseconds ( ) / 1_000_000
269
+ }
270
+
271
+ pub fn num_microseconds ( & self ) -> i64 {
272
+ self . num_nanoseconds ( ) / 1_000
273
+ }
274
+
275
+ pub fn num_nanoseconds ( & self ) -> i64 {
276
+ let secs = self . num_seconds ( ) * NANOS_PER_SEC ;
277
+ let nsec = self . nanos_mod_sec ( ) ;
278
+ secs + nsec as i64
279
+ }
280
+
281
+ fn nanos_mod_sec ( & self ) -> suseconds_t {
282
+ if self . spec . tv_sec < 0 && self . spec . tv_nsec > 0 {
283
+ self . spec . tv_nsec - NANOS_PER_SEC as c_long
284
+ } else {
285
+ self . spec . tv_nsec
286
+ }
287
+ }
288
+ }
289
+
290
+ impl ops:: Neg for TimeSpec {
291
+ type Output = TimeSpec ;
292
+
293
+ fn neg ( self ) -> TimeSpec {
294
+ TimeSpec :: nanoseconds ( -self . num_nanoseconds ( ) )
295
+ }
296
+ }
297
+
298
+ impl ops:: Add for TimeSpec {
299
+ type Output = TimeSpec ;
300
+
301
+ fn add ( self , rhs : TimeSpec ) -> TimeSpec {
302
+ TimeSpec :: nanoseconds (
303
+ self . num_nanoseconds ( ) + rhs. num_nanoseconds ( ) )
304
+ }
305
+ }
306
+
307
+ impl ops:: Sub for TimeSpec {
308
+ type Output = TimeSpec ;
309
+
310
+ fn sub ( self , rhs : TimeSpec ) -> TimeSpec {
311
+ TimeSpec :: nanoseconds (
312
+ self . num_nanoseconds ( ) - rhs. num_nanoseconds ( ) )
313
+ }
314
+ }
315
+
316
+ impl ops:: Mul < i32 > for TimeSpec {
317
+ type Output = TimeSpec ;
318
+
319
+ fn mul ( self , rhs : i32 ) -> TimeSpec {
320
+ let nsec = self . num_nanoseconds ( ) . checked_mul ( rhs as i64 )
321
+ . expect ( "TimeSpec multiply out of bounds" ) ;
322
+
323
+ TimeSpec :: nanoseconds ( nsec)
324
+ }
325
+ }
326
+
327
+ impl ops:: Div < i32 > for TimeSpec {
328
+ type Output = TimeSpec ;
329
+
330
+ fn div ( self , rhs : i32 ) -> TimeSpec {
331
+ let nsec = self . num_nanoseconds ( ) / rhs as i64 ;
332
+ TimeSpec :: nanoseconds ( nsec)
333
+ }
334
+ }
335
+
336
+ impl fmt:: Display for TimeSpec {
337
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
338
+ let ( abs, sign) = if self . spec . tv_sec < 0 {
339
+ ( -* self , "-" )
340
+ } else {
341
+ ( * self , "" )
342
+ } ;
343
+
344
+ let sec = abs. spec . tv_sec ;
345
+
346
+ try!( write ! ( f, "{}" , sign) ) ;
347
+
348
+ if abs. spec . tv_nsec == 0 {
349
+ if abs. spec . tv_sec == 1 {
350
+ try!( write ! ( f, "{} second" , sec) ) ;
351
+ } else {
352
+ try!( write ! ( f, "{} seconds" , sec) ) ;
353
+ }
354
+ } else if abs. spec . tv_nsec % 1_000_000 == 0 {
355
+ try!( write ! ( f, "{}.{:03} seconds" , sec, abs. spec. tv_nsec / 1_000_000 ) ) ;
356
+ } else if abs. spec . tv_nsec % 1_000 == 0 {
357
+ try!( write ! ( f, "{}.{:06} seconds" , sec, abs. spec. tv_nsec / 1_000 ) ) ;
358
+ } else {
359
+ try!( write ! ( f, "{}.{:09} seconds" , sec, abs. spec. tv_nsec) ) ;
360
+ }
361
+
362
+ Ok ( ( ) )
363
+ }
364
+ }
365
+
366
+ impl PartialEq for TimeSpec {
367
+ fn eq ( & self , rhs : & TimeSpec ) -> bool {
368
+ self . spec . tv_sec == rhs. spec . tv_sec && self . spec . tv_nsec == rhs. spec . tv_nsec
369
+ }
370
+ }
371
+
372
+ impl Eq for TimeSpec { }
373
+
186
374
#[ inline]
187
375
fn div_mod_floor_64 ( this : i64 , other : i64 ) -> ( i64 , i64 ) {
188
376
( div_floor_64 ( this, other) , mod_floor_64 ( this, other) )
@@ -213,7 +401,7 @@ fn div_rem_64(this: i64, other: i64) -> (i64, i64) {
213
401
214
402
#[ cfg( test) ]
215
403
mod test {
216
- use super :: TimeVal ;
404
+ use super :: { TimeVal , TimeSpec } ;
217
405
218
406
#[ test]
219
407
pub fn test_time_val ( ) {
@@ -238,4 +426,29 @@ mod test {
238
426
assert_eq ! ( TimeVal :: microseconds( 42 ) . to_string( ) , "0.000042 seconds" ) ;
239
427
assert_eq ! ( TimeVal :: seconds( -86401 ) . to_string( ) , "-86401 seconds" ) ;
240
428
}
429
+
430
+ #[ test]
431
+ pub fn test_time_spec ( ) {
432
+ assert ! ( TimeSpec :: seconds( 1 ) != TimeSpec :: zero( ) ) ;
433
+ assert ! ( TimeSpec :: seconds( 1 ) + TimeSpec :: seconds( 2 ) == TimeSpec :: seconds( 3 ) ) ;
434
+ assert ! ( TimeSpec :: minutes( 3 ) + TimeSpec :: seconds( 2 ) == TimeSpec :: seconds( 182 ) ) ;
435
+ }
436
+
437
+ #[ test]
438
+ pub fn test_time_spec_neg ( ) {
439
+ let a = TimeSpec :: seconds ( 1 ) + TimeSpec :: nanoseconds ( 123 ) ;
440
+ let b = TimeSpec :: seconds ( -1 ) + TimeSpec :: nanoseconds ( -123 ) ;
441
+
442
+ assert ! ( a == -b) ;
443
+ }
444
+
445
+ #[ test]
446
+ pub fn test_time_spec_fmt ( ) {
447
+ assert_eq ! ( TimeSpec :: zero( ) . to_string( ) , "0 seconds" ) ;
448
+ assert_eq ! ( TimeSpec :: seconds( 42 ) . to_string( ) , "42 seconds" ) ;
449
+ assert_eq ! ( TimeSpec :: milliseconds( 42 ) . to_string( ) , "0.042 seconds" ) ;
450
+ assert_eq ! ( TimeSpec :: microseconds( 42 ) . to_string( ) , "0.000042 seconds" ) ;
451
+ assert_eq ! ( TimeSpec :: nanoseconds( 42 ) . to_string( ) , "0.000000042 seconds" ) ;
452
+ assert_eq ! ( TimeSpec :: seconds( -86401 ) . to_string( ) , "-86401 seconds" ) ;
453
+ }
241
454
}
0 commit comments