tabled/features/
measurment.rs

1//! The module contains [`Measurment`] trait and its implementations to be used in [`Height`] and [`Width`].
2
3use papergrid::{
4    height::HeightEstimator,
5    records::Records,
6    width::{CfgWidthFunction, WidthFunc},
7    GridConfig,
8};
9
10use crate::{height::get_table_total_height, width::get_table_widths_with_total, Height, Width};
11
12/// A width value which can be obtained on behalf of [`Table`].
13///
14/// [`Table`]: crate::Table
15pub trait Measurment<Attribute> {
16    /// Returns a measurment value.
17    fn measure<R>(&self, records: R, cfg: &GridConfig) -> usize
18    where
19        R: Records;
20}
21
22impl<T> Measurment<T> for usize {
23    fn measure<R>(&self, _: R, _: &GridConfig) -> usize {
24        *self
25    }
26}
27
28/// Max width value.
29#[derive(Debug)]
30pub struct Max;
31
32impl Measurment<Width> for Max {
33    fn measure<R>(&self, records: R, cfg: &GridConfig) -> usize
34    where
35        R: Records,
36    {
37        let ctrl = CfgWidthFunction::from_cfg(cfg);
38        grid_widths(&records, &ctrl)
39            .map(|r| r.max().unwrap_or(0))
40            .max()
41            .unwrap_or(0)
42    }
43}
44
45impl Measurment<Height> for Max {
46    fn measure<R>(&self, records: R, _: &GridConfig) -> usize
47    where
48        R: Records,
49    {
50        records_heights(&records)
51            .map(|r| r.max().unwrap_or(0))
52            .max()
53            .unwrap_or(0)
54    }
55}
56
57/// Min width value.
58#[derive(Debug)]
59pub struct Min;
60
61impl Measurment<Width> for Min {
62    fn measure<R>(&self, records: R, cfg: &GridConfig) -> usize
63    where
64        R: Records,
65    {
66        let ctrl = CfgWidthFunction::from_cfg(cfg);
67        grid_widths(&records, &ctrl)
68            .map(|r| r.min().unwrap_or(0))
69            .max()
70            .unwrap_or(0)
71    }
72}
73
74impl Measurment<Height> for Min {
75    fn measure<R>(&self, records: R, _: &GridConfig) -> usize
76    where
77        R: Records,
78    {
79        records_heights(&records)
80            .map(|r| r.max().unwrap_or(0))
81            .min()
82            .unwrap_or(0)
83    }
84}
85
86/// Percent from a total table width.
87#[derive(Debug)]
88pub struct Percent(pub usize);
89
90impl Measurment<Width> for Percent {
91    fn measure<R>(&self, records: R, cfg: &GridConfig) -> usize
92    where
93        R: Records,
94    {
95        let (_, total) = get_table_widths_with_total(&records, cfg);
96        (total * self.0) / 100
97    }
98}
99
100impl Measurment<Height> for Percent {
101    fn measure<R>(&self, records: R, cfg: &GridConfig) -> usize
102    where
103        R: Records,
104    {
105        let total = get_table_total_height(&records, cfg, &HeightEstimator::default());
106        (total * self.0) / 100
107    }
108}
109
110fn records_heights<R>(records: &R) -> impl Iterator<Item = impl Iterator<Item = usize> + '_> + '_
111where
112    R: Records,
113{
114    (0..records.count_rows()).map(move |row| {
115        (0..records.count_columns()).map(move |col| records.count_lines((row, col)))
116    })
117}
118
119fn grid_widths<'a, R, W>(
120    records: &'a R,
121    ctrl: &'a W,
122) -> impl Iterator<Item = impl Iterator<Item = usize> + 'a> + 'a
123where
124    W: WidthFunc,
125    R: Records,
126{
127    let (count_rows, count_cols) = (records.count_rows(), records.count_columns());
128    (0..count_rows)
129        .map(move |row| (0..count_cols).map(move |col| records.get_width((row, col), ctrl)))
130}