use crate::compat::Duration;
#[cfg(feature = "alloc")]
use crate::compat::Box;
#[cfg(feature = "std")]
use std::time::Instant;
pub(crate) type ElapsedClockFn = fn() -> Duration;
enum ClockSource {
FnPtr(ElapsedClockFn),
#[cfg(feature = "alloc")]
Boxed(Box<dyn Fn() -> Duration>),
}
impl ClockSource {
fn call(&self) -> Duration {
match self {
ClockSource::FnPtr(f) => f(),
#[cfg(feature = "alloc")]
ClockSource::Boxed(f) => f(),
}
}
}
enum Baseline {
NotStarted,
Origin(Duration),
#[cfg(feature = "std")]
StdInstant(Instant),
}
pub(crate) struct ElapsedTracker {
source: Option<ClockSource>,
baseline: Baseline,
}
impl ElapsedTracker {
pub(crate) fn new(clock: Option<ElapsedClockFn>) -> Self {
Self {
source: clock.map(ClockSource::FnPtr),
baseline: Baseline::NotStarted,
}
}
#[cfg(feature = "alloc")]
pub(crate) fn new_boxed(clock: Box<dyn Fn() -> Duration>) -> Self {
Self {
source: Some(ClockSource::Boxed(clock)),
baseline: Baseline::NotStarted,
}
}
pub(crate) fn start(&mut self) {
if !matches!(self.baseline, Baseline::NotStarted) {
return;
}
self.baseline = match &self.source {
Some(source) => Baseline::Origin(source.call()),
None => {
#[cfg(feature = "std")]
{
Baseline::StdInstant(Instant::now())
}
#[cfg(not(feature = "std"))]
{
Baseline::NotStarted
}
}
};
}
pub(crate) fn elapsed(&self) -> Option<Duration> {
match &self.baseline {
Baseline::NotStarted => None,
Baseline::Origin(origin) => {
let source = self.source.as_ref()?;
Some(source.call().saturating_sub(*origin))
}
#[cfg(feature = "std")]
Baseline::StdInstant(start) => Some(start.elapsed()),
}
}
}