use core::{
fmt::{self, Debug, Display},
ops::{Add, AddAssign, Sub, SubAssign},
};
#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Duration {
nanos: i128,
}
const NANOS_IN_MICROS: i128 = 1000;
const NANOS_IN_MILLIS: i128 = NANOS_IN_MICROS * 1000;
const NANOS_IN_SECS: i128 = NANOS_IN_MILLIS * 1000;
const NANOS_IN_MINS: i128 = NANOS_IN_SECS * 60;
const NANOS_IN_HOURS: i128 = NANOS_IN_MINS * 60;
const NANOS_IN_DAYS: i128 = NANOS_IN_HOURS * 24;
const NANOS_IN_WEEKS: i128 = NANOS_IN_DAYS * 7;
impl Duration {
pub const ZERO: Duration = Duration { nanos: 0 };
pub const fn from_nanos(nanos: i128) -> Duration {
Duration { nanos }
}
pub const fn from_micros(micros: i64) -> Duration {
Duration {
nanos: micros as i128 * NANOS_IN_MICROS,
}
}
pub const fn from_millis(millis: i64) -> Duration {
Duration {
nanos: millis as i128 * NANOS_IN_MILLIS,
}
}
pub const fn from_secs(secs: i64) -> Duration {
Duration {
nanos: secs as i128 * NANOS_IN_SECS,
}
}
pub const fn from_minutes(mins: i64) -> Duration {
Duration {
nanos: mins as i128 * NANOS_IN_MINS,
}
}
pub const fn from_hours(hours: i64) -> Duration {
Duration {
nanos: hours as i128 * NANOS_IN_HOURS,
}
}
pub const fn from_days(days: i64) -> Duration {
Duration {
nanos: days as i128 * NANOS_IN_DAYS,
}
}
pub const fn from_weeks(weeks: i64) -> Duration {
Duration {
nanos: weeks as i128 * NANOS_IN_WEEKS,
}
}
pub const fn nanos(&self) -> i128 {
self.nanos
}
pub const fn micros(&self) -> i128 {
self.nanos / NANOS_IN_MICROS
}
pub const fn millis(&self) -> i128 {
self.nanos / NANOS_IN_MILLIS
}
pub const fn secs(&self) -> i128 {
self.nanos / NANOS_IN_SECS
}
pub const fn mins(&self) -> i128 {
self.nanos / NANOS_IN_MINS
}
pub const fn hours(&self) -> i128 {
self.nanos / NANOS_IN_HOURS
}
pub const fn days(&self) -> i128 {
self.nanos / NANOS_IN_DAYS
}
pub const fn weeks(&self) -> i128 {
self.nanos / NANOS_IN_WEEKS
}
pub fn checked_add(&self, rhs: &Duration) -> Option<Self> {
self.nanos
.checked_add(rhs.nanos)
.map(|nanos| Duration { nanos })
}
pub fn checked_sub(&self, rhs: &Duration) -> Option<Self> {
self.nanos
.checked_sub(rhs.nanos)
.map(|nanos| Duration { nanos })
}
}
impl Add<Duration> for Duration {
type Output = Duration;
fn add(self, rhs: Self) -> Self::Output {
self.checked_add(&rhs)
.expect("overflow while adding durations")
}
}
impl AddAssign<Duration> for Duration {
fn add_assign(&mut self, rhs: Duration) {
*self = *self + rhs
}
}
impl Sub<Duration> for Duration {
type Output = Duration;
fn sub(self, rhs: Duration) -> Self::Output {
self.checked_sub(&rhs)
.expect("overflow while subtracting durations")
}
}
impl SubAssign<Duration> for Duration {
fn sub_assign(&mut self, rhs: Duration) {
*self = *self - rhs
}
}
impl Default for Duration {
fn default() -> Self {
Duration::ZERO
}
}
impl Debug for Duration {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<Duration as Display>::fmt(self, f)
}
}
impl Display for Duration {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.nanos % NANOS_IN_HOURS == 0 {
write!(f, "{}h", self.nanos / NANOS_IN_HOURS)
} else if self.nanos % NANOS_IN_MINS == 0 {
write!(f, "{}min", self.nanos / NANOS_IN_MINS)
} else if self.nanos % NANOS_IN_SECS == 0 {
write!(f, "{}s", self.nanos / NANOS_IN_SECS)
} else if self.nanos % NANOS_IN_MILLIS == 0 {
write!(f, "{}ms", self.nanos / NANOS_IN_MILLIS)
} else {
write!(f, "{}ns", self.nanos)
}
}
}