use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, Sub, SubAssign};
#[repr(transparent)]
#[derive(Copy, Clone, Default, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Duration {
pub(crate) ns: u64,
}
impl Duration {
pub const MAX: Duration = Duration { ns: u64::MAX };
pub const ZERO: Duration = Duration { ns: 0 };
pub const SECOND: Duration = Duration::from_nanos(1_000_000_000);
pub const MILLISECOND: Duration = Duration::from_nanos(1_000_000);
pub const MICROSECOND: Duration = Duration::from_nanos(1_000);
pub const NANOSECOND: Duration = Duration::from_nanos(1);
pub const fn from_secs(secs: u32) -> Self {
Self {
ns: secs as u64 * Self::SECOND.as_nanos(),
}
}
pub const fn from_millis(millis: u32) -> Self {
Self {
ns: millis as u64 * Self::MILLISECOND.as_nanos(),
}
}
pub const fn try_from_millis(millis: u64) -> Result<Self, TryFromError> {
if let Some(ns) = millis.checked_mul(Self::MILLISECOND.as_nanos()) {
Ok(Self { ns })
} else {
Err(TryFromError {
kind: TryFromErrorKind::Overflow,
})
}
}
pub const fn from_micros(micros: u32) -> Self {
Self {
ns: micros as u64 * Self::MICROSECOND.as_nanos(),
}
}
pub const fn try_from_micros(micros: u64) -> Result<Self, TryFromError> {
if let Some(ns) = micros.checked_mul(Self::MICROSECOND.as_nanos()) {
Ok(Self { ns })
} else {
Err(TryFromError {
kind: TryFromErrorKind::Overflow,
})
}
}
pub const fn try_from_secs(secs: u64) -> Result<Self, TryFromError> {
match secs.checked_mul(Self::SECOND.as_nanos()) {
Some(ns) => Ok(Duration { ns }),
None => Err(TryFromError {
kind: TryFromErrorKind::Overflow,
}),
}
}
pub const fn from_nanos(nanos: u64) -> Self {
Self { ns: nanos }
}
pub const fn as_nanos(&self) -> u64 {
self.ns
}
pub const fn as_micros(&self) -> u64 {
self.ns / Self::MICROSECOND.as_nanos()
}
pub const fn as_millis(&self) -> u64 {
self.ns / Self::MILLISECOND.as_nanos()
}
pub const fn as_secs(&self) -> u64 {
self.ns / Self::SECOND.as_nanos()
}
pub const fn subsec_nanos(&self) -> u32 {
(self.ns % Self::SECOND.as_nanos()) as u32
}
pub const fn as_secs_f64(&self) -> f64 {
self.as_secs() as f64 + self.subsec_nanos() as f64 / 1e9
}
pub fn mul_f64(self, rhs: f64) -> Self {
Self {
ns: (self.ns as f64 * rhs) as u64,
}
}
}
impl Add<Duration> for Duration {
type Output = Duration;
fn add(self, rhs: Duration) -> Self::Output {
Duration {
ns: self.ns + rhs.ns,
}
}
}
impl AddAssign<Duration> for Duration {
fn add_assign(&mut self, rhs: Duration) {
self.ns += rhs.ns;
}
}
impl Sub<Duration> for Duration {
type Output = Duration;
fn sub(self, rhs: Duration) -> Self::Output {
Duration {
ns: self.ns - rhs.ns,
}
}
}
impl SubAssign<Duration> for Duration {
fn sub_assign(&mut self, rhs: Duration) {
self.ns -= rhs.ns;
}
}
impl Mul<u64> for Duration {
type Output = Duration;
fn mul(self, rhs: u64) -> Self::Output {
Duration { ns: self.ns * rhs }
}
}
impl MulAssign<u64> for Duration {
fn mul_assign(&mut self, rhs: u64) {
self.ns *= rhs
}
}
impl Div<u64> for Duration {
type Output = Duration;
fn div(self, rhs: u64) -> Self::Output {
Duration { ns: self.ns / rhs }
}
}
impl DivAssign<u64> for Duration {
fn div_assign(&mut self, rhs: u64) {
self.ns /= rhs
}
}
impl Rem<Duration> for Duration {
type Output = Duration;
fn rem(self, rhs: Duration) -> Self::Output {
Duration {
ns: self.ns % rhs.ns,
}
}
}
impl From<crate::coarse::Duration> for Duration {
fn from(other: crate::coarse::Duration) -> Self {
Self::from_secs(other.as_secs())
}
}
#[derive(Debug)]
pub struct TryFromError {
kind: TryFromErrorKind,
}
#[derive(Debug)]
enum TryFromErrorKind {
Overflow,
}
impl TryFromError {
const fn description(&self) -> &'static str {
match self.kind {
TryFromErrorKind::Overflow => "can not convert to Duration: value is too big",
}
}
}
impl core::fmt::Display for TryFromError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.description().fmt(f)
}
}
impl std::error::Error for TryFromError {}
impl TryFrom<core::time::Duration> for Duration {
type Error = TryFromError;
fn try_from(other: core::time::Duration) -> Result<Self, Self::Error> {
if other.as_nanos() > u64::MAX as u128 {
Err(TryFromError {
kind: TryFromErrorKind::Overflow,
})
} else {
Ok(Self::from_nanos(other.as_nanos() as u64))
}
}
}