use crate::duration::{Duration, Period};
use crate::helpers::Helpers;
use core::cmp::Ordering;
use core::marker::PhantomData;
use core::ops;
use typenum::{NonZero, Unsigned};
#[derive(Clone, Copy, Debug)]
pub struct Instant<T, Numer, Denom: NonZero> {
pub since_start: Duration<T, Numer, Denom>,
}
macro_rules! impl_instant_for_integer {
($i:ty) => {
impl<Numer, Denom: NonZero> Instant<$i, Numer, Denom> {
#[doc = concat!("let i = Instant::<", stringify!($i), ", typenum::U1, typenum::U1000>::from_ticks(234);")]
#[inline]
pub const fn ticks(&self) -> $i {
self.since_start.ticks
}
}
impl<Numer: Unsigned, Denom: Unsigned + NonZero> Instant<$i, Numer, Denom> {
#[doc = concat!("let _i = Instant::<", stringify!($i), ", typenum::U1, typenum::U1000>::from_ticks(1);")]
#[inline]
pub const fn from_ticks(ticks: $i) -> Self {
Self { since_start: Duration { ticks, _period: Period{_numer: PhantomData, _denom: PhantomData} }}
}
#[doc = concat!("let i1 = Instant::<", stringify!($i), ", typenum::U1, typenum::U1000>::from_ticks(1);")]
#[doc = concat!("let i2 = Instant::<", stringify!($i), ", typenum::U1, typenum::U1000>::from_ticks(2);")]
#[doc = concat!("let i1 = Instant::<", stringify!($i), ", typenum::U1, typenum::U1000>::from_ticks(", stringify!($i),"::MAX);")]
#[doc = concat!("let i2 = Instant::<", stringify!($i), ", typenum::U1, typenum::U1000>::from_ticks(1);")]
#[inline]
pub const fn const_cmp(self, other: Self) -> Ordering {
if self.since_start.ticks == other.since_start.ticks {
Ordering::Equal
} else {
let v = self.since_start.ticks.wrapping_sub(other.since_start.ticks);
if v > <$i>::MAX / 2 {
Ordering::Less
} else if v < <$i>::MAX / 2 {
Ordering::Greater
} else {
Ordering::Equal
}
}
}
#[doc = concat!("let i = Instant::<", stringify!($i), ", typenum::U1, typenum::U1000>::from_ticks(11);")]
#[inline]
pub const fn duration_since_epoch(self) -> Duration<$i, Numer, Denom> {
Duration::<$i, Numer, Denom>::from_ticks(self.ticks())
}
#[doc = concat!("let i1 = Instant::<", stringify!($i), ", typenum::U1, typenum::U1000>::from_ticks(1);")]
#[doc = concat!("let i2 = Instant::<", stringify!($i), ", typenum::U1, typenum::U1000>::from_ticks(2);")]
#[inline]
pub const fn checked_duration_since(
self,
other: Self,
) -> Option<Duration<$i, Numer, Denom>> {
match self.const_cmp(other) {
Ordering::Greater | Ordering::Equal => {
Some(Duration::<$i, Numer, Denom>::from_ticks(
self.since_start.ticks.wrapping_sub(other.since_start.ticks),
))
}
Ordering::Less => None,
}
}
#[doc = concat!("let i = Instant::<", stringify!($i), ", typenum::U1, typenum::U1000>::from_ticks(1);")]
#[doc = concat!("let d = Duration::<", stringify!($i), ", typenum::U1, typenum::U1000>::from_ticks(1);")]
pub const fn checked_sub_duration<ONumer: Unsigned, ODenom: Unsigned + NonZero>(
self,
other: Duration<$i, ONumer, ODenom>,
) -> Option<Self> {
if Helpers::<Numer, Denom, ONumer, ODenom>::SAME_BASE {
Some(Instant::<$i, Numer, Denom>::from_ticks(
self.since_start.ticks.wrapping_sub(other.ticks()),
))
} else {
if let Some(lh) = other
.ticks()
.checked_mul(Helpers::<Numer, Denom, ONumer, ODenom>::LD_TIMES_RN as $i)
{
let ticks = lh / Helpers::<Numer, Denom, ONumer, ODenom>::RD_TIMES_LN as $i;
Some(Instant::<$i, Numer, Denom>::from_ticks(
self.since_start.ticks.wrapping_sub(ticks),
))
} else {
None
}
}
}
#[doc = concat!("let i = Instant::<", stringify!($i), ", typenum::U1, typenum::U1000>::from_ticks(1);")]
#[doc = concat!("let d = Duration::<", stringify!($i), ", typenum::U1, typenum::U1000>::from_ticks(1);")]
pub const fn checked_add_duration<ONumer: Unsigned, ODenom: Unsigned + NonZero>(
self,
other: Duration<$i, ONumer, ODenom>,
) -> Option<Self> {
if Helpers::<Numer, Denom, ONumer, ODenom>::SAME_BASE {
Some(Instant::<$i, Numer, Denom>::from_ticks(
self.since_start.ticks.wrapping_add(other.ticks()),
))
} else {
if let Some(lh) = other
.ticks()
.checked_mul(Helpers::<Numer, Denom, ONumer, ODenom>::LD_TIMES_RN as $i)
{
let ticks = lh / Helpers::<Numer, Denom, ONumer, ODenom>::RD_TIMES_LN as $i;
Some(Instant::<$i, Numer, Denom>::from_ticks(
self.since_start.ticks.wrapping_add(ticks),
))
} else {
None
}
}
}
}
impl<Numer:Unsigned, Denom: Unsigned + NonZero> PartialOrd for Instant<$i, Numer, Denom> {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.const_cmp(*other))
}
}
impl<Numer:Unsigned, Denom: Unsigned + NonZero> Ord for Instant<$i, Numer, Denom> {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
self.const_cmp(*other)
}
}
impl<Numer:Unsigned, Denom: Unsigned + NonZero> PartialEq for Instant<$i, Numer, Denom> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.since_start.ticks.eq(&other.since_start.ticks)
}
}
impl<Numer:Unsigned, Denom: Unsigned + NonZero> Eq for Instant<$i, Numer, Denom> {}
impl<Numer:Unsigned, Denom: Unsigned + NonZero> ops::Sub<Instant<$i, Numer, Denom>>
for Instant<$i, Numer, Denom>
{
type Output = Duration<$i, Numer, Denom>;
#[inline]
fn sub(self, other: Self) -> Self::Output {
if let Some(v) = self.checked_duration_since(other) {
v
} else {
panic!("Sub failed! Other > self");
}
}
}
impl<Numer:Unsigned, Denom: Unsigned + NonZero> ops::Sub<Duration<$i, Numer, Denom>>
for Instant<$i, Numer, Denom>
{
type Output = Instant<$i, Numer, Denom>;
#[inline]
fn sub(self, other: Duration<$i, Numer, Denom>) -> Self::Output {
if let Some(v) = self.checked_sub_duration(other) {
v
} else {
panic!("Sub failed! Overflow");
}
}
}
impl<Numer:Unsigned, Denom: Unsigned + NonZero> ops::SubAssign<Duration<$i, Numer, Denom>>
for Instant<$i, Numer, Denom>
{
#[inline]
fn sub_assign(&mut self, other: Duration<$i, Numer, Denom>) {
*self = *self - other;
}
}
impl<Numer:Unsigned, Denom: Unsigned + NonZero> ops::Add<Duration<$i, Numer, Denom>>
for Instant<$i, Numer, Denom>
{
type Output = Instant<$i, Numer, Denom>;
#[inline]
fn add(self, other: Duration<$i, Numer, Denom>) -> Self::Output {
if let Some(v) = self.checked_add_duration(other) {
v
} else {
panic!("Add failed! Overflow");
}
}
}
impl<Numer:Unsigned, Denom: Unsigned + NonZero> ops::AddAssign<Duration<$i, Numer, Denom>>
for Instant<$i, Numer, Denom>
{
#[inline]
fn add_assign(&mut self, other: Duration<$i, Numer, Denom>) {
*self = *self + other;
}
}
#[cfg(feature = "defmt")]
impl<Numer:Unsigned, Denom: Unsigned + NonZero> defmt::Format for Instant<$i, Numer, Denom> {
fn format(&self, f: defmt::Formatter) {
if Numer == 3_600 && Denom == 1 {
defmt::write!(f, "{} h", self.since_start.ticks)
} else if Numer == 60 && Denom == 1 {
defmt::write!(f, "{} min", self.since_start.ticks)
} else if Numer == 1 && Denom == 1 {
defmt::write!(f, "{} s", self.since_start.ticks)
} else if Numer == 1 && Denom == 1_000 {
defmt::write!(f, "{} ms", self.since_start.ticks)
} else if Numer == 1 && Denom == 1_000_000 {
defmt::write!(f, "{} us", self.since_start.ticks)
} else if Numer == 1 && Denom == 1_000_000_000 {
defmt::write!(f, "{} ns", self.since_start.ticks)
} else {
defmt::write!(f, "{} ticks @ ({}/{})", self.since_start.ticks, Numer, Denom)
}
}
}
impl<Numer:Unsigned, Denom: Unsigned + NonZero> core::fmt::Display for Instant<$i, Numer, Denom> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
if Numer::U64 == 3_600 && Denom::U64 == 1 {
write!(f, "{} h", self.since_start.ticks)
} else if Numer::U64 == 60 && Denom::U64 == 1 {
write!(f, "{} min", self.since_start.ticks)
} else if Numer::U64 == 1 && Denom::U64 == 1 {
write!(f, "{} s", self.since_start.ticks)
} else if Numer::U64 == 1 && Denom::U64 == 1_000 {
write!(f, "{} ms", self.since_start.ticks)
} else if Numer::U64 == 1 && Denom::U64 == 1_000_000 {
write!(f, "{} μs", self.since_start.ticks)
} else if Numer::U64 == 1 && Denom::U64 == 1_000_000_000 {
write!(f, "{} ns", self.since_start.ticks)
} else {
write!(f, "{} ticks @ ({}/{})", self.since_start.ticks, Numer::U64, Denom::U64)
}
}
}
};
}
impl_instant_for_integer!(u32);
impl_instant_for_integer!(u64);
impl<Numer: Unsigned, Denom: Unsigned + NonZero> ops::Sub<Duration<u32, Numer, Denom>>
for Instant<u64, Numer, Denom>
{
type Output = Instant<u64, Numer, Denom>;
#[inline]
fn sub(self, other: Duration<u32, Numer, Denom>) -> Self::Output {
if let Some(v) = self.checked_sub_duration(other.into()) {
v
} else {
panic!("Sub failed! Overflow");
}
}
}
impl<Numer: Unsigned, Denom: Unsigned + NonZero> ops::SubAssign<Duration<u32, Numer, Denom>>
for Instant<u64, Numer, Denom>
{
#[inline]
fn sub_assign(&mut self, other: Duration<u32, Numer, Denom>) {
*self = *self - other;
}
}
impl<Numer: Unsigned, Denom: Unsigned + NonZero> ops::Add<Duration<u32, Numer, Denom>>
for Instant<u64, Numer, Denom>
{
type Output = Instant<u64, Numer, Denom>;
#[inline]
fn add(self, other: Duration<u32, Numer, Denom>) -> Self::Output {
if let Some(v) = self.checked_add_duration(other.into()) {
v
} else {
panic!("Add failed! Overflow");
}
}
}
impl<Numer: Unsigned, Denom: Unsigned + NonZero> ops::AddAssign<Duration<u32, Numer, Denom>>
for Instant<u64, Numer, Denom>
{
#[inline]
fn add_assign(&mut self, other: Duration<u32, Numer, Denom>) {
*self = *self + other;
}
}