#![doc = simple_mermaid::mermaid!("../diagrams/session_lifecycle.mmd")]
use web_time::{Duration, Instant};
use crate::CharacterResult;
use crate::config::Configuration;
use crate::statistics::{Statistics, TempStatistics};
#[derive(Debug, Clone)]
pub struct StatisticsTracker {
stats: TempStatistics,
started_at: Option<Instant>,
completed_at: Option<Instant>,
}
impl StatisticsTracker {
pub fn new() -> Self {
Self {
stats: TempStatistics::default(),
started_at: None,
completed_at: None,
}
}
pub fn statistics(&self) -> &TempStatistics {
&self.stats
}
pub fn update(
&mut self,
char: char,
result: CharacterResult,
input_len: usize,
config: &Configuration,
) {
if self.started_at.is_none() {
self.started_at = Some(Instant::now());
}
let started_at = self.started_at.as_ref().unwrap();
let elapsed = started_at.elapsed();
self.stats.update(char, result, input_len, elapsed, config);
}
pub fn has_started(&self) -> bool {
self.started_at.is_some()
}
pub fn elapsed(&self) -> Option<Duration> {
self.started_at.map(|start| start.elapsed())
}
pub fn mark_completed(&mut self) {
if self.completed_at.is_none() {
self.completed_at = Some(Instant::now());
}
}
pub fn is_completed(&self) -> bool {
self.completed_at.is_some()
}
pub fn total_duration(&self) -> Option<Duration> {
match (self.started_at, self.completed_at) {
(Some(start), Some(end)) => Some(end.duration_since(start)),
(Some(start), None) => Some(start.elapsed()),
_ => None,
}
}
pub fn finalize(self, input_len: usize) -> Statistics {
let total_duration = self.total_duration().unwrap_or(Duration::ZERO);
self.stats.finalize(total_duration, input_len)
}
}
impl Default for StatisticsTracker {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_statistics_tracker() {
let mut stats_tracker = StatisticsTracker::new();
let config = Configuration::default();
let stats = stats_tracker.statistics();
assert_eq!(stats.counters.adds, 0);
assert_eq!(stats.counters.errors, 0);
assert!(!stats_tracker.has_started());
stats_tracker.update('x', CharacterResult::Wrong, 1, &config);
let stats = stats_tracker.statistics();
assert_eq!(stats.counters.adds, 1);
assert_eq!(stats.counters.errors, 1);
assert!(stats_tracker.has_started());
stats_tracker.update('b', CharacterResult::Correct, 2, &config);
let stats = stats_tracker.statistics();
assert_eq!(stats.counters.adds, 2);
assert_eq!(stats.counters.errors, 1);
assert!(stats_tracker.elapsed().is_some());
}
}