evobench_tools/stats_tables/tables/
change.rs

1//! A value representing change, by pairing a from and to value
2//!
3//! With formatting indicating positive/negative change, used by the
4//! `change()` method on `Table` to produce a table that represents
5//! the change between two tables.
6
7use std::{borrow::Cow, marker::PhantomData};
8
9use super::table_view::{ColumnFormatting, Highlight, TableViewRow, Unit};
10
11pub trait IsBetter {
12    const FORMATTING_FOR_LARGER: Highlight;
13    const FORMATTING_FOR_SMALLER: Highlight;
14}
15
16pub struct LargerIsBetter;
17impl IsBetter for LargerIsBetter {
18    const FORMATTING_FOR_LARGER: Highlight = Highlight::Green;
19
20    const FORMATTING_FOR_SMALLER: Highlight = Highlight::Red;
21}
22
23pub struct SmallerIsBetter;
24impl IsBetter for SmallerIsBetter {
25    const FORMATTING_FOR_LARGER: Highlight = Highlight::Red;
26
27    const FORMATTING_FOR_SMALLER: Highlight = Highlight::Green;
28}
29
30#[derive(Debug)]
31pub struct Change<Better: IsBetter> {
32    better: PhantomData<Better>,
33    pub from: u64,
34    pub to: u64,
35}
36
37impl<Better: IsBetter> Change<Better> {
38    // XX take two `ViewType`s instead to ensure the values are
39    // compatible? "But" already have u64 from `Stat`, "that's more
40    // efficient".
41    pub fn new(from: u64, to: u64) -> Self {
42        Self {
43            better: Default::default(),
44            from,
45            to,
46        }
47    }
48}
49
50impl<Better: IsBetter> TableViewRow<()> for Change<Better> {
51    fn table_view_header(_: ()) -> Box<dyn AsRef<[(Cow<'static, str>, Unit, ColumnFormatting)]>> {
52        const HEADER: &[(Cow<'static, str>, Unit, ColumnFormatting)] = &[(
53            Cow::Borrowed("change"),
54            Unit::DimensionLess,
55            ColumnFormatting::Number,
56        )];
57        Box::new(HEADER)
58    }
59    fn table_view_row(&self, out: &mut Vec<(Cow<str>, Highlight)>) {
60        let Change {
61            better: _,
62            from,
63            to,
64        } = self;
65        let relative = *to as f64 / *from as f64;
66        let formatting = if relative > 1.1 {
67            Better::FORMATTING_FOR_LARGER
68        } else if relative < 0.9 {
69            Better::FORMATTING_FOR_SMALLER
70        } else {
71            Highlight::Neutral
72        };
73        out.push((format!("{relative:.3}").into(), formatting));
74    }
75}