use std::{borrow::{Borrow, Cow}, cmp::Ordering, fmt, io::{self}, ops::{self, Deref}, sync::Arc, task::Poll, time::Duration};
use chrono::{DateTime, TimeZone};
use crate::{common, timer_portable::{portable_error::TimerPortResult}};
#[cfg(target_family = "unix")]
use super::unix::TimerFdInternal;
#[cfg(target_family = "windows")]
use super::windows::timer_fd_windows::TimerFdInternal;
use super::{timespec, TimerSetTimeFlags, UnixFd, TimerType, TimerFlags};
pub trait ModeTimeType:
Eq + PartialEq + Ord + PartialOrd + fmt::Display + fmt::Debug + Clone + Copy +
From<timespec> + fmt::Display
{
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<i64> for RelativeTime
{
fn from(value: i64) -> Self
{
return
Self
{
time_sec:
value,
time_nsec:
0
};
}
}
impl From<u64> for RelativeTime
{
fn from(value: u64) -> Self
{
return
Self
{
time_sec:
value as i64,
time_nsec:
0
};
}
}
impl From<(i64, i64)> for RelativeTime
{
fn from(value: (i64, i64)) -> Self
{
return
Self
{
time_sec:
value.0,
time_nsec:
value.1
};
}
}
impl From<u128> for RelativeTime
{
fn from(value: u128) -> Self
{
return
Self
{
time_sec:
((value & 0xFFFF_FFFF_FFFF_FFFF_0000_0000_0000_0000) >> 64) as i64,
time_nsec:
(value & 0x0000_0000_0000_0000_FFFF_FFFF_FFFF_FFFF) 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 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<i64> for AbsoluteTime
{
fn from(value: i64) -> Self
{
return
Self
{
time_sec:
value,
time_nsec:
0
};
}
}
impl From<u64> for AbsoluteTime
{
fn from(value: u64) -> Self
{
return
Self
{
time_sec:
value as i64,
time_nsec:
0
};
}
}
impl From<(i64, i64)> for AbsoluteTime
{
fn from(value: (i64, i64)) -> Self
{
return
Self
{
time_sec:
value.0,
time_nsec:
value.1
};
}
}
impl From<u128> for AbsoluteTime
{
fn from(value: u128) -> Self
{
return
Self
{
time_sec:
((value & 0xFFFF_FFFF_FFFF_FFFF_0000_0000_0000_0000) >> 64) as i64,
time_nsec:
(value & 0x0000_0000_0000_0000_FFFF_FFFF_FFFF_FFFF) 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 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: impl Into<AbsoluteTime>) -> Self
{
return Self::OneShot { timeout: abs_time.into() };
}
}
impl TimerExpMode<RelativeTime>
{
pub
fn new_oneshot(rel_time: impl Into<RelativeTime>) -> Self
{
return Self::OneShot { timeout: rel_time.into() };
}
pub
fn new_interval(rel_time: impl Into<RelativeTime>) -> Self
{
return Self::Interval { interv_tm: rel_time.into() };
}
pub
fn new_interval_with_init_delay(delay_time: impl Into<RelativeTime>, intev_time: impl Into<RelativeTime>) -> Self
{
return Self::IntervalDelayed { delay_tm: delay_time.into(), interv_tm: intev_time.into() };
}
}
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> 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;
}
}
#[cfg(all(target_family = "unix", feature = "enable_mio_compat"))]
pub trait TimerFdMioCompat: mio::event::Source + PartialEq<mio::Token>
{
fn get_token(&self) -> mio::Token;
}
pub trait AsTimerId
{
fn as_timer_id(&self) -> TimerId;
}
#[repr(transparent)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct TimerId(pub(crate) usize);
impl PartialEq<usize> for TimerId
{
fn eq(&self, other: &usize) -> bool
{
return self.0 == *other;
}
}
impl fmt::Display for TimerId
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
write!(f, "{}", self.0)
}
}
impl Borrow<usize> for TimerId
{
fn borrow(&self) -> &usize
{
return &self.0;
}
}
pub trait FdTimerRead: UnixFd + fmt::Display + AsRef<str> + PartialEq<str> + AsTimerId
{
fn read(&self) -> TimerPortResult<TimerReadRes<u64>>;
}
pub trait FdTimerMarker: FdTimerRead + Eq + PartialEq
{
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>;
}
#[repr(transparent)]
#[derive(Debug)]
pub struct TimerFd(Arc<TimerFdInternal>);
impl AsTimerId for TimerFd
{
fn as_timer_id(&self) -> TimerId
{
return self.0.as_timer_id();
}
}
impl fmt::Display for TimerFd
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
write!(f, "{}", self.0)
}
}
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<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 Deref for TimerFd
{
type Target = TimerFdInternal;
fn deref(&self) -> &Self::Target
{
return self.0.as_ref();
}
}
impl Future for &TimerFd
{
type Output = TimerPortResult<TimerReadRes<u64>>;
fn poll(self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> std::task::Poll<Self::Output>
{
let res = self.get_timer().read();
if let Ok(TimerReadRes::WouldBlock) = res
{
cx.waker().wake_by_ref();
return Poll::Pending;
}
else
{
return Poll::Ready(res);
}
}
}
impl Future for TimerFd
{
type Output = TimerPortResult<TimerReadRes<u64>>;
fn poll(self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> std::task::Poll<Self::Output>
{
let res = self.get_timer().read();
if let Ok(TimerReadRes::WouldBlock) = res
{
cx.waker().wake_by_ref();
return Poll::Pending;
}
else
{
return Poll::Ready(res);
}
}
}
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();
}
}
#[cfg(test)]
mod tests
{
use std::time::Duration;
use crate::{common, timer_portable::timer::{AbsoluteTime, 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);
}
#[test]
fn test_timer_from_test()
{
let abs1 = AbsoluteTime::from((100, 200));
assert_eq!(abs1.time_sec, 100);
assert_eq!(abs1.time_nsec, 200);
let abs2 = AbsoluteTime::from(0x0000_0000_0000_00FF_0000_0000_0000_0AAA as u128);
assert_eq!(abs2.time_sec, 0xFF);
assert_eq!(abs2.time_nsec, 0xAAA);
let abs3 = AbsoluteTime::from(400 as u64);
assert_eq!(abs3.time_sec, 400);
assert_eq!(abs3.time_nsec, 0);
let abs4 = AbsoluteTime::from(Duration::new(456, 123456));
assert_eq!(abs4.time_sec, 456);
assert_eq!(abs4.time_nsec, 123456);
}
#[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);
}
}
#[cfg(all(target_family = "unix", feature = "enable_mio_compat"))]
#[cfg(test)]
mod tests_mio_compat
{
use std::time::Duration;
use mio::{Events, Interest, Poll};
use crate::{AbsoluteTime, FdTimerCom, RelativeTime, TimerReadRes, timer_portable::{TimerExpMode, TimerFd, TimerFdMioCompat, TimerFlags, TimerType, timer::{FdTimerRead, ModeTimeType}}};
fn test1_handle(id: u64, time_dif: i64, timer_tm: AbsoluteTime, events: &Events, timer: &TimerFd)
{
let timer_tm_end = AbsoluteTime::now();
let timer_tm_dif = timer_tm_end - timer_tm;
println!("timer{}: armed: {} event: {} dif: {}", id, timer_tm, timer_tm_end, timer_tm_dif);
assert_eq!(timer_tm_dif.get_sec(), time_dif);
let mut ev_iter = events.iter();
let event1 = ev_iter.next();
assert_eq!(event1.is_some(), true);
let event1 = event1.unwrap();
assert_eq!(event1.token(), timer.get_token());
let timer1_res = timer.read().unwrap();
assert_eq!(timer1_res, TimerReadRes::Ok(1));
assert_eq!(ev_iter.next().is_none(), true);
}
#[test]
fn mio_test1()
{
let mut poll = Poll::new().unwrap();
let mut events = Events::with_capacity(2);
let mut timer1 =
TimerFd::new("timer1".into(), TimerType::CLOCK_REALTIME,
TimerFlags::TFD_NONBLOCK)
.unwrap();
let mut timer2 =
TimerFd::new("timer2".into(), TimerType::CLOCK_REALTIME,
TimerFlags::TFD_NONBLOCK)
.unwrap();
let tok = timer1.get_token();
poll
.registry()
.register(&mut timer1, tok, Interest::READABLE)
.unwrap();
let tok = timer2.get_token();
poll
.registry()
.register(&mut timer2, tok, Interest::READABLE)
.unwrap();
let timer_tm = AbsoluteTime::now();
timer1.set_time(TimerExpMode::<RelativeTime>::new_oneshot(2 as i64)).unwrap();
timer2.set_time(TimerExpMode::<RelativeTime>::new_oneshot(3 as i64)).unwrap();
poll.poll(&mut events, Some(Duration::from_millis(2500))).unwrap();
test1_handle(1, 2, timer_tm, &events, &timer1);
poll.poll(&mut events, Some(Duration::from_millis(1300))).unwrap();
test1_handle(2, 3, timer_tm, &events, &timer2);
}
}
#[cfg(test)]
mod test_timer_fd
{
use std::{time::{Duration, Instant, SystemTime}};
use crate::timer_portable::timer::AbsoluteTime;
use super::*;
#[test]
fn test0()
{
let timer =
TimerFd::new(Cow::Borrowed("test"), TimerType::CLOCK_REALTIME,
TimerFlags::empty()).unwrap();
let full_now = SystemTime::now(); let s = Instant::now();
let timer_mode1 =
TimerExpMode::<RelativeTime>::new_oneshot(
Duration::from_secs(3)
);
let res =
timer
.set_time(timer_mode1);
println!("now: '{}', timer was set: '{}'",
full_now.duration_since(std::time::UNIX_EPOCH).unwrap().as_secs(),
full_now.duration_since(std::time::UNIX_EPOCH).unwrap().as_secs() + 3
);
assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
let ovf = timer.read().unwrap().unwrap();
let elapsed = full_now.elapsed().unwrap();
assert_eq!(ovf, 1);
println!("elapsed: {:?}, ts: {}", elapsed, full_now.duration_since(std::time::UNIX_EPOCH).unwrap().as_secs());
assert_eq!((elapsed.as_millis() <= 3100), true);
println!("Success");
return;
}
#[test]
fn test1()
{
let timer =
TimerFd::new(Cow::Borrowed("test"), TimerType::CLOCK_REALTIME,
TimerFlags::empty()).unwrap();
let abs_time_now = AbsoluteTime::now();
let snow = abs_time_now + Duration::from_secs(3);
let s = Instant::now();
let timer_mode1 =
TimerExpMode::<AbsoluteTime>::new_oneshot(snow);
let res =
timer
.set_time(timer_mode1);
println!("now: '{}', timer was set to: '{}'", abs_time_now, snow);
assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
let ovf = timer.read().unwrap().unwrap();
let abs_time_now = AbsoluteTime::now();
let e = s.elapsed();
assert_eq!(ovf, 1);
assert_eq!(abs_time_now.seconds_cmp(&snow), Ordering::Equal);
println!("elapsed: {:?}, ts: {}", e, abs_time_now);
assert_eq!((e.as_millis() <= 3100), true);
println!("Success");
return;
}
#[test]
fn test1_1()
{
let timer =
TimerFdInternal::new(Cow::Borrowed("test"), TimerType::CLOCK_REALTIME,
TimerFlags::empty()).unwrap();
let ts = common::get_current_timestamp();
let set_ts = AbsoluteTime::from(ts) + RelativeTime::new_time(3, 0);
let timer1_time =
TimerExpMode::<AbsoluteTime>::new_oneshot(set_ts);
timer.set_time(timer1_time).unwrap();
let res = timer.read().unwrap();
let ts = common::get_current_timestamp();
assert_eq!(AbsoluteTime::from(ts).seconds_cmp(&set_ts), Ordering::Equal);
let set_ts = AbsoluteTime::from(ts) + RelativeTime::new_time(3, 0);
let timer1_time =
TimerExpMode
::<AbsoluteTime>
::new_oneshot(set_ts);
timer.set_time(timer1_time).unwrap();
let res = timer.read().unwrap();
let ts = common::get_current_timestamp();
assert_eq!(AbsoluteTime::from(ts).seconds_cmp(&set_ts), Ordering::Equal);
println!("Success");
return;
}
#[tokio::test]
async fn test2_fut()
{
let timer =
TimerFd::new(Cow::Borrowed("test"), TimerType::CLOCK_REALTIME,
TimerFlags::empty()).unwrap();
let now = chrono::offset::Local::now().timestamp();
let snow = now + 3;
let s = Instant::now();
let timer_mode1 =
TimerExpMode::<AbsoluteTime>::new_oneshot(
AbsoluteTime::new_time(snow, 0).unwrap()
);
let res =
timer
.set_time(timer_mode1);
println!("timer was set: '{}' '{}'", now, snow);
assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
tokio::select! {
ovf = timer => {
let ts = chrono::offset::Local::now().timestamp();
let e = s.elapsed();
assert_eq!(ovf, Ok(TimerReadRes::Ok(1)));
assert_eq!(ts, snow);
println!("timeout e: {:?}, ts:{} snow:{}", e, ts, snow);
}
}
}
#[cfg(target_family = "unix")]
#[tokio::test]
async fn test3_tokio()
{
use tokio::io::{unix::AsyncFd, Interest};
let mut timer: AsyncFd<TimerFd> =
AsyncFd::with_interest(
TimerFd::new(Cow::Borrowed("test"), TimerType::CLOCK_REALTIME,
TimerFlags::empty()).unwrap(),
Interest::READABLE
).unwrap();
let now = chrono::offset::Local::now().timestamp();
let snow = now + 3;
let s = Instant::now();
let timer_mode1 =
TimerExpMode::<AbsoluteTime>::new_oneshot(
AbsoluteTime::new_time(snow, 0).unwrap()
);
let res =
timer
.get_mut()
.set_time(timer_mode1);
println!("timer was set: '{}' '{}'", now, snow);
assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
tokio::select! {
read_guard_res = timer.ready(Interest::READABLE) =>
{
let read_guard = read_guard_res.unwrap();
let res = read_guard.get_inner().read();
let ts = chrono::offset::Local::now().timestamp();
let e = s.elapsed();
assert_eq!(res, Ok(TimerReadRes::Ok(1)));
assert_eq!(ts, snow);
println!("timeout e: {:?}, ts:{} snow:{}", e, ts, snow);
}
}
}
#[test]
fn test4_cancel()
{
let timer =
TimerFd::new(Cow::Borrowed("test"), TimerType::CLOCK_REALTIME,
TimerFlags::TFD_NONBLOCK).unwrap();
let now = chrono::offset::Local::now().timestamp();
let snow = now + 3;
let s = Instant::now();
let timer_mode1 =
TimerExpMode::<AbsoluteTime>::new_oneshot(
AbsoluteTime::new_time(snow, 0).unwrap()
);
let res =
timer
.set_time(timer_mode1);
println!("timer was set: '{}' '{}'", now, snow);
assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
let ovf = timer.read().unwrap();
println!("{}", ovf);
timer.unset_time().unwrap();
let ovf = timer.read().unwrap();
println!("{}", ovf);
}
#[test]
fn test5_preiodic_with_delay()
{
let timer =
TimerFd::new(Cow::Borrowed("test"), TimerType::CLOCK_REALTIME,
TimerFlags::empty()).unwrap();
let timer_mode1 =
TimerExpMode
::<RelativeTime>
::new_interval_with_init_delay(
RelativeTime::new_time(1, 0),
RelativeTime::new_time(0, 500_000_000)
);
timer.set_time(timer_mode1).unwrap();
let start = AbsoluteTime::now();
let res = timer.read().unwrap();
let end = AbsoluteTime::now();
let diff = end - start;
println!("timer was set s: '{}' e:'{}', diff = '{}' res: '{}'", start, end, diff, res);
assert_eq!((diff.get_sec() == 0 && diff.get_nsec() <= 995_000_000) || (diff.get_sec() == 1), true);
assert_eq!(res, TimerReadRes::Ok(1));
let res = timer.read().unwrap();
let end2 = AbsoluteTime::now();
let diff = end2 - end;
println!("timer was set s: '{}' e:'{}', diff = '{}' res: '{}'", end, end2, diff, res);
assert_eq!(diff.get_sec(), 0);
assert!(diff.get_nsec() >= 499_930_000 && diff.get_nsec() <= 500_900_000);
assert_eq!(res, TimerReadRes::Ok(1));
let res = timer.read().unwrap();
let end3 = AbsoluteTime::now();
let diff = end3 - end2;
println!("timer was set s: '{}' e:'{}', diff = '{}' res: '{}'", end2, end3, diff, res);
assert_eq!(diff.get_sec(), 0);
assert!(diff.get_nsec() >= 499_430_000 && diff.get_nsec() <= 500_900_000);
assert_eq!(res, TimerReadRes::Ok(1));
timer.unset_time().unwrap();
timer.set_nonblocking(true).unwrap();
std::thread::sleep(Duration::from_millis(1000));
let res = timer.read().unwrap();
assert_eq!(res, TimerReadRes::WouldBlock);
}
}