use crate::{
ClockDomain,
TimeError,
};
use std::cmp::Ordering;
use std::time::Duration;
#[must_use = "monotonic instants should be used to measure or compare time"]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MonotonicInstant {
domain: ClockDomain,
elapsed: Duration,
}
impl MonotonicInstant {
#[inline(always)]
pub const fn new(domain: ClockDomain, elapsed: Duration) -> Self {
Self { domain, elapsed }
}
#[inline(always)]
pub const fn domain(self) -> ClockDomain {
self.domain
}
#[must_use]
#[inline(always)]
pub const fn elapsed_since_origin(self) -> Duration {
self.elapsed
}
#[inline]
pub fn checked_add(self, duration: Duration) -> Result<Self, TimeError> {
let elapsed = self
.elapsed
.checked_add(duration)
.ok_or(TimeError::InstantOverflow)?;
Ok(Self::new(self.domain, elapsed))
}
#[inline]
pub fn duration_since(self, earlier: Self) -> Result<Duration, TimeError> {
earlier.validate_domain(self.domain)?;
self.elapsed.checked_sub(earlier.elapsed).ok_or(
TimeError::InvalidInstantOrder {
current_elapsed: self.elapsed,
earlier_elapsed: earlier.elapsed,
},
)
}
#[inline]
pub fn validate_domain(
self,
expected_domain: ClockDomain,
) -> Result<(), TimeError> {
if self.domain == expected_domain {
Ok(())
} else {
Err(TimeError::ClockDomainMismatch {
expected: expected_domain,
actual: self.domain,
})
}
}
}
impl PartialOrd for MonotonicInstant {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
(self.domain == other.domain).then(|| self.elapsed.cmp(&other.elapsed))
}
}