use crate::{duration::Duration, ConversionError};
use core::{cmp::Ordering, convert::TryFrom, ops};
use num::traits::{WrappingAdd, WrappingSub};
#[derive(Debug)]
pub struct Instant<Clock: crate::Clock> {
ticks: Clock::Rep,
}
impl<Clock: crate::Clock> Instant<Clock> {
pub fn new(ticks: Clock::Rep) -> Self {
Self { ticks }
}
pub fn duration_since<Dur: Duration>(&self, other: &Self) -> Result<Dur, ConversionError>
where
Dur::Rep: TryFrom<Clock::Rep>,
{
if self >= other {
Dur::from_ticks(self.ticks.wrapping_sub(&other.ticks), Clock::PERIOD)
} else {
Err(ConversionError::NegDuration)
}
}
pub fn duration_until<Dur: Duration>(&self, other: &Self) -> Result<Dur, ConversionError>
where
Dur::Rep: TryFrom<Clock::Rep>,
{
if self <= other {
Dur::from_ticks(other.ticks.wrapping_sub(&self.ticks), Clock::PERIOD)
} else {
Err(ConversionError::NegDuration)
}
}
pub fn duration_since_epoch<Dur: Duration>(&self) -> Result<Dur, ConversionError>
where
Dur::Rep: TryFrom<Clock::Rep>,
Clock::Rep: TryFrom<Dur::Rep>,
{
Self::duration_since::<Dur>(
&self,
&Self {
ticks: Clock::Rep::from(0),
},
)
}
pub fn checked_add_duration<Dur: Duration>(self, duration: Dur) -> Result<Self, ConversionError>
where
Clock::Rep: TryFrom<Dur::Rep>,
{
let add_ticks: Clock::Rep = duration.into_ticks(Clock::PERIOD)?;
if add_ticks <= (<Clock::Rep as num::Bounded>::max_value() / 2.into()) {
Ok(Self {
ticks: self.ticks.wrapping_add(&add_ticks),
})
} else {
Err(ConversionError::Overflow)
}
}
pub fn checked_sub_duration<Dur: Duration>(self, duration: Dur) -> Result<Self, ConversionError>
where
Clock::Rep: TryFrom<Dur::Rep>,
{
let sub_ticks: Clock::Rep = duration.into_ticks(Clock::PERIOD)?;
if sub_ticks <= (<Clock::Rep as num::Bounded>::max_value() / 2.into()) {
Ok(Self {
ticks: self.ticks.wrapping_sub(&sub_ticks),
})
} else {
Err(ConversionError::Overflow)
}
}
}
impl<Clock: crate::Clock> Copy for Instant<Clock> {}
impl<Clock: crate::Clock> Clone for Instant<Clock> {
fn clone(&self) -> Self {
Self { ticks: self.ticks }
}
}
impl<Clock: crate::Clock> PartialEq for Instant<Clock> {
fn eq(&self, other: &Self) -> bool {
self.ticks == other.ticks
}
}
impl<Clock: crate::Clock> Eq for Instant<Clock> {}
impl<Clock: crate::Clock> PartialOrd for Instant<Clock> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(&other))
}
}
impl<Clock: crate::Clock> Ord for Instant<Clock> {
fn cmp(&self, other: &Self) -> Ordering {
self.ticks
.wrapping_sub(&other.ticks)
.cmp(&(<Clock::Rep as num::Bounded>::max_value() / 2.into()))
.reverse()
}
}
impl<Clock: crate::Clock, Dur: Duration> ops::Add<Dur> for Instant<Clock>
where
Clock::Rep: TryFrom<Dur::Rep>,
{
type Output = Self;
fn add(self, rhs: Dur) -> Self::Output {
self.checked_add_duration(rhs).unwrap()
}
}
impl<Clock: crate::Clock, Dur: Duration> ops::Sub<Dur> for Instant<Clock>
where
Clock::Rep: TryFrom<Dur::Rep>,
{
type Output = Self;
fn sub(self, rhs: Dur) -> Self::Output {
self.checked_sub_duration(rhs).unwrap()
}
}
#[cfg(test)]
mod tests {
use crate::{self as time, units::*, ConversionError, Instant, Period};
#[derive(Debug)]
struct Clock;
impl time::Clock for Clock {
type Rep = u32;
const PERIOD: Period = <Period>::new(1, 1_000);
type ImplError = ();
fn now(&self) -> Result<Instant<Self>, time::clock::Error<Self::ImplError>> {
unimplemented!()
}
}
#[test]
fn duration_since() {
let diff: Result<Milliseconds<_>, _> =
Instant::<Clock>::new(5).duration_since(&Instant::<Clock>::new(3));
assert_eq!(diff, Ok(Milliseconds(2_u32)));
let diff: Result<Microseconds<u64>, _> =
Instant::<Clock>::new(5).duration_since(&Instant::<Clock>::new(3));
assert_eq!(diff, Ok(Microseconds(2_000_u64)));
let diff: Result<Microseconds<u64>, _> =
Instant::<Clock>::new(u32::MIN).duration_since(&Instant::<Clock>::new(u32::MAX));
assert_eq!(diff, Ok(Microseconds(1_000_u64)));
let diff: Result<Microseconds<u64>, _> =
Instant::<Clock>::new(5).duration_since(&Instant::<Clock>::new(6));
assert_eq!(diff, Err(ConversionError::NegDuration));
}
}