use core::fmt;
use core::ops::{Add, AddAssign, Sub, SubAssign};
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Duration(u32);
impl Duration {
pub const T_IFS: Self = Duration(150);
pub fn from_micros(micros: u32) -> Self {
Duration(micros)
}
pub fn from_millis(millis: u16) -> Self {
Duration(u32::from(millis) * 1_000)
}
pub fn from_secs(secs: u16) -> Self {
Duration(u32::from(secs) * 1_000_000)
}
pub fn whole_secs(&self) -> u32 {
self.0 / 1_000_000
}
pub fn whole_millis(&self) -> u32 {
self.0 / 1_000
}
pub fn as_micros(&self) -> u32 {
self.0
}
pub fn subsec_micros(&self) -> u32 {
self.0 % 1_000_000
}
}
impl Add for Duration {
type Output = Self;
fn add(self, rhs: Self) -> Self {
Duration(self.0.checked_add(rhs.0).expect("duration overflow"))
}
}
impl Add<&'_ Self> for Duration {
type Output = Duration;
fn add(self, rhs: &'_ Self) -> Self {
self + *rhs
}
}
impl AddAssign for Duration {
fn add_assign(&mut self, rhs: Self) {
*self = *self + rhs;
}
}
impl Sub for Duration {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
Duration(self.0.checked_sub(rhs.0).expect("duration underflow"))
}
}
impl Sub<&'_ Self> for Duration {
type Output = Self;
fn sub(self, rhs: &'_ Self) -> Self {
self - *rhs
}
}
impl SubAssign for Duration {
fn sub_assign(&mut self, rhs: Self) {
*self = *self - rhs;
}
}
impl fmt::Display for Duration {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.0 >= 1_000_000 {
let (secs, subsec_micros) = (self.whole_secs(), self.subsec_micros());
if subsec_micros == 0 {
write!(f, "{}s", secs)
} else {
write!(f, "{}.{:06}s", secs, subsec_micros)
}
} else if self.0 >= 1000 {
let (millis, submilli_micros) = (self.whole_millis(), self.0 % 1000);
if submilli_micros == 0 {
write!(f, "{}ms", millis)
} else {
write!(f, "{}.{:03}ms", millis, submilli_micros)
}
} else {
write!(f, "{}µs", self.0)
}
}
}
impl fmt::Debug for Duration {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<Self as fmt::Display>::fmt(self, f)
}
}
#[derive(Copy, Clone)]
pub struct Instant(u32);
impl Instant {
pub const MAX_TIME_BETWEEN: Duration = Duration(1_000_000 * 60 * 5);
pub fn from_raw_micros(micros: u32) -> Self {
Instant(micros)
}
pub fn raw_micros(&self) -> u32 {
self.0
}
pub fn duration_since(&self, earlier: Instant) -> Duration {
let micros_passed = self.0.wrapping_sub(earlier.0);
debug_assert!(
micros_passed <= Self::MAX_TIME_BETWEEN.0,
"{}µs between instants {} and {}",
micros_passed,
earlier,
self
);
Duration(micros_passed)
}
}
impl Sub<Instant> for Instant {
type Output = Duration;
fn sub(self, rhs: Self) -> Duration {
self.duration_since(rhs)
}
}
impl Add<Duration> for Instant {
type Output = Self;
fn add(self, d: Duration) -> Self {
Instant(self.0.wrapping_add(d.as_micros()))
}
}
impl AddAssign<Duration> for Instant {
fn add_assign(&mut self, d: Duration) {
*self = *self + d;
}
}
impl Sub<Duration> for Instant {
type Output = Self;
fn sub(self, d: Duration) -> Self {
Instant(self.0.wrapping_sub(d.as_micros()))
}
}
impl SubAssign<Duration> for Instant {
fn sub_assign(&mut self, d: Duration) {
*self = *self - d;
}
}
impl fmt::Display for Instant {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.0 >= 1_000_000 {
let (secs, subsec_micros) = (self.0 / 1_000_000, self.0 % 1_000_000);
if subsec_micros == 0 {
write!(f, "{}s", secs)
} else {
write!(f, "{}.{:06}s", secs, subsec_micros)
}
} else if self.0 >= 1000 {
let (millis, submilli_micros) = (self.0 / 1000, self.0 % 1000);
if submilli_micros == 0 {
write!(f, "{}ms", millis)
} else {
write!(f, "{}.{:03}ms", millis, submilli_micros)
}
} else {
write!(f, "{}µs", self.0)
}
}
}
impl fmt::Debug for Instant {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<Self as fmt::Display>::fmt(self, f)
}
}
pub trait Timer {
fn now(&self) -> Instant;
}