use core::ops::{Add, AddAssign, Sub, SubAssign};
use crate::divide::div_rem;
use crate::{NANOS_PER_MICRO, NANOS_PER_MILLI, NANOS_PER_SEC};
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Duration(u64);
impl Duration {
pub const ZERO: Self = Self(0);
pub const MAX: Self = Self(u64::MAX);
#[must_use]
pub const fn from_nanos(nanos: u64) -> Self {
Self(nanos)
}
#[must_use]
pub const fn from_micros(micros: u64) -> Self {
Self(micros.saturating_mul(NANOS_PER_MICRO))
}
#[must_use]
pub const fn from_millis(millis: u64) -> Self {
Self(millis.saturating_mul(NANOS_PER_MILLI))
}
#[must_use]
pub const fn from_secs(secs: u64) -> Self {
Self(secs.saturating_mul(NANOS_PER_SEC))
}
#[must_use]
pub const fn try_from_micros(micros: u64) -> Option<Self> {
match micros.checked_mul(NANOS_PER_MICRO) {
Some(nanos) => Some(Self(nanos)),
None => None,
}
}
#[must_use]
pub const fn try_from_millis(millis: u64) -> Option<Self> {
match millis.checked_mul(NANOS_PER_MILLI) {
Some(nanos) => Some(Self(nanos)),
None => None,
}
}
#[must_use]
pub const fn try_from_secs(secs: u64) -> Option<Self> {
match secs.checked_mul(NANOS_PER_SEC) {
Some(nanos) => Some(Self(nanos)),
None => None,
}
}
#[must_use]
pub const fn as_nanos(self) -> u64 {
self.0
}
#[must_use]
pub const fn is_zero(self) -> bool {
self.0 == 0
}
#[must_use]
pub const fn as_micros(self) -> u64 {
div_rem(self.0, NANOS_PER_MICRO).0
}
#[must_use]
pub const fn as_millis(self) -> u64 {
div_rem(self.0, NANOS_PER_MILLI).0
}
#[must_use]
pub const fn as_secs(self) -> u64 {
div_rem(self.0, NANOS_PER_SEC).0
}
#[must_use]
pub const fn checked_add(self, other: Self) -> Option<Self> {
match self.0.checked_add(other.0) {
Some(nanos) => Some(Self(nanos)),
None => None,
}
}
#[must_use]
pub const fn saturating_add(self, other: Self) -> Self {
Self(self.0.saturating_add(other.0))
}
#[must_use]
pub const fn checked_sub(self, other: Self) -> Option<Self> {
match self.0.checked_sub(other.0) {
Some(nanos) => Some(Self(nanos)),
None => None,
}
}
#[must_use]
pub const fn saturating_sub(self, other: Self) -> Self {
Self(self.0.saturating_sub(other.0))
}
#[must_use]
pub const fn checked_mul(self, factor: u32) -> Option<Self> {
match self.0.checked_mul(factor as u64) {
Some(nanos) => Some(Self(nanos)),
None => None,
}
}
#[must_use]
pub const fn saturating_mul(self, factor: u32) -> Self {
Self(self.0.saturating_mul(factor as u64))
}
#[must_use]
pub const fn min(self, other: Self) -> Self {
if self.0 <= other.0 {
self
} else {
other
}
}
#[must_use]
pub const fn max(self, other: Self) -> Self {
if self.0 >= other.0 {
self
} else {
other
}
}
#[must_use]
pub const fn checked_rem(self, divisor: Self) -> Option<Self> {
if divisor.0 == 0 {
None
} else {
Some(Self(div_rem(self.0, divisor.0).1))
}
}
}
impl Add for Duration {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self.saturating_add(rhs)
}
}
impl AddAssign for Duration {
fn add_assign(&mut self, rhs: Self) {
*self = self.saturating_add(rhs);
}
}
impl Sub for Duration {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
self.saturating_sub(rhs)
}
}
impl SubAssign for Duration {
fn sub_assign(&mut self, rhs: Self) {
*self = self.saturating_sub(rhs);
}
}