use crate::{
duration::{self, Duration},
fixed_point::FixedPoint,
};
use core::{
cmp::Ordering,
convert::TryFrom,
hash::{Hash, Hasher},
ops,
};
use num::traits::{WrappingAdd, WrappingSub};
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Instant<Clock: crate::Clock> {
ticks: Clock::T,
}
impl<Clock: crate::Clock> Instant<Clock> {
pub fn new(ticks: Clock::T) -> Self {
Self { ticks }
}
pub fn checked_duration_since(&self, other: &Self) -> Option<duration::Generic<Clock::T>> {
if self >= other {
Some(duration::Generic::new(
self.ticks.wrapping_sub(&other.ticks),
Clock::SCALING_FACTOR,
))
} else {
None
}
}
pub fn checked_duration_until(&self, other: &Self) -> Option<duration::Generic<Clock::T>> {
if self <= other {
Some(duration::Generic::new(
other.ticks.wrapping_sub(&self.ticks),
Clock::SCALING_FACTOR,
))
} else {
None
}
}
pub fn duration_since_epoch(&self) -> duration::Generic<Clock::T> {
duration::Generic::new(self.ticks, Clock::SCALING_FACTOR)
}
pub fn checked_add<Dur: Duration>(self, duration: Dur) -> Option<Self>
where
Dur: FixedPoint,
Clock::T: TryFrom<Dur::T> + core::ops::Div<Output = Clock::T>,
{
let add_ticks: Clock::T = duration.into_ticks(Clock::SCALING_FACTOR).ok()?;
if add_ticks <= (<Clock::T as num::Bounded>::max_value() / 2.into()) {
Some(Self {
ticks: self.ticks.wrapping_add(&add_ticks),
})
} else {
None
}
}
pub fn checked_sub<Dur: Duration>(self, duration: Dur) -> Option<Self>
where
Dur: FixedPoint,
Clock::T: TryFrom<Dur::T> + core::ops::Div<Output = Clock::T>,
{
let sub_ticks: Clock::T = duration.into_ticks(Clock::SCALING_FACTOR).ok()?;
if sub_ticks <= (<Clock::T as num::Bounded>::max_value() / 2.into()) {
Some(Self {
ticks: self.ticks.wrapping_sub(&sub_ticks),
})
} else {
None
}
}
}
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> Ord for Instant<Clock>
where
Clock: crate::Clock,
Clock::T: ops::Div<Output = Clock::T>,
{
fn cmp(&self, other: &Self) -> Ordering {
if self.ticks == other.ticks {
Ordering::Equal
} else {
self.ticks
.wrapping_sub(&other.ticks)
.cmp(&(<Clock::T as num::Bounded>::max_value() / 2.into()))
.reverse()
}
}
}
impl<Clock: crate::Clock, Dur: Duration> ops::Add<Dur> for Instant<Clock>
where
Clock::T: TryFrom<Dur::T>,
Dur: FixedPoint,
{
type Output = Self;
fn add(self, rhs: Dur) -> Self::Output {
if let Some(v) = self.checked_add(rhs) {
v
} else {
panic!("Add failed")
}
}
}
impl<Clock: crate::Clock, Dur: Duration> ops::Sub<Dur> for Instant<Clock>
where
Clock::T: TryFrom<Dur::T>,
Dur: FixedPoint,
{
type Output = Self;
fn sub(self, rhs: Dur) -> Self::Output {
if let Some(v) = self.checked_sub(rhs) {
v
} else {
panic!("Sub failed")
}
}
}
impl<Clock: crate::Clock> ops::Sub<Instant<Clock>> for Instant<Clock> {
type Output = duration::Generic<Clock::T>;
fn sub(self, rhs: Instant<Clock>) -> Self::Output {
if let Some(v) = self.checked_duration_since(&rhs) {
v
} else {
panic!("Sub failed")
}
}
}
impl<Clock: crate::clock::Clock> Hash for Instant<Clock> {
fn hash<H: Hasher>(&self, state: &mut H) {
Clock::SCALING_FACTOR.hash(state);
self.ticks.hash(state);
}
}
#[cfg(test)]
mod tests {}