1#[cfg_attr(any(target_env = "musl", target_env = "ohos"), allow(deprecated))] 2// https://github.com/rust-lang/libc/issues/1848 3pub use libc::{suseconds_t, time_t}; 4use libc::{timespec, timeval}; 5use std::convert::From; 6use std::time::Duration; 7use std::{cmp, fmt, ops}; 8 9const fn zero_init_timespec() -> timespec { 10 // `std::mem::MaybeUninit::zeroed()` is not yet a const fn 11 // (https://github.com/rust-lang/rust/issues/91850) so we will instead initialize an array of 12 // the appropriate size to zero and then transmute it to a timespec value. 13 unsafe { std::mem::transmute([0u8; std::mem::size_of::<timespec>()]) } 14} 15 16#[cfg(any( 17 all(feature = "time", any(target_os = "android", target_os = "linux")), 18 all( 19 any( 20 target_os = "freebsd", 21 target_os = "illumos", 22 target_os = "linux", 23 target_os = "netbsd" 24 ), 25 feature = "time", 26 feature = "signal" 27 ) 28))] 29pub(crate) mod timer { 30 use crate::sys::time::{zero_init_timespec, TimeSpec}; 31 use bitflags::bitflags; 32 33 #[derive(Debug, Clone, Copy)] 34 pub(crate) struct TimerSpec(libc::itimerspec); 35 36 impl TimerSpec { 37 pub const fn none() -> Self { 38 Self(libc::itimerspec { 39 it_interval: zero_init_timespec(), 40 it_value: zero_init_timespec(), 41 }) 42 } 43 } 44 45 impl AsMut<libc::itimerspec> for TimerSpec { 46 fn as_mut(&mut self) -> &mut libc::itimerspec { 47 &mut self.0 48 } 49 } 50 51 impl AsRef<libc::itimerspec> for TimerSpec { 52 fn as_ref(&self) -> &libc::itimerspec { 53 &self.0 54 } 55 } 56 57 impl From<Expiration> for TimerSpec { 58 fn from(expiration: Expiration) -> TimerSpec { 59 match expiration { 60 Expiration::OneShot(t) => TimerSpec(libc::itimerspec { 61 it_interval: zero_init_timespec(), 62 it_value: *t.as_ref(), 63 }), 64 Expiration::IntervalDelayed(start, interval) => { 65 TimerSpec(libc::itimerspec { 66 it_interval: *interval.as_ref(), 67 it_value: *start.as_ref(), 68 }) 69 } 70 Expiration::Interval(t) => TimerSpec(libc::itimerspec { 71 it_interval: *t.as_ref(), 72 it_value: *t.as_ref(), 73 }), 74 } 75 } 76 } 77 78 /// An enumeration allowing the definition of the expiration time of an alarm, 79 /// recurring or not. 80 #[derive(Debug, Clone, Copy, Eq, PartialEq)] 81 pub enum Expiration { 82 /// Alarm will trigger once after the time given in `TimeSpec` 83 OneShot(TimeSpec), 84 /// Alarm will trigger after a specified delay and then every interval of 85 /// time. 86 IntervalDelayed(TimeSpec, TimeSpec), 87 /// Alarm will trigger every specified interval of time. 88 Interval(TimeSpec), 89 } 90 91 #[cfg(any(target_os = "android", target_os = "linux"))] 92 bitflags! { 93 /// Flags that are used for arming the timer. 94 pub struct TimerSetTimeFlags: libc::c_int { 95 const TFD_TIMER_ABSTIME = libc::TFD_TIMER_ABSTIME; 96 } 97 } 98 #[cfg(any( 99 target_os = "freebsd", 100 target_os = "netbsd", 101 target_os = "dragonfly", 102 target_os = "illumos" 103 ))] 104 bitflags! { 105 /// Flags that are used for arming the timer. 106 pub struct TimerSetTimeFlags: libc::c_int { 107 const TFD_TIMER_ABSTIME = libc::TIMER_ABSTIME; 108 } 109 } 110 111 impl From<TimerSpec> for Expiration { 112 fn from(timerspec: TimerSpec) -> Expiration { 113 match timerspec { 114 TimerSpec(libc::itimerspec { 115 it_interval: 116 libc::timespec { 117 tv_sec: 0, 118 tv_nsec: 0, 119 .. 120 }, 121 it_value: ts, 122 }) => Expiration::OneShot(ts.into()), 123 TimerSpec(libc::itimerspec { 124 it_interval: int_ts, 125 it_value: val_ts, 126 }) => { 127 if (int_ts.tv_sec == val_ts.tv_sec) 128 && (int_ts.tv_nsec == val_ts.tv_nsec) 129 { 130 Expiration::Interval(int_ts.into()) 131 } else { 132 Expiration::IntervalDelayed( 133 val_ts.into(), 134 int_ts.into(), 135 ) 136 } 137 } 138 } 139 } 140 } 141} 142 143pub trait TimeValLike: Sized { 144 #[inline] 145 fn zero() -> Self { 146 Self::seconds(0) 147 } 148 149 #[inline] 150 fn hours(hours: i64) -> Self { 151 let secs = hours 152 .checked_mul(SECS_PER_HOUR) 153 .expect("TimeValLike::hours ouf of bounds"); 154 Self::seconds(secs) 155 } 156 157 #[inline] 158 fn minutes(minutes: i64) -> Self { 159 let secs = minutes 160 .checked_mul(SECS_PER_MINUTE) 161 .expect("TimeValLike::minutes out of bounds"); 162 Self::seconds(secs) 163 } 164 165 fn seconds(seconds: i64) -> Self; 166 fn milliseconds(milliseconds: i64) -> Self; 167 fn microseconds(microseconds: i64) -> Self; 168 fn nanoseconds(nanoseconds: i64) -> Self; 169 170 #[inline] 171 fn num_hours(&self) -> i64 { 172 self.num_seconds() / 3600 173 } 174 175 #[inline] 176 fn num_minutes(&self) -> i64 { 177 self.num_seconds() / 60 178 } 179 180 fn num_seconds(&self) -> i64; 181 fn num_milliseconds(&self) -> i64; 182 fn num_microseconds(&self) -> i64; 183 fn num_nanoseconds(&self) -> i64; 184} 185 186#[repr(C)] 187#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 188pub struct TimeSpec(timespec); 189 190const NANOS_PER_SEC: i64 = 1_000_000_000; 191const SECS_PER_MINUTE: i64 = 60; 192const SECS_PER_HOUR: i64 = 3600; 193 194#[cfg(target_pointer_width = "64")] 195const TS_MAX_SECONDS: i64 = (i64::MAX / NANOS_PER_SEC) - 1; 196 197#[cfg(target_pointer_width = "32")] 198const TS_MAX_SECONDS: i64 = isize::MAX as i64; 199 200const TS_MIN_SECONDS: i64 = -TS_MAX_SECONDS; 201 202// x32 compatibility 203// See https://sourceware.org/bugzilla/show_bug.cgi?id=16437 204#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] 205type timespec_tv_nsec_t = i64; 206#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] 207type timespec_tv_nsec_t = libc::c_long; 208 209impl From<timespec> for TimeSpec { 210 fn from(ts: timespec) -> Self { 211 Self(ts) 212 } 213} 214 215impl From<Duration> for TimeSpec { 216 fn from(duration: Duration) -> Self { 217 Self::from_duration(duration) 218 } 219} 220 221impl From<TimeSpec> for Duration { 222 fn from(timespec: TimeSpec) -> Self { 223 Duration::new(timespec.0.tv_sec as u64, timespec.0.tv_nsec as u32) 224 } 225} 226 227impl AsRef<timespec> for TimeSpec { 228 fn as_ref(&self) -> ×pec { 229 &self.0 230 } 231} 232 233impl AsMut<timespec> for TimeSpec { 234 fn as_mut(&mut self) -> &mut timespec { 235 &mut self.0 236 } 237} 238 239impl Ord for TimeSpec { 240 // The implementation of cmp is simplified by assuming that the struct is 241 // normalized. That is, tv_nsec must always be within [0, 1_000_000_000) 242 fn cmp(&self, other: &TimeSpec) -> cmp::Ordering { 243 if self.tv_sec() == other.tv_sec() { 244 self.tv_nsec().cmp(&other.tv_nsec()) 245 } else { 246 self.tv_sec().cmp(&other.tv_sec()) 247 } 248 } 249} 250 251impl PartialOrd for TimeSpec { 252 fn partial_cmp(&self, other: &TimeSpec) -> Option<cmp::Ordering> { 253 Some(self.cmp(other)) 254 } 255} 256 257impl TimeValLike for TimeSpec { 258 #[inline] 259 #[cfg_attr(any(target_env = "musl", target_env = "ohos"), allow(deprecated))] 260 // https://github.com/rust-lang/libc/issues/1848 261 fn seconds(seconds: i64) -> TimeSpec { 262 assert!( 263 (TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&seconds), 264 "TimeSpec out of bounds; seconds={}", 265 seconds 266 ); 267 let mut ts = zero_init_timespec(); 268 ts.tv_sec = seconds as time_t; 269 TimeSpec(ts) 270 } 271 272 #[inline] 273 fn milliseconds(milliseconds: i64) -> TimeSpec { 274 let nanoseconds = milliseconds 275 .checked_mul(1_000_000) 276 .expect("TimeSpec::milliseconds out of bounds"); 277 278 TimeSpec::nanoseconds(nanoseconds) 279 } 280 281 /// Makes a new `TimeSpec` with given number of microseconds. 282 #[inline] 283 fn microseconds(microseconds: i64) -> TimeSpec { 284 let nanoseconds = microseconds 285 .checked_mul(1_000) 286 .expect("TimeSpec::milliseconds out of bounds"); 287 288 TimeSpec::nanoseconds(nanoseconds) 289 } 290 291 /// Makes a new `TimeSpec` with given number of nanoseconds. 292 #[inline] 293 #[cfg_attr(any(target_env = "musl", target_env = "ohos"), allow(deprecated))] 294 // https://github.com/rust-lang/libc/issues/1848 295 fn nanoseconds(nanoseconds: i64) -> TimeSpec { 296 let (secs, nanos) = div_mod_floor_64(nanoseconds, NANOS_PER_SEC); 297 assert!( 298 (TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&secs), 299 "TimeSpec out of bounds" 300 ); 301 let mut ts = zero_init_timespec(); 302 ts.tv_sec = secs as time_t; 303 ts.tv_nsec = nanos as timespec_tv_nsec_t; 304 TimeSpec(ts) 305 } 306 307 // The cast is not unnecessary on all platforms. 308 #[allow(clippy::unnecessary_cast)] 309 fn num_seconds(&self) -> i64 { 310 if self.tv_sec() < 0 && self.tv_nsec() > 0 { 311 (self.tv_sec() + 1) as i64 312 } else { 313 self.tv_sec() as i64 314 } 315 } 316 317 fn num_milliseconds(&self) -> i64 { 318 self.num_nanoseconds() / 1_000_000 319 } 320 321 fn num_microseconds(&self) -> i64 { 322 self.num_nanoseconds() / 1_000 323 } 324 325 // The cast is not unnecessary on all platforms. 326 #[allow(clippy::unnecessary_cast)] 327 fn num_nanoseconds(&self) -> i64 { 328 let secs = self.num_seconds() * 1_000_000_000; 329 let nsec = self.nanos_mod_sec(); 330 secs + nsec as i64 331 } 332} 333 334impl TimeSpec { 335 /// Construct a new `TimeSpec` from its components 336 #[cfg_attr(any(target_env = "musl", target_env = "ohos"), allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 337 pub const fn new(seconds: time_t, nanoseconds: timespec_tv_nsec_t) -> Self { 338 let mut ts = zero_init_timespec(); 339 ts.tv_sec = seconds; 340 ts.tv_nsec = nanoseconds; 341 Self(ts) 342 } 343 344 fn nanos_mod_sec(&self) -> timespec_tv_nsec_t { 345 if self.tv_sec() < 0 && self.tv_nsec() > 0 { 346 self.tv_nsec() - NANOS_PER_SEC as timespec_tv_nsec_t 347 } else { 348 self.tv_nsec() 349 } 350 } 351 352 #[cfg_attr(any(target_env = "musl", target_env = "ohos"), allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 353 pub const fn tv_sec(&self) -> time_t { 354 self.0.tv_sec 355 } 356 357 pub const fn tv_nsec(&self) -> timespec_tv_nsec_t { 358 self.0.tv_nsec 359 } 360 361 #[cfg_attr(any(target_env = "musl", target_env = "ohos"), allow(deprecated))] 362 // https://github.com/rust-lang/libc/issues/1848 363 pub const fn from_duration(duration: Duration) -> Self { 364 let mut ts = zero_init_timespec(); 365 ts.tv_sec = duration.as_secs() as time_t; 366 ts.tv_nsec = duration.subsec_nanos() as timespec_tv_nsec_t; 367 TimeSpec(ts) 368 } 369 370 pub const fn from_timespec(timespec: timespec) -> Self { 371 Self(timespec) 372 } 373} 374 375impl ops::Neg for TimeSpec { 376 type Output = TimeSpec; 377 378 fn neg(self) -> TimeSpec { 379 TimeSpec::nanoseconds(-self.num_nanoseconds()) 380 } 381} 382 383impl ops::Add for TimeSpec { 384 type Output = TimeSpec; 385 386 fn add(self, rhs: TimeSpec) -> TimeSpec { 387 TimeSpec::nanoseconds(self.num_nanoseconds() + rhs.num_nanoseconds()) 388 } 389} 390 391impl ops::Sub for TimeSpec { 392 type Output = TimeSpec; 393 394 fn sub(self, rhs: TimeSpec) -> TimeSpec { 395 TimeSpec::nanoseconds(self.num_nanoseconds() - rhs.num_nanoseconds()) 396 } 397} 398 399impl ops::Mul<i32> for TimeSpec { 400 type Output = TimeSpec; 401 402 fn mul(self, rhs: i32) -> TimeSpec { 403 let usec = self 404 .num_nanoseconds() 405 .checked_mul(i64::from(rhs)) 406 .expect("TimeSpec multiply out of bounds"); 407 408 TimeSpec::nanoseconds(usec) 409 } 410} 411 412impl ops::Div<i32> for TimeSpec { 413 type Output = TimeSpec; 414 415 fn div(self, rhs: i32) -> TimeSpec { 416 let usec = self.num_nanoseconds() / i64::from(rhs); 417 TimeSpec::nanoseconds(usec) 418 } 419} 420 421impl fmt::Display for TimeSpec { 422 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 423 let (abs, sign) = if self.tv_sec() < 0 { 424 (-*self, "-") 425 } else { 426 (*self, "") 427 }; 428 429 let sec = abs.tv_sec(); 430 431 write!(f, "{}", sign)?; 432 433 if abs.tv_nsec() == 0 { 434 if abs.tv_sec() == 1 { 435 write!(f, "{} second", sec)?; 436 } else { 437 write!(f, "{} seconds", sec)?; 438 } 439 } else if abs.tv_nsec() % 1_000_000 == 0 { 440 write!(f, "{}.{:03} seconds", sec, abs.tv_nsec() / 1_000_000)?; 441 } else if abs.tv_nsec() % 1_000 == 0 { 442 write!(f, "{}.{:06} seconds", sec, abs.tv_nsec() / 1_000)?; 443 } else { 444 write!(f, "{}.{:09} seconds", sec, abs.tv_nsec())?; 445 } 446 447 Ok(()) 448 } 449} 450 451#[repr(transparent)] 452#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 453pub struct TimeVal(timeval); 454 455const MICROS_PER_SEC: i64 = 1_000_000; 456 457#[cfg(target_pointer_width = "64")] 458const TV_MAX_SECONDS: i64 = (i64::MAX / MICROS_PER_SEC) - 1; 459 460#[cfg(target_pointer_width = "32")] 461const TV_MAX_SECONDS: i64 = isize::MAX as i64; 462 463const TV_MIN_SECONDS: i64 = -TV_MAX_SECONDS; 464 465impl AsRef<timeval> for TimeVal { 466 fn as_ref(&self) -> &timeval { 467 &self.0 468 } 469} 470 471impl AsMut<timeval> for TimeVal { 472 fn as_mut(&mut self) -> &mut timeval { 473 &mut self.0 474 } 475} 476 477impl Ord for TimeVal { 478 // The implementation of cmp is simplified by assuming that the struct is 479 // normalized. That is, tv_usec must always be within [0, 1_000_000) 480 fn cmp(&self, other: &TimeVal) -> cmp::Ordering { 481 if self.tv_sec() == other.tv_sec() { 482 self.tv_usec().cmp(&other.tv_usec()) 483 } else { 484 self.tv_sec().cmp(&other.tv_sec()) 485 } 486 } 487} 488 489impl PartialOrd for TimeVal { 490 fn partial_cmp(&self, other: &TimeVal) -> Option<cmp::Ordering> { 491 Some(self.cmp(other)) 492 } 493} 494 495impl TimeValLike for TimeVal { 496 #[inline] 497 fn seconds(seconds: i64) -> TimeVal { 498 assert!( 499 (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&seconds), 500 "TimeVal out of bounds; seconds={}", 501 seconds 502 ); 503 #[cfg_attr(any(target_env = "musl", target_env = "ohos"), allow(deprecated))] 504 // https://github.com/rust-lang/libc/issues/1848 505 TimeVal(timeval { 506 tv_sec: seconds as time_t, 507 tv_usec: 0, 508 }) 509 } 510 511 #[inline] 512 fn milliseconds(milliseconds: i64) -> TimeVal { 513 let microseconds = milliseconds 514 .checked_mul(1_000) 515 .expect("TimeVal::milliseconds out of bounds"); 516 517 TimeVal::microseconds(microseconds) 518 } 519 520 /// Makes a new `TimeVal` with given number of microseconds. 521 #[inline] 522 fn microseconds(microseconds: i64) -> TimeVal { 523 let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC); 524 assert!( 525 (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&secs), 526 "TimeVal out of bounds" 527 ); 528 #[cfg_attr(any(target_env = "musl", target_env = "ohos"), allow(deprecated))] 529 // https://github.com/rust-lang/libc/issues/1848 530 TimeVal(timeval { 531 tv_sec: secs as time_t, 532 tv_usec: micros as suseconds_t, 533 }) 534 } 535 536 /// Makes a new `TimeVal` with given number of nanoseconds. Some precision 537 /// will be lost 538 #[inline] 539 fn nanoseconds(nanoseconds: i64) -> TimeVal { 540 let microseconds = nanoseconds / 1000; 541 let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC); 542 assert!( 543 (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&secs), 544 "TimeVal out of bounds" 545 ); 546 #[cfg_attr(any(target_env = "musl", target_env = "ohos"), allow(deprecated))] 547 // https://github.com/rust-lang/libc/issues/1848 548 TimeVal(timeval { 549 tv_sec: secs as time_t, 550 tv_usec: micros as suseconds_t, 551 }) 552 } 553 554 // The cast is not unnecessary on all platforms. 555 #[allow(clippy::unnecessary_cast)] 556 fn num_seconds(&self) -> i64 { 557 if self.tv_sec() < 0 && self.tv_usec() > 0 { 558 (self.tv_sec() + 1) as i64 559 } else { 560 self.tv_sec() as i64 561 } 562 } 563 564 fn num_milliseconds(&self) -> i64 { 565 self.num_microseconds() / 1_000 566 } 567 568 // The cast is not unnecessary on all platforms. 569 #[allow(clippy::unnecessary_cast)] 570 fn num_microseconds(&self) -> i64 { 571 let secs = self.num_seconds() * 1_000_000; 572 let usec = self.micros_mod_sec(); 573 secs + usec as i64 574 } 575 576 fn num_nanoseconds(&self) -> i64 { 577 self.num_microseconds() * 1_000 578 } 579} 580 581impl TimeVal { 582 /// Construct a new `TimeVal` from its components 583 #[cfg_attr(any(target_env = "musl", target_env = "ohos"), allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 584 pub const fn new(seconds: time_t, microseconds: suseconds_t) -> Self { 585 Self(timeval { 586 tv_sec: seconds, 587 tv_usec: microseconds, 588 }) 589 } 590 591 fn micros_mod_sec(&self) -> suseconds_t { 592 if self.tv_sec() < 0 && self.tv_usec() > 0 { 593 self.tv_usec() - MICROS_PER_SEC as suseconds_t 594 } else { 595 self.tv_usec() 596 } 597 } 598 599 #[cfg_attr(any(target_env = "musl", target_env = "ohos"), allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 600 pub const fn tv_sec(&self) -> time_t { 601 self.0.tv_sec 602 } 603 604 pub const fn tv_usec(&self) -> suseconds_t { 605 self.0.tv_usec 606 } 607} 608 609impl ops::Neg for TimeVal { 610 type Output = TimeVal; 611 612 fn neg(self) -> TimeVal { 613 TimeVal::microseconds(-self.num_microseconds()) 614 } 615} 616 617impl ops::Add for TimeVal { 618 type Output = TimeVal; 619 620 fn add(self, rhs: TimeVal) -> TimeVal { 621 TimeVal::microseconds(self.num_microseconds() + rhs.num_microseconds()) 622 } 623} 624 625impl ops::Sub for TimeVal { 626 type Output = TimeVal; 627 628 fn sub(self, rhs: TimeVal) -> TimeVal { 629 TimeVal::microseconds(self.num_microseconds() - rhs.num_microseconds()) 630 } 631} 632 633impl ops::Mul<i32> for TimeVal { 634 type Output = TimeVal; 635 636 fn mul(self, rhs: i32) -> TimeVal { 637 let usec = self 638 .num_microseconds() 639 .checked_mul(i64::from(rhs)) 640 .expect("TimeVal multiply out of bounds"); 641 642 TimeVal::microseconds(usec) 643 } 644} 645 646impl ops::Div<i32> for TimeVal { 647 type Output = TimeVal; 648 649 fn div(self, rhs: i32) -> TimeVal { 650 let usec = self.num_microseconds() / i64::from(rhs); 651 TimeVal::microseconds(usec) 652 } 653} 654 655impl fmt::Display for TimeVal { 656 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 657 let (abs, sign) = if self.tv_sec() < 0 { 658 (-*self, "-") 659 } else { 660 (*self, "") 661 }; 662 663 let sec = abs.tv_sec(); 664 665 write!(f, "{}", sign)?; 666 667 if abs.tv_usec() == 0 { 668 if abs.tv_sec() == 1 { 669 write!(f, "{} second", sec)?; 670 } else { 671 write!(f, "{} seconds", sec)?; 672 } 673 } else if abs.tv_usec() % 1000 == 0 { 674 write!(f, "{}.{:03} seconds", sec, abs.tv_usec() / 1000)?; 675 } else { 676 write!(f, "{}.{:06} seconds", sec, abs.tv_usec())?; 677 } 678 679 Ok(()) 680 } 681} 682 683impl From<timeval> for TimeVal { 684 fn from(tv: timeval) -> Self { 685 TimeVal(tv) 686 } 687} 688 689#[inline] 690fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) { 691 (div_floor_64(this, other), mod_floor_64(this, other)) 692} 693 694#[inline] 695fn div_floor_64(this: i64, other: i64) -> i64 { 696 match div_rem_64(this, other) { 697 (d, r) if (r > 0 && other < 0) || (r < 0 && other > 0) => d - 1, 698 (d, _) => d, 699 } 700} 701 702#[inline] 703fn mod_floor_64(this: i64, other: i64) -> i64 { 704 match this % other { 705 r if (r > 0 && other < 0) || (r < 0 && other > 0) => r + other, 706 r => r, 707 } 708} 709 710#[inline] 711fn div_rem_64(this: i64, other: i64) -> (i64, i64) { 712 (this / other, this % other) 713} 714 715#[cfg(test)] 716mod test { 717 use super::{TimeSpec, TimeVal, TimeValLike}; 718 use std::time::Duration; 719 720 #[test] 721 pub fn test_timespec() { 722 assert_ne!(TimeSpec::seconds(1), TimeSpec::zero()); 723 assert_eq!( 724 TimeSpec::seconds(1) + TimeSpec::seconds(2), 725 TimeSpec::seconds(3) 726 ); 727 assert_eq!( 728 TimeSpec::minutes(3) + TimeSpec::seconds(2), 729 TimeSpec::seconds(182) 730 ); 731 } 732 733 #[test] 734 pub fn test_timespec_from() { 735 let duration = Duration::new(123, 123_456_789); 736 let timespec = TimeSpec::nanoseconds(123_123_456_789); 737 738 assert_eq!(TimeSpec::from(duration), timespec); 739 assert_eq!(Duration::from(timespec), duration); 740 } 741 742 #[test] 743 pub fn test_timespec_neg() { 744 let a = TimeSpec::seconds(1) + TimeSpec::nanoseconds(123); 745 let b = TimeSpec::seconds(-1) + TimeSpec::nanoseconds(-123); 746 747 assert_eq!(a, -b); 748 } 749 750 #[test] 751 pub fn test_timespec_ord() { 752 assert_eq!(TimeSpec::seconds(1), TimeSpec::nanoseconds(1_000_000_000)); 753 assert!(TimeSpec::seconds(1) < TimeSpec::nanoseconds(1_000_000_001)); 754 assert!(TimeSpec::seconds(1) > TimeSpec::nanoseconds(999_999_999)); 755 assert!(TimeSpec::seconds(-1) < TimeSpec::nanoseconds(-999_999_999)); 756 assert!(TimeSpec::seconds(-1) > TimeSpec::nanoseconds(-1_000_000_001)); 757 } 758 759 #[test] 760 pub fn test_timespec_fmt() { 761 assert_eq!(TimeSpec::zero().to_string(), "0 seconds"); 762 assert_eq!(TimeSpec::seconds(42).to_string(), "42 seconds"); 763 assert_eq!(TimeSpec::milliseconds(42).to_string(), "0.042 seconds"); 764 assert_eq!(TimeSpec::microseconds(42).to_string(), "0.000042 seconds"); 765 assert_eq!( 766 TimeSpec::nanoseconds(42).to_string(), 767 "0.000000042 seconds" 768 ); 769 assert_eq!(TimeSpec::seconds(-86401).to_string(), "-86401 seconds"); 770 } 771 772 #[test] 773 pub fn test_timeval() { 774 assert_ne!(TimeVal::seconds(1), TimeVal::zero()); 775 assert_eq!( 776 TimeVal::seconds(1) + TimeVal::seconds(2), 777 TimeVal::seconds(3) 778 ); 779 assert_eq!( 780 TimeVal::minutes(3) + TimeVal::seconds(2), 781 TimeVal::seconds(182) 782 ); 783 } 784 785 #[test] 786 pub fn test_timeval_ord() { 787 assert_eq!(TimeVal::seconds(1), TimeVal::microseconds(1_000_000)); 788 assert!(TimeVal::seconds(1) < TimeVal::microseconds(1_000_001)); 789 assert!(TimeVal::seconds(1) > TimeVal::microseconds(999_999)); 790 assert!(TimeVal::seconds(-1) < TimeVal::microseconds(-999_999)); 791 assert!(TimeVal::seconds(-1) > TimeVal::microseconds(-1_000_001)); 792 } 793 794 #[test] 795 pub fn test_timeval_neg() { 796 let a = TimeVal::seconds(1) + TimeVal::microseconds(123); 797 let b = TimeVal::seconds(-1) + TimeVal::microseconds(-123); 798 799 assert_eq!(a, -b); 800 } 801 802 #[test] 803 pub fn test_timeval_fmt() { 804 assert_eq!(TimeVal::zero().to_string(), "0 seconds"); 805 assert_eq!(TimeVal::seconds(42).to_string(), "42 seconds"); 806 assert_eq!(TimeVal::milliseconds(42).to_string(), "0.042 seconds"); 807 assert_eq!(TimeVal::microseconds(42).to_string(), "0.000042 seconds"); 808 assert_eq!(TimeVal::nanoseconds(1402).to_string(), "0.000001 seconds"); 809 assert_eq!(TimeVal::seconds(-86401).to_string(), "-86401 seconds"); 810 } 811} 812