use std::{borrow::Cow, cmp::Ordering, fmt, io::{self}, ops, os::fd::{AsFd, AsRawFd, BorrowedFd, RawFd}, sync::Arc, time::Duration};
use chrono::{DateTime, TimeZone};
use nix::libc::{self, ECANCELED, EWOULDBLOCK};
use bitflags::bitflags;
use crate::{common, timer_portable::portable_error::TimerPortResult};
#[cfg(target_os = "linux")]
pub use super::linux::timer_fd_linux::TimerFdInternal;
#[cfg(
all(
any(
target_os = "freebsd",
target_os = "dragonfly",
target_os = "netbsd",
target_os = "openbsd",
target_os = "macos",
),
feature = "bsd_use_timerfd"
)
)]
pub use super::bsd::timer_fd_bsd::TimerFdInternal;
#[cfg(
all(
any(
target_os = "freebsd",
target_os = "dragonfly",
target_os = "netbsd",
target_os = "openbsd",
target_os = "macos",
),
not(feature = "bsd_use_timerfd")
)
)]
pub use super::bsd::timer_kqueue_fd_bsd::TimerFdInternal;
#[allow(non_camel_case_types)]
#[repr(i32)]
#[derive(Debug)]
pub enum TimerType
{
CLOCK_REALTIME = libc::CLOCK_REALTIME,
CLOCK_MONOTONIC = libc::CLOCK_MONOTONIC,
#[cfg(target_os = "linux")]
CLOCK_BOOTTIME = libc::CLOCK_BOOTTIME,
#[cfg(target_os = "linux")]
CLOCK_REALTIME_ALARM = libc::CLOCK_REALTIME_ALARM,
#[cfg(target_os = "linux")]
CLOCK_BOOTTIME_ALARM = libc::CLOCK_BOOTTIME_ALARM,
}
impl From<TimerType> for libc::clockid_t
{
fn from(value: TimerType) -> Self
{
return value as libc::clockid_t;
}
}
bitflags! {
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub struct TimerFlags: i32
{
const TFD_NONBLOCK = libc::TFD_NONBLOCK;
const TFD_CLOEXEC = libc::TFD_CLOEXEC;
}
}
bitflags! {
#[derive(Default, Debug, Eq, PartialEq, Clone, Copy)]
pub struct TimerSetTimeFlags: i32
{
const TFD_TIMER_ABSTIME = libc::TFD_TIMER_ABSTIME;
const TFD_TIMER_CANCEL_ON_SET = libc::TFD_TIMER_CANCEL_ON_SET;
}
}
pub trait ModeTimeType: Eq + PartialEq + Ord + PartialOrd + fmt::Display + fmt::Debug + Clone + Copy
{
fn new(time_spec: timespec) -> Self where Self: Sized;
fn get_sec(&self) -> i64;
fn get_nsec(&self) -> i64;
fn is_value_valid(&self) -> bool;
fn get_flags() -> TimerSetTimeFlags;
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct RelativeTime
{
time_sec: i64,
time_nsec: i64,
}
impl From<Duration> for RelativeTime
{
fn from(value: Duration) -> Self
{
return Self
{
time_sec:
value.as_secs() as i64,
time_nsec:
value.subsec_nanos() as i64,
};
}
}
impl From<RelativeTime> for Duration
{
fn from(value: RelativeTime) -> Self
{
return Duration::new(value.time_sec as u64, value.time_nsec as u32);
}
}
impl Ord for RelativeTime
{
fn cmp(&self, other: &Self) -> Ordering
{
return
self
.time_sec
.cmp(&other.time_sec)
.then(
self
.time_nsec
.cmp(&other.time_nsec)
);
}
}
impl PartialOrd for RelativeTime
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering>
{
return Some(self.cmp(other));
}
}
impl fmt::Display for RelativeTime
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
write!(f, "[relative] sec: {}, nsec: {}", self.time_sec, self.time_nsec)
}
}
impl ModeTimeType for RelativeTime
{
fn new(time_spec: timespec) -> RelativeTime
{
return
Self::new_time(time_spec.tv_sec, time_spec.tv_nsec);
}
fn get_sec(&self) -> i64
{
return self.time_sec;
}
fn get_nsec(&self) -> i64 {
return self.time_nsec;
}
fn is_value_valid(&self) -> bool
{
return true;
}
fn get_flags() -> TimerSetTimeFlags
{
return TimerSetTimeFlags::empty();
}
}
impl RelativeTime
{
pub const MAX_NS: i64 = 1_000_000_000;
pub
fn new_time(time_sec: i64, time_nsec: i64) -> Self
{
let extra_sec = time_nsec / Self::MAX_NS;
let nsec_new = time_nsec % Self::MAX_NS;
return
Self
{
time_nsec: nsec_new,
time_sec: time_sec + extra_sec,
};
}
pub
fn is_zero(&self) -> bool
{
return self.time_nsec == 0 && self.time_sec == 0;
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct AbsoluteTime
{
time_sec: i64,
time_nsec: i64,
}
impl<TZ: TimeZone> From<DateTime<TZ>> for AbsoluteTime
{
fn from(value: DateTime<TZ>) -> Self
{
return Self
{
time_sec:
value.timestamp(),
time_nsec:
value.timestamp_subsec_nanos() as i64,
};
}
}
impl From<Duration> for AbsoluteTime
{
fn from(value: Duration) -> Self
{
return Self
{
time_sec:
value.as_secs() as i64,
time_nsec:
value.subsec_nanos() as i64,
};
}
}
impl From<AbsoluteTime> for Duration
{
fn from(value: AbsoluteTime) -> Self
{
return Duration::new(value.time_sec as u64, value.time_nsec as u32);
}
}
impl Ord for AbsoluteTime
{
fn cmp(&self, other: &Self) -> Ordering
{
return
self
.time_sec
.cmp(&other.time_sec)
.then(
self
.time_nsec
.cmp(&other.time_nsec)
);
}
}
impl PartialOrd for AbsoluteTime
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering>
{
return Some(self.cmp(other));
}
}
impl ops::AddAssign<Duration> for AbsoluteTime
{
fn add_assign(&mut self, rhs: Duration)
{
self.time_nsec += rhs.subsec_nanos() as i64;
let add_sec = self.time_nsec / Self::MAX_NS;
if add_sec > 0
{
self.time_nsec %= Self::MAX_NS;
}
self.time_sec += rhs.as_secs() as i64 + add_sec;
}
}
impl ops::AddAssign<RelativeTime> for AbsoluteTime
{
fn add_assign(&mut self, rhs: RelativeTime)
{
self.time_nsec += rhs.time_nsec;
let add_sec = self.time_nsec / Self::MAX_NS;
if add_sec > 0
{
self.time_nsec %= Self::MAX_NS;
}
self.time_sec += rhs.time_sec + add_sec;
}
}
impl ops::Add<Duration> for AbsoluteTime
{
type Output = AbsoluteTime;
fn add(mut self, rhs: Duration) -> Self::Output
{
self += rhs;
return self;
}
}
impl ops::Add<RelativeTime> for AbsoluteTime
{
type Output = AbsoluteTime;
fn add(mut self, rhs: RelativeTime) -> Self::Output
{
self += rhs;
return self;
}
}
impl ops::SubAssign<Duration> for AbsoluteTime
{
fn sub_assign(&mut self, rhs: Duration)
{
let mut sec = rhs.as_secs() as i64;
let mut nsec = self.time_nsec - rhs.subsec_nanos() as i64;
if nsec < 0
{
sec += 1;
nsec = Self::MAX_NS + nsec;
}
self.time_nsec = nsec;
self.time_sec -= sec;
return;
}
}
impl ops::SubAssign<RelativeTime> for AbsoluteTime
{
fn sub_assign(&mut self, mut rhs: RelativeTime)
{
let mut nsec = self.time_nsec - rhs.time_nsec;
if nsec < 0
{
rhs.time_sec += 1;
nsec = Self::MAX_NS + nsec;
}
self.time_nsec = nsec;
self.time_sec -= rhs.time_sec;
return;
}
}
impl ops::Sub<Duration> for AbsoluteTime
{
type Output = AbsoluteTime;
fn sub(mut self, rhs: Duration) -> Self::Output
{
self -= rhs;
return self;
}
}
impl ops::Sub<RelativeTime> for AbsoluteTime
{
type Output = AbsoluteTime;
fn sub(mut self, rhs: RelativeTime) -> Self::Output
{
self -= rhs;
return self;
}
}
impl ops::SubAssign for AbsoluteTime
{
fn sub_assign(&mut self, mut rhs: Self)
{
let mut nsec = self.time_nsec - rhs.time_nsec;
if nsec < 0
{
rhs.time_sec += 1;
nsec = Self::MAX_NS + nsec;
}
self.time_nsec = nsec;
self.time_sec -= rhs.time_sec;
return;
}
}
impl ops::Sub for AbsoluteTime
{
type Output = AbsoluteTime;
fn sub(mut self, rhs: Self) -> Self::Output
{
self -= rhs;
return self;
}
}
impl fmt::Display for AbsoluteTime
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
write!(f, "[absolute] {}.{:09}sec", self.time_sec, self.time_nsec)
}
}
impl ModeTimeType for AbsoluteTime
{
fn new(time_spec: timespec) -> Self where Self: Sized
{
return
unsafe { Self::new_time_unchecked(time_spec.tv_sec, time_spec.tv_nsec) };
}
fn get_sec(&self) -> i64
{
return self.time_sec;
}
fn get_nsec(&self) -> i64
{
return self.time_nsec;
}
fn is_value_valid(&self) -> bool
{
return self.time_nsec != 0 || self.time_sec != 0;
}
fn get_flags() -> TimerSetTimeFlags
{
return TimerSetTimeFlags::TFD_TIMER_ABSTIME | TimerSetTimeFlags::TFD_TIMER_CANCEL_ON_SET;
}
}
impl AbsoluteTime
{
pub const MAX_NS: i64 = 1_000_000_000;}
impl AbsoluteTime
{
pub
fn now() -> Self
{
let value = common::get_current_timestamp();
return Self
{
time_sec: value.timestamp(),
time_nsec: value.timestamp_subsec_nanos() as i64,
}
}
pub
fn new_time(time_sec: i64, time_nsec: i64) -> Option<Self>
{
let tm =
unsafe { Self::new_time_unchecked(time_sec, time_nsec) };
if tm.is_value_valid() == false
{
return None;
}
return Some(tm);
}
pub unsafe
fn new_time_unchecked(time_sec: i64, time_nsec: i64) -> Self
{
let extra_sec = time_nsec / Self::MAX_NS;
let nsec_new = time_nsec % Self::MAX_NS;
return
Self
{
time_nsec: nsec_new,
time_sec: time_sec + extra_sec,
};
}
pub
fn seconds_cmp(&self, other: &Self) -> Ordering
{
return self.time_sec.cmp(&other.time_sec);
}
pub
fn add_sec(mut self, seconds: i64) -> Self
{
self.time_sec += seconds;
return self;
}
pub
fn reset_nsec(mut self) -> Self
{
self.time_nsec = 0;
return self;
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TimerExpMode<TIMERTYPE: ModeTimeType>
{
None,
OneShot
{
timeout: TIMERTYPE
},
IntervalDelayed
{
delay_tm: TIMERTYPE,
interv_tm: TIMERTYPE
},
Interval
{
interv_tm: TIMERTYPE
},
}
impl ops::AddAssign<RelativeTime> for TimerExpMode<AbsoluteTime>
{
fn add_assign(&mut self, rhs: RelativeTime)
{
match self
{
TimerExpMode::None =>
return,
TimerExpMode::OneShot { timeout } =>
{
*timeout += rhs;
},
TimerExpMode::IntervalDelayed { interv_tm, .. } =>
{
*interv_tm += rhs;
},
TimerExpMode::Interval { interv_tm } =>
{
*interv_tm += rhs;
},
}
}
}
impl ops::Add<RelativeTime> for TimerExpMode<AbsoluteTime>
{
type Output = TimerExpMode<AbsoluteTime>;
fn add(mut self, rhs: RelativeTime) -> Self::Output
{
self += rhs;
return self;
}
}
impl<TIMERTYPE: ModeTimeType> Ord for TimerExpMode<TIMERTYPE>
{
fn cmp(&self, other: &Self) -> Ordering
{
match (self, other)
{
(TimerExpMode::None, TimerExpMode::None) =>
return Ordering::Equal,
(TimerExpMode::OneShot{ timeout }, TimerExpMode::OneShot { timeout: timeout2 }) =>
{
return timeout.cmp(timeout2);
},
(
TimerExpMode::IntervalDelayed{ delay_tm, interv_tm },
TimerExpMode::IntervalDelayed{ delay_tm: delay_tm2, interv_tm: interv_tm2 }
) =>
{
return
delay_tm.cmp(delay_tm2)
.then(interv_tm.cmp(interv_tm2));
},
(TimerExpMode::Interval { interv_tm }, TimerExpMode::Interval { interv_tm: interv_tm2 }) =>
{
return interv_tm.cmp(interv_tm2);
},
_ =>
panic!("cannot compare different types {} and {}", self, other)
}
}
}
impl<TIMERTYPE: ModeTimeType> PartialOrd for TimerExpMode<TIMERTYPE>
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering>
{
return Some(self.cmp(other));
}
}
impl TimerExpMode<AbsoluteTime>
{
#[inline]
fn is_valid_inner(&self) -> bool
{
match self
{
Self::None =>
return false,
Self::OneShot{ timeout} =>
return timeout.is_value_valid(),
Self::IntervalDelayed{ delay_tm, interv_tm } =>
return delay_tm.is_value_valid() && interv_tm.is_value_valid(),
Self::Interval{ interv_tm } =>
return interv_tm.is_value_valid()
}
}
pub
fn new_oneshot(abs_time: AbsoluteTime) -> Self
{
return Self::OneShot { timeout: abs_time };
}
}
impl TimerExpMode<RelativeTime>
{
pub
fn new_oneshot(rel_time: RelativeTime) -> Self
{
return Self::OneShot { timeout: rel_time };
}
pub
fn new_interval(rel_time: RelativeTime) -> Self
{
return Self::Interval { interv_tm: rel_time };
}
pub
fn new_interval_with_init_delay(delay_time: RelativeTime, intev_time: RelativeTime) -> Self
{
return Self::IntervalDelayed { delay_tm: delay_time, interv_tm: intev_time };
}
}
impl<TIMERTYPE: ModeTimeType> TimerExpMode<TIMERTYPE>
{
#[inline]
pub
fn reset() -> Self
{
return Self::None;
}
}
impl<TIMERTYPE: ModeTimeType> fmt::Display for TimerExpMode<TIMERTYPE>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
match self
{
Self::None =>
write!(f, "disarmed"),
Self::OneShot{ timeout } =>
write!(f, "oneshot {}", timeout),
Self::IntervalDelayed
{ delay_tm, interv_tm } =>
write!(f, "interval {} with delay {}", interv_tm, delay_tm),
Self::Interval{ interv_tm } =>
write!(f, "interval {}", interv_tm),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TimerReadRes<T: Sized + fmt::Debug + fmt::Display + Clone + Eq + PartialEq>
{
Ok(T),
Cancelled,
WouldBlock,
}
impl TimerReadRes<u64>
{
pub
fn ok() -> Self
{
return Self::Ok(1);
}
}
impl<T: Sized + fmt::Debug + fmt::Display + Clone + Eq + PartialEq> From<io::Error> for TimerReadRes<T>
{
fn from(value: io::Error) -> Self
{
if let Some(errn) = value.raw_os_error()
{
if errn == ECANCELED
{
return Self::Cancelled;
}
else if errn == EWOULDBLOCK
{
return Self::WouldBlock;
}
}
return Self::Cancelled;
}
}
impl<T: Sized + fmt::Debug + fmt::Display + Clone + Eq + PartialEq> fmt::Display for TimerReadRes<T>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
match self
{
Self::Ok(ovfl) =>
write!(f, "OK(overflows:{})", ovfl),
Self::Cancelled =>
write!(f, "CANCELLED"),
Self::WouldBlock =>
write!(f, "WOULDBLOCK"),
}
}
}
impl<T: Sized + fmt::Debug + fmt::Display + Clone + Eq + PartialEq> TimerReadRes<T>
{
pub
fn unwrap(self) -> T
{
let Self::Ok(t) = self
else { panic!("can not unwrap {:?}", self)};
return t;
}
}
pub trait FdTimerRead: AsFd + AsRawFd + fmt::Display + AsRef<str> + PartialEq<str> + PartialEq<RawFd>
{
fn read(&self) -> TimerPortResult<TimerReadRes<u64>>;
}
pub trait FdTimerMarker: FdTimerRead + Eq + PartialEq + PartialEq<RawFd>
{
fn clone_timer(&self) -> TimerFd;
fn get_strong_count(&self) -> usize;
}
pub trait FdTimerCom: FdTimerRead
{
fn new(label: Cow<'static, str>, timer_type: TimerType, timer_flags: TimerFlags) -> TimerPortResult<Self>
where Self: Sized;
fn set_time<TIMERTYPE: ModeTimeType>(&self, timer_exp: TimerExpMode<TIMERTYPE>) -> TimerPortResult<()>;
fn unset_time(&self) -> TimerPortResult<()>;
fn set_nonblocking(&self, flag: bool) -> TimerPortResult<()>;
fn is_nonblocking(&self) -> TimerPortResult<bool>;
}
#[derive(Debug)]
pub struct TimerFd(Arc<TimerFdInternal>);
impl fmt::Display for TimerFd
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
write!(f, "{}", self.0)
}
}
impl AsFd for TimerFd
{
fn as_fd(&self) -> BorrowedFd<'_>
{
return self.0.as_fd();
}
}
impl AsRawFd for TimerFd
{
fn as_raw_fd(&self) -> RawFd
{
return self.0.as_raw_fd();
}
}
impl AsRef<str> for TimerFd
{
fn as_ref(&self) -> &str
{
return self.0.as_ref().as_ref();
}
}
impl Eq for TimerFd {}
impl PartialEq for TimerFd
{
fn eq(&self, other: &Self) -> bool
{
return self.0 == other.0
}
}
impl PartialEq<RawFd> for TimerFd
{
fn eq(&self, other: &RawFd) -> bool
{
return self.0.as_raw_fd() == *other;
}
}
impl PartialEq<str> for TimerFd
{
fn eq(&self, other: &str) -> bool
{
return self.0.as_ref() == other;
}
}
impl FdTimerMarker for TimerFd
{
fn clone_timer(&self) -> TimerFd
{
return Self(self.0.clone());
}
fn get_strong_count(&self) -> usize
{
return Arc::strong_count(&self.0);
}
}
impl TimerFd
{
pub
fn new(label: Cow<'static, str>, timer_type: TimerType, timer_flags: TimerFlags) -> TimerPortResult<Self>
{
return Ok(
Self( Arc::new(TimerFdInternal::new(label, timer_type, timer_flags)?) )
);
}
pub
fn get_timer(&self) -> &TimerFdInternal
{
return &self.0;
}
}
impl FdTimerRead for TimerFd
{
fn read(&self) -> TimerPortResult<TimerReadRes<u64>>
{
return self.0.read();
}
}
pub use nix::libc::{itimerspec, timespec};
impl<TIMERTYPE: ModeTimeType> From<itimerspec> for TimerExpMode<TIMERTYPE>
{
fn from(value: itimerspec) -> Self
{
if value.it_interval.tv_sec == 0 && value.it_interval.tv_nsec == 0 &&
value.it_value.tv_sec == 0 && value.it_value.tv_nsec == 0
{
return Self::None;
}
else if value.it_interval.tv_sec == 0 && value.it_interval.tv_nsec == 0
{
return
Self::OneShot
{
timeout: TIMERTYPE::new(value.it_value)
};
}
else if value.it_interval.tv_sec == value.it_value.tv_sec &&
value.it_interval.tv_nsec == value.it_value.tv_nsec
{
return
Self::Interval
{
interv_tm: TIMERTYPE::new(value.it_interval)
};
}
else
{
return
Self::IntervalDelayed
{
delay_tm: TIMERTYPE::new(value.it_value),
interv_tm: TIMERTYPE::new(value.it_interval)
};
}
}
}
impl<TIMERTYPE: ModeTimeType> From<TimerExpMode<TIMERTYPE>> for itimerspec
{
fn from(value: TimerExpMode<TIMERTYPE>) -> Self
{
return (&value).into();
}
}
impl<TIMERTYPE: ModeTimeType> From<&TimerExpMode<TIMERTYPE>> for itimerspec
{
fn from(value: &TimerExpMode<TIMERTYPE>) -> Self
{
match value
{
TimerExpMode::None =>
return
itimerspec
{
it_interval: timespec
{
tv_sec: 0,
tv_nsec: 0,
},
it_value: timespec
{
tv_sec: 0,
tv_nsec: 0,
},
},
TimerExpMode::OneShot{ timeout} =>
return
itimerspec
{
it_interval: timespec
{
tv_sec: 0,
tv_nsec: 0,
},
it_value: timespec
{
tv_sec: timeout.get_sec(),
tv_nsec: timeout.get_nsec(),
},
},
TimerExpMode::IntervalDelayed{ delay_tm, interv_tm } =>
return
itimerspec
{
it_interval: timespec
{
tv_sec: interv_tm.get_sec(),
tv_nsec: interv_tm.get_nsec(),
},
it_value: timespec
{
tv_sec: delay_tm.get_sec(),
tv_nsec: delay_tm.get_nsec(),
},
},
TimerExpMode::Interval{ interv_tm } =>
return
itimerspec
{
it_interval: timespec
{
tv_sec: interv_tm.get_sec(),
tv_nsec: interv_tm.get_nsec(),
},
it_value: timespec
{
tv_sec: interv_tm.get_sec(),
tv_nsec: interv_tm.get_nsec(),
},
}
}
}
}
#[cfg(test)]
mod tests
{
use crate::{common, timer_portable::timer::{AbsoluteTime, ModeTimeType, RelativeTime, TimerExpMode}};
#[test]
fn test_0()
{
let ts = common::get_current_timestamp();
let texp1 = TimerExpMode::<AbsoluteTime>::new_oneshot(AbsoluteTime::from(ts));
assert_eq!(
TimerExpMode::OneShot { timeout: AbsoluteTime::from(ts) },
texp1
);
}
#[test]
fn test_1()
{
let ts = common::get_current_timestamp();
let texp1 =
TimerExpMode::<AbsoluteTime>::new_oneshot(AbsoluteTime::from(ts));
let texp2 =
texp1 + RelativeTime::new_time(1, 0);
assert_eq!(texp1 < texp2, true);
assert_eq!(texp2 > texp1, true);
assert_eq!(texp2 != texp1, true);
assert_eq!(texp2 < texp1, false);
}
#[test]
fn test_2()
{
let texp1 =
TimerExpMode::<AbsoluteTime>::new_oneshot(
unsafe {AbsoluteTime::new_time_unchecked(100, AbsoluteTime::MAX_NS)}
);
let texp2 =
texp1 + RelativeTime::new_time(0, 1);
assert_eq!(texp1 < texp2, true);
assert_eq!(texp2 > texp1, true);
assert_eq!(texp2 != texp1, true);
assert_eq!(texp2 < texp1, false);
}
#[should_panic]
#[test]
fn test_2_fail()
{
let ts = common::get_current_timestamp();
let texp1 =
TimerExpMode::<AbsoluteTime>::new_oneshot(AbsoluteTime::from(ts));
let texp2 =
TimerExpMode::<AbsoluteTime>::Interval { interv_tm: AbsoluteTime::from(ts)};
assert_eq!(texp1 == texp2, true);
}
#[test]
fn test_abstime_cmp()
{
let abs_time = AbsoluteTime::now();
let abs_time_future = abs_time + RelativeTime::new_time(10, 1);
let abs_time_past = abs_time - RelativeTime::new_time(10, 1);
assert_eq!(abs_time < abs_time_future, true);
assert_eq!(abs_time_future > abs_time, true);
assert_eq!(abs_time > abs_time_past, true);
assert_eq!(abs_time_past < abs_time, true);
assert_eq!(abs_time_future > abs_time_past, true);
assert_eq!(abs_time_past < abs_time_future, true);
}
#[test]
fn test_abstime_new()
{
let abs = AbsoluteTime::new_time(1, 999_999_999).unwrap();
assert_eq!(abs.time_nsec, 999_999_999);
assert_eq!(abs.time_sec, 1);
let abs = AbsoluteTime::new_time(1, 1_000_000_000).unwrap();
assert_eq!(abs.time_nsec, 0);
assert_eq!(abs.time_sec, 2);
let abs = AbsoluteTime::new_time(1, 1_000_000_001).unwrap();
assert_eq!(abs.time_nsec, 1);
assert_eq!(abs.time_sec, 2);
let abs = AbsoluteTime::new_time(1, 2_000_000_001).unwrap();
assert_eq!(abs.time_nsec, 1);
assert_eq!(abs.time_sec, 3);
}
#[test]
fn test_abstime_add()
{
let mut abs = AbsoluteTime::new_time(1, 999_999_999).unwrap();
abs += RelativeTime::new_time(0, 1);
assert_eq!(abs.time_nsec, 0);
assert_eq!(abs.time_sec, 2);
abs += RelativeTime::new_time(1, 1);
assert_eq!(abs.time_nsec, 1);
assert_eq!(abs.time_sec, 3);
abs += RelativeTime::new_time(0, 999_999_999);
assert_eq!(abs.time_nsec, 0);
assert_eq!(abs.time_sec, 4);
abs -= RelativeTime::new_time(0, 999_999_999);
assert_eq!(abs.time_nsec, 1);
assert_eq!(abs.time_sec, 3);
abs -= RelativeTime::new_time(0, 1);
assert_eq!(abs.time_nsec, 0);
assert_eq!(abs.time_sec, 3);
abs -= RelativeTime::new_time(0, 500_000_000);
assert_eq!(abs.time_nsec, 500_000_000);
assert_eq!(abs.time_sec, 2);
abs -= RelativeTime::new_time(0, 400_000_000);
assert_eq!(abs.time_nsec, 100_000_000);
assert_eq!(abs.time_sec, 2);
abs -= RelativeTime::new_time(1, 200_000_000);
assert_eq!(abs.time_nsec, 900_000_000);
assert_eq!(abs.time_sec, 0);
}
}