use std::collections::HashMap;
#[doc(inline)]
use crate::chart::{Percentages, TagPercent};
#[derive(Debug)]
pub struct PieData {
total: f32,
data: HashMap<String, f32>
}
impl PieData {
pub fn add_secs(&mut self, label: &str, secs: u64) {
#![allow(clippy::cast_precision_loss)]
let secs = secs as f32;
self.total += secs;
let entry = self.data.entry(label.to_string()).or_insert(0.0);
*entry += secs;
}
pub fn get_percent(&self, label: &str) -> Option<f32> {
self.data.get(label).map(|&s| self.cent(s))
}
pub fn is_empty(&self) -> bool { self.data.is_empty() }
pub fn total(&self) -> f32 { self.total }
pub fn labels(&self) -> Vec<&str> {
let mut labels: Vec<&str> = self.data.keys().map(String::as_str).collect();
labels.sort();
labels
}
pub fn percentages(&self) -> Percentages {
let mut percents: Percentages = self
.data
.iter()
.filter_map(|(l, p)| TagPercent::new(l, self.cent(*p)))
.collect();
percents.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
percents
}
fn cent(&self, val: f32) -> f32 { 100.0 * val / self.total }
}
impl Default for PieData {
fn default() -> Self { Self { total: 0.0, data: HashMap::new() } }
}
#[cfg(test)]
mod tests {
use assert2::{assert, let_assert};
use super::*;
#[test]
fn test_default() {
let pd = PieData::default();
assert!(pd.is_empty());
assert!(pd.total() == 0.0);
assert!(pd.labels().len() == 0);
assert!(pd.percentages().len() == 0);
}
#[test]
fn test_add_secs() {
let mut pd = PieData::default();
pd.add_secs("foo", 300);
assert!(!pd.is_empty());
assert!(pd.total() == 300.0);
assert!(pd.labels().len() == 1);
assert!(pd.labels() == vec!["foo"]);
let_assert!(Some(expected_pcnt) = TagPercent::new("foo", 100.0));
assert!(pd.percentages() == vec![expected_pcnt]);
}
#[test]
fn test_add_secs_multiple() {
let mut pd = PieData::default();
#[rustfmt::skip]
let input = [
("david", 400),
("kirsten", 300),
("mark", 200),
("connie", 100)
];
for (label, secs) in &input {
pd.add_secs(label, *secs);
}
assert!(pd.total() == 1000.0);
let expect: Vec<&str> = vec!["connie", "david", "kirsten", "mark"];
assert!(pd.labels() == expect);
let expect: Vec<TagPercent> = input
.iter()
.map(|(l, s)| TagPercent::new(l, *s as f32 / 10.0).expect("Hardcoded value"))
.collect();
assert!(pd.percentages() == expect);
}
}