evobench_tools/stats_tables/tables/
table.rs1use std::{borrow::Cow, fmt::Debug};
13
14use genawaiter::rc::Gen;
15use itertools::{EitherOrBoth, Itertools};
16
17use crate::{
18 evaluator::options::TILE_COUNT,
19 join::KeyVal,
20 resolution_unit::ResolutionUnit,
21 stats_tables::{
22 dynamic_typing::{StatsOrCount, StatsOrCountOrSubStats},
23 stats::{Stats, StatsField, SubStats, ToStatsString},
24 tables::{
25 change::{Change, IsBetter},
26 table_field_view::TableFieldView,
27 table_view::{ColumnFormatting, Highlight, TableView, TableViewRow, Unit},
28 },
29 },
30};
31
32pub trait TableKind: Clone {
33 fn table_name(&self) -> Cow<'_, str>;
34 fn table_key_label(&self) -> Cow<'_, str>;
36 fn table_key_column_width(&self) -> Option<f64>;
39}
40
41pub struct Table<'key, K: TableKind, T> {
42 pub kind: K,
43 pub rows: Vec<KeyVal<Cow<'key, str>, T>>,
44}
45
46impl<'key, K: TableKind, T: TableViewRow<()>> TableView for Table<'key, K, T> {
47 fn table_view_header(&self) -> Box<dyn AsRef<[(Cow<'static, str>, Unit, ColumnFormatting)]>> {
48 let mut header = vec![(
49 self.kind.table_key_label().to_string().into(),
50 Unit::None,
51 ColumnFormatting::String {
52 width_chars: self.kind.table_key_column_width(),
53 },
54 )];
55 let row_header = T::table_view_header(());
56 for label in (*row_header).as_ref() {
57 header.push((*label).clone());
58 }
59 Box::new(header)
60 }
61
62 fn table_name(&self) -> Cow<'_, str> {
63 self.kind.table_name()
64 }
65
66 fn table_view_body<'s>(
67 &'s self,
68 ) -> Box<dyn Iterator<Item = Cow<'s, [(Cow<'s, str>, Highlight)]>> + 's> {
69 Box::new(
70 Gen::new(|co| async move {
71 for KeyVal { key, val } in &self.rows {
72 let mut vals = Vec::new();
76 vals.push((key.clone(), Highlight::Neutral));
77 val.table_view_row(&mut vals);
78 co.yield_(vals.into()).await;
79 }
80 })
81 .into_iter(),
82 )
83 }
84}
85
86impl<'key, K: TableKind, ViewType: Debug + ToStatsString + From<u64> + ResolutionUnit>
87 TableFieldView<TILE_COUNT> for Table<'key, K, StatsOrCountOrSubStats<ViewType, TILE_COUNT>>
88{
89 fn table_key_vals<'s>(
90 &'s self,
91 stats_field: StatsField<TILE_COUNT>,
92 ) -> Box<dyn Iterator<Item = KeyVal<&'s str, u64>> + 's> {
93 Box::new(
94 Gen::new(|co| async move {
95 for KeyVal { key, val } in &self.rows {
96 let val = match val {
97 StatsOrCountOrSubStats::StatsOrCount(stats_or_count) => {
98 match stats_or_count {
99 StatsOrCount::Stats(stats) => stats.get(stats_field),
100 StatsOrCount::Count(_) => {
101 continue;
105 }
106 }
107 }
108 StatsOrCountOrSubStats::SubStats(sub_stats) => match sub_stats {
109 SubStats::Count(stats) => stats.get(stats_field),
110 SubStats::ViewType(stats) => stats.get(stats_field),
111 },
112 };
113 co.yield_(KeyVal {
114 key: key.as_ref(),
115 val,
116 })
117 .await;
118 }
119 })
120 .into_iter(),
121 )
122 }
123
124 fn resolution_unit(&self) -> String {
125 ViewType::RESOLUTION_UNIT_SHORT.into()
126 }
127}
128
129impl<'key, K: TableKind, ViewType: Debug, const TILE_COUNT: usize>
130 Table<'key, K, StatsOrCount<ViewType, TILE_COUNT>>
131{
132 pub fn change<Better: IsBetter>(
135 &self,
136 to: &Self,
137 extract: fn(&Stats<ViewType, TILE_COUNT>) -> u64,
138 ) -> Table<'key, K, Change<Better>> {
139 let mut rows: Vec<KeyVal<_, _>> = Vec::new();
140 for either_or_both in self
141 .rows
142 .iter()
143 .merge_join_by(&to.rows, |a, b| a.key.cmp(&b.key))
144 {
145 if let EitherOrBoth::Both(from, to) = either_or_both {
146 match (&from.val, &to.val) {
147 (StatsOrCount::Stats(from_stats), StatsOrCount::Stats(to_stats)) => {
148 rows.push(KeyVal {
149 key: from.key.clone(), val: Change::new(extract(from_stats), extract(to_stats)),
151 });
152 }
154 (StatsOrCount::Count(_from), StatsOrCount::Count(_to)) => {
155 }
161 _ => panic!("not in sync, {from:?} vs. {to:?}"),
162 }
163 }
164 }
167 Table {
168 kind: self.kind.clone(), rows,
170 }
171 }
172}