use core::time::Duration;
use core::any::Any;
use core::borrow::{Borrow, BorrowMut};
use core::fmt::Debug;
use core::hash::Hash;
use core::ops::{Add, AddAssign, Sub, SubAssign};
use core::panic::{RefUnwindSafe, UnwindSafe};
use core::convert::TryInto;
pub trait Instant:
Sized
+ Add<Duration, Output=Self>
+ AddAssign<Duration>
+ Clone
+ Copy
+ Debug
+ Eq
+ Hash
+ Ord
+ PartialEq<Self>
+ PartialOrd<Self>
+ Sub<Duration, Output=Self>
+ Sub<Self, Output=Duration>
+ SubAssign<Duration>
+ RefUnwindSafe
+ Send
+ Sync
+ Unpin
+ UnwindSafe
+ Any
+ Borrow<Self>
+ BorrowMut<Self>
+ From<Self>
{
#[must_use]
fn duration_since(&self, earlier: Self) -> Duration {
self.checked_duration_since(earlier).unwrap_or_default()
}
#[must_use]
fn checked_duration_since(&self, earlier: Self) -> Option<Duration>;
#[must_use]
fn saturating_duration_since(&self, earlier: Self) -> Duration {
self.checked_duration_since(earlier).unwrap_or_default()
}
fn checked_add(&self, duration: Duration) -> Option<Self>;
fn checked_sub(&self, duration: Duration) -> Option<Self>;
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct TimespecInstant {
secs: u32,
nanos: u32,
}
impl TimespecInstant {
pub fn new(secs: u32, nanos: u32) -> Self {
Self { secs, nanos }
}
}
impl Instant for TimespecInstant {
fn checked_duration_since(&self, earlier: Self) -> Option<Duration> {
let slf = Duration::new(self.secs as u64, self.nanos);
let early = Duration::new(earlier.secs as u64, earlier.nanos);
slf.checked_sub(early)
}
fn checked_add(&self, duration: Duration) -> Option<Self> {
let sum = Duration::new(self.secs as u64, self.nanos).checked_add(duration)?;
Some(TimespecInstant {
secs: sum.as_secs().try_into().ok()?,
nanos: sum.subsec_nanos(),
})
}
fn checked_sub(&self, duration: Duration) -> Option<Self> {
let diff = Duration::new(self.secs as u64, self.nanos).checked_add(duration)?;
Some(TimespecInstant {
secs: diff.as_secs().try_into().ok()?,
nanos: diff.subsec_nanos(),
})
}
}
impl core::ops::Add<Duration> for TimespecInstant {
type Output = TimespecInstant;
fn add(self, other: Duration) -> TimespecInstant {
self.checked_add(other)
.expect("overflow when adding duration to instant")
}
}
impl core::ops::AddAssign<Duration> for TimespecInstant {
fn add_assign(&mut self, other: Duration) {
*self = *self + other;
}
}
impl core::ops::Sub<Duration> for TimespecInstant {
type Output = TimespecInstant;
fn sub(self, other: Duration) -> TimespecInstant {
self.checked_sub(other)
.expect("overflow when subtracting duration from instant")
}
}
impl core::ops::SubAssign<Duration> for TimespecInstant {
fn sub_assign(&mut self, other: Duration) {
*self = *self - other;
}
}
impl core::ops::Sub<TimespecInstant> for TimespecInstant {
type Output = Duration;
fn sub(self, other: TimespecInstant) -> Duration {
self.duration_since(other)
}
}
macro_rules! impl_instant {
($instant_name:ident, $primitive_type:ident) => {
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct $instant_name<const TICKS_PER_SEC: u32> {
ticks: $primitive_type,
}
impl<const TICKS_PER_SEC: u32> $instant_name<TICKS_PER_SEC> {
pub fn new(ticks: $primitive_type) -> Self {
Self { ticks }
}
}
impl<const TICKS_PER_SEC: u32> Instant for $instant_name<TICKS_PER_SEC> {
fn checked_duration_since(&self, earlier: Self) -> Option<Duration> {
let ticks: $primitive_type = self.ticks.checked_sub(earlier.ticks)?;
let secs: $primitive_type = ticks / TICKS_PER_SEC as $primitive_type;
let remaining: $primitive_type = ticks % TICKS_PER_SEC as $primitive_type;
let remaining: u32 = remaining
.try_into()
.expect("more than u32::MAX subsec ticks");
let nanos_per_tick: u32 = 1_000_000_000 / TICKS_PER_SEC;
let nanos = remaining * nanos_per_tick;
Some(Duration::new(secs.into(), nanos))
}
fn checked_add(&self, duration: Duration) -> Option<Self> {
let mut ticks: $primitive_type = self.ticks;
let secs: $primitive_type = duration.as_secs().try_into().ok()?;
let sec_ticks = secs.checked_mul(TICKS_PER_SEC.into())?;
ticks = ticks.checked_add(sec_ticks)?;
let nanos: u32 = duration.subsec_nanos();
let nanos_per_tick: u32 = 1_000_000_000 / TICKS_PER_SEC;
let nano_ticks: u32 = nanos / nanos_per_tick;
ticks = ticks.checked_add(nano_ticks.into())?;
Some($instant_name { ticks })
}
fn checked_sub(&self, duration: Duration) -> Option<Self> {
let mut ticks: $primitive_type = self.ticks;
let secs: $primitive_type = duration.as_secs().try_into().ok()?;
let sec_ticks = secs.checked_mul(TICKS_PER_SEC.into())?;
ticks = ticks.checked_sub(sec_ticks)?;
let nanos: u32 = duration.subsec_nanos();
let nanos_per_tick: u32 = 1_000_000_000 / TICKS_PER_SEC;
let nano_ticks: u32 = nanos / nanos_per_tick;
ticks = ticks.checked_sub(nano_ticks.into())?;
Some($instant_name { ticks })
}
}
impl<const TICKS_PER_SEC: u32> core::ops::Add<Duration> for $instant_name<TICKS_PER_SEC> {
type Output = $instant_name<TICKS_PER_SEC>;
fn add(self, other: Duration) -> $instant_name<TICKS_PER_SEC> {
self.checked_add(other)
.expect("overflow when adding duration to instant")
}
}
impl<const TICKS_PER_SEC: u32> core::ops::AddAssign<Duration>
for $instant_name<TICKS_PER_SEC>
{
fn add_assign(&mut self, other: Duration) {
*self = *self + other;
}
}
impl<const TICKS_PER_SEC: u32> core::ops::Sub<Duration> for $instant_name<TICKS_PER_SEC> {
type Output = $instant_name<TICKS_PER_SEC>;
fn sub(self, other: Duration) -> $instant_name<TICKS_PER_SEC> {
self.checked_sub(other)
.expect("overflow when subtracting duration from instant")
}
}
impl<const TICKS_PER_SEC: u32> core::ops::SubAssign<Duration>
for $instant_name<TICKS_PER_SEC>
{
fn sub_assign(&mut self, other: Duration) {
*self = *self - other;
}
}
impl<const TICKS_PER_SEC: u32> core::ops::Sub<$instant_name<TICKS_PER_SEC>>
for $instant_name<TICKS_PER_SEC>
{
type Output = Duration;
fn sub(self, other: $instant_name<TICKS_PER_SEC>) -> Duration {
self.duration_since(other)
}
}
};
}
impl_instant!(Instant32, u32);
impl_instant!(Instant64, u64);
#[cfg(feature = "std")]
impl Instant for std::time::Instant {
fn checked_duration_since(&self, earlier: Self) -> Option<Duration> {
self.checked_duration_since(earlier)
}
fn checked_add(&self, duration: Duration) -> Option<Self> {
self.checked_add(duration)
}
fn checked_sub(&self, duration: Duration) -> Option<Self> {
self.checked_sub(duration)
}
}