use crate::meter::format::{format_duration_nanos, format_speed};
use crate::{NanoClock, NanoMonotonicClock};
use chrono::Duration;
pub struct NanoTimeMeter<C: NanoClock> {
clock: C,
start_time: Option<i128>,
end_time: Option<i128>,
}
impl<C: NanoClock> NanoTimeMeter<C> {
#[inline]
pub fn with_clock(clock: C) -> Self {
NanoTimeMeter {
clock,
start_time: None,
end_time: None,
}
}
#[inline]
pub fn with_clock_started(clock: C) -> Self {
let mut meter = Self::with_clock(clock);
meter.start();
meter
}
#[inline]
pub fn start(&mut self) {
self.start_time = Some(self.clock.nanos());
self.end_time = None;
}
#[inline]
pub fn stop(&mut self) {
self.end_time = Some(self.clock.nanos());
}
#[inline]
pub fn reset(&mut self) {
self.start_time = None;
self.end_time = None;
}
#[inline]
pub fn restart(&mut self) {
self.reset();
self.start();
}
#[inline]
pub fn nanos(&self) -> i128 {
let start = match self.start_time {
Some(t) => t,
None => return 0,
};
let end = self.end_time.unwrap_or_else(|| self.clock.nanos());
end - start
}
#[inline]
pub fn micros(&self) -> i128 {
self.nanos() / 1_000
}
#[inline]
pub fn millis(&self) -> i64 {
(self.nanos() / 1_000_000) as i64
}
#[inline]
pub fn seconds(&self) -> i64 {
(self.nanos() / 1_000_000_000) as i64
}
#[inline]
pub fn minutes(&self) -> i64 {
(self.nanos() / 60_000_000_000) as i64
}
#[inline]
pub fn duration(&self) -> Duration {
Duration::nanoseconds(self.nanos() as i64)
}
#[inline]
pub fn readable_duration(&self) -> String {
format_duration_nanos(self.nanos())
}
#[inline]
pub fn speed_per_second(&self, count: usize) -> Option<f64> {
let seconds = self.seconds();
if seconds == 0 {
None
} else {
Some(count as f64 / seconds as f64)
}
}
#[inline]
pub fn speed_per_minute(&self, count: usize) -> Option<f64> {
let seconds = self.seconds();
if seconds == 0 {
None
} else {
Some((count as f64 / seconds as f64) * 60.0)
}
}
#[inline]
pub fn formatted_speed_per_second(&self, count: usize) -> String {
match self.speed_per_second(count) {
Some(speed) => format_speed(speed, "/s"),
None => "N/A".to_string(),
}
}
#[inline]
pub fn formatted_speed_per_minute(&self, count: usize) -> String {
match self.speed_per_minute(count) {
Some(speed) => format_speed(speed, "/m"),
None => "N/A".to_string(),
}
}
#[inline]
pub fn is_running(&self) -> bool {
self.start_time.is_some() && self.end_time.is_none()
}
#[inline]
pub fn is_stopped(&self) -> bool {
self.end_time.is_some()
}
#[inline]
pub fn clock(&self) -> &C {
&self.clock
}
#[inline]
pub fn clock_mut(&mut self) -> &mut C {
&mut self.clock
}
}
impl NanoTimeMeter<NanoMonotonicClock> {
#[inline]
pub fn new() -> Self {
Self::with_clock(NanoMonotonicClock::new())
}
#[inline]
pub fn start_now() -> Self {
Self::with_clock_started(NanoMonotonicClock::new())
}
}
impl Default for NanoTimeMeter<NanoMonotonicClock> {
#[inline]
fn default() -> Self {
Self::new()
}
}