#![doc = include_str!("../README.md")]
#![forbid(unsafe_code)]
#![cfg_attr(
feature = "nightly",
feature(time_systemtime_limits, time_saturating_systemtime)
)]
use std::time::{Duration, Instant, SystemTime};
mod internal;
pub trait SaturatingTime: internal::SaturatingTime {
fn max_value() -> Self {
internal::SaturatingTime::max_value()
}
fn min_value() -> Self {
internal::SaturatingTime::min_value()
}
fn saturating_add(self, duration: Duration) -> Self {
self.checked_add(duration)
.unwrap_or(SaturatingTime::max_value())
}
fn saturating_sub(self, duration: Duration) -> Self {
self.checked_sub(duration)
.unwrap_or(SaturatingTime::min_value())
}
fn saturating_duration_since(&self, earlier: Self) -> Duration {
self.checked_duration_since(earlier)
.unwrap_or(Duration::ZERO)
}
}
#[cfg(feature = "nightly")]
impl SaturatingTime for SystemTime {
fn max_value() -> Self {
Self::MAX
}
fn min_value() -> Self {
Self::MIN
}
fn saturating_add(self, duration: Duration) -> Self {
Self::saturating_add(&self, duration)
}
fn saturating_sub(self, duration: Duration) -> Self {
Self::saturating_sub(&self, duration)
}
fn saturating_duration_since(&self, earlier: Self) -> Duration {
Self::saturating_duration_since(&self, earlier)
}
}
#[cfg(not(feature = "nightly"))]
impl SaturatingTime for SystemTime {}
impl SaturatingTime for Instant {
fn saturating_duration_since(&self, earlier: Self) -> Duration {
Self::saturating_duration_since(self, earlier)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::internal;
use std::{
fmt::Debug,
ops::{Add, Sub},
time::{Instant, SystemTime},
};
fn min_max<T: SaturatingTime + PartialEq + Debug>() {
assert_eq!(
<T as SaturatingTime>::max_value(),
<T as internal::SaturatingTime>::max_value()
);
assert_eq!(
<T as SaturatingTime>::min_value(),
<T as internal::SaturatingTime>::min_value()
);
}
fn saturating_add_sub<
T: SaturatingTime + PartialEq + Debug + Add<Duration, Output = T> + Sub<Duration, Output = T>,
>() {
let max = <T as SaturatingTime>::max_value();
assert_eq!(max.saturating_add(Duration::ZERO), max);
assert_eq!(max.saturating_add(Duration::new(0, 1)), max);
assert_eq!(max.saturating_sub(Duration::ZERO), max);
assert_eq!(
max.saturating_sub(Duration::new(0, 1)),
max - Duration::new(0, 1)
);
let min = <T as SaturatingTime>::min_value();
assert_eq!(min.saturating_sub(Duration::ZERO), min);
assert_eq!(min.saturating_sub(Duration::new(0, 1)), min);
assert_eq!(min.saturating_add(Duration::ZERO), min);
assert_eq!(
min.saturating_add(Duration::new(0, 1)),
min + Duration::new(0, 1)
);
}
fn saturating_duration<T: SaturatingTime + PartialEq + Debug>() {
let anchor = T::anchor();
assert_eq!(anchor.saturating_duration_since(anchor), Duration::ZERO);
let later_anchor = anchor.checked_add(Duration::from_secs(1)).unwrap();
assert!(later_anchor.saturating_duration_since(anchor) == Duration::from_secs(1));
assert_eq!(
anchor.saturating_duration_since(later_anchor),
Duration::ZERO
);
let max = <T as SaturatingTime>::max_value();
let min = <T as SaturatingTime>::min_value();
assert_eq!(max.saturating_duration_since(min), Duration::MAX);
assert_eq!(min.saturating_duration_since(max), Duration::ZERO);
}
#[test]
fn system_time_min_max() {
min_max::<SystemTime>();
}
#[test]
fn instant_min_max() {
min_max::<Instant>();
}
#[test]
fn system_time_saturating() {
saturating_add_sub::<SystemTime>();
saturating_duration::<SystemTime>();
}
#[test]
fn instant_saturating() {
saturating_add_sub::<Instant>();
saturating_duration::<Instant>();
}
}