use std::fmt;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
pub struct Heatmap(Vec<HeatmapPoint>);
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct HeatmapPoint {
pub start_time: f64,
pub end_time: f64,
pub value: f64,
}
impl Heatmap {
pub fn new(points: Vec<HeatmapPoint>) -> Self {
Self(points)
}
pub fn points(&self) -> &[HeatmapPoint] {
&self.0
}
pub fn most_engaged_segment(&self) -> Option<&HeatmapPoint> {
self.points()
.iter()
.max_by(|a, b| a.value.partial_cmp(&b.value).unwrap_or(std::cmp::Ordering::Equal))
}
pub fn get_highly_engaged_segments(&self, threshold: f64) -> Vec<&HeatmapPoint> {
self.points().iter().filter(|p| p.value >= threshold).collect()
}
pub fn get_point_at_time(&self, timestamp: f64) -> Option<&HeatmapPoint> {
self.points().iter().find(|p| p.contains_timestamp(timestamp))
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl fmt::Display for Heatmap {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Heatmap(points={})", self.0.len())
}
}
impl HeatmapPoint {
pub fn duration(&self) -> f64 {
self.end_time - self.start_time
}
pub fn contains_timestamp(&self, timestamp: f64) -> bool {
timestamp >= self.start_time && timestamp < self.end_time
}
}
impl fmt::Display for HeatmapPoint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"HeatmapPoint(start={:.2}s, end={:.2}s, value={:.2})",
self.start_time, self.end_time, self.value
)
}
}