use core::fmt;
use core::num::TryFromIntError;
use core::ops::{Add, Div, Mul, Sub};
#[derive(
Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize,
)]
pub struct Duration {
micros: u64,
}
impl Duration {
pub const MAX: Duration = Duration { micros: u64::MAX };
pub const ZERO: Duration = Duration { micros: 0 };
const MICROS_PER_SECOND: u64 = 1_000_000;
const MILLIS_PER_SECOND: u64 = 1_000;
pub const fn from_secs(secs: u64) -> Duration {
Duration {
micros: secs * Self::MICROS_PER_SECOND,
}
}
pub const fn from_millis(millis: u64) -> Duration {
Duration {
micros: millis * Self::MILLIS_PER_SECOND,
}
}
pub const fn from_micros(micros: u64) -> Duration {
Duration { micros }
}
pub const fn as_secs(&self) -> u64 {
self.micros / Self::MICROS_PER_SECOND
}
pub const fn as_millis(&self) -> u64 {
self.micros / Self::MILLIS_PER_SECOND
}
pub const fn as_micros(&self) -> u64 {
self.micros
}
pub fn checked_add(self, rhs: Duration) -> Option<Duration> {
self.micros
.checked_add(rhs.micros)
.map(|micros| Duration { micros })
}
pub fn checked_sub(self, rhs: Duration) -> Option<Duration> {
self.micros
.checked_sub(rhs.micros)
.map(|micros| Duration { micros })
}
pub fn checked_mul(self, rhs: u32) -> Option<Duration> {
self.micros
.checked_mul(rhs as _)
.map(|micros| Duration { micros })
}
pub fn checked_div(self, rhs: u32) -> Option<Duration> {
self.micros
.checked_div(rhs as _)
.map(|micros| Duration { micros })
}
pub fn abs_diff(self, rhs: Self) -> Duration {
Self {
micros: self.micros.abs_diff(rhs.micros),
}
}
pub(crate) fn max_no_overflow_alias() -> Self {
Self::from_secs(60 * 60 * 24 * 7 * 52 * 50)
}
}
impl Add for Duration {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
let Some(result) = self.checked_add(rhs) else {
panic!("overflow when adding two durations");
};
result
}
}
impl Sub for Duration {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
let Some(result) = self.checked_sub(rhs) else {
panic!("underflow when subtracting two durations");
};
result
}
}
impl Mul<u32> for Duration {
type Output = Self;
fn mul(self, rhs: u32) -> Self::Output {
let Some(result) = self.checked_mul(rhs) else {
panic!("overflow when multiplying a duration by a scalar");
};
result
}
}
impl Mul<Duration> for u32 {
type Output = Duration;
fn mul(self, rhs: Duration) -> Self::Output {
rhs * self
}
}
impl Div<u32> for Duration {
type Output = Self;
fn div(self, rhs: u32) -> Self::Output {
let Some(result) = self.checked_div(rhs) else {
panic!("divided a duration by zero");
};
result
}
}
impl fmt::Debug for Duration {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}s.{}us",
self.as_secs(),
self.as_micros() % Self::MICROS_PER_SECOND
)
}
}
impl TryFrom<core::time::Duration> for Duration {
type Error = TryFromIntError;
fn try_from(value: core::time::Duration) -> Result<Self, Self::Error> {
value.as_micros().try_into().map(Self::from_micros)
}
}
impl From<Duration> for core::time::Duration {
fn from(value: Duration) -> Self {
Self::from_micros(value.as_micros())
}
}