//! The module contains [`Measurement`] trait and its implementations to be used in [`Height`] and [`Width`].; use crate::{ grid::config::SpannedConfig, grid::dimension::SpannedGridDimension, grid::records::{ExactRecords, PeekableRecords, Records}, grid::util::string::{self, string_width_multiline}, settings::{Height, Width}, }; /// A width value which can be obtained on behalf of [`Table`]. /// /// [`Table`]: crate::Table pub trait Measurement { /// Returns a measurement value. fn measure( &self, records: R, cfg: &SpannedConfig, ) -> usize; } impl Measurement for usize { fn measure(&self, _: R, _: &SpannedConfig) -> usize { *self } } /// Max width value. #[derive(Debug)] pub struct Max; impl Measurement for Max { fn measure( &self, records: R, _: &SpannedConfig, ) -> usize { grid_widths(&records) .map(|r| r.max().unwrap_or(0)) .max() .unwrap_or(0) } } impl Measurement for Max { fn measure( &self, records: R, _: &SpannedConfig, ) -> usize { records_heights(&records) .map(|r| r.max().unwrap_or(0)) .max() .unwrap_or(0) } } /// Min width value. #[derive(Debug)] pub struct Min; impl Measurement for Min { fn measure( &self, records: R, _: &SpannedConfig, ) -> usize { grid_widths(&records) .map(|r| r.min().unwrap_or(0)) .max() .unwrap_or(0) } } impl Measurement for Min { fn measure( &self, records: R, _: &SpannedConfig, ) -> usize { records_heights(&records) .map(|r| r.max().unwrap_or(0)) .min() .unwrap_or(0) } } /// Percent from a total table width. #[derive(Debug)] pub struct Percent(pub usize); impl Measurement for Percent { fn measure(&self, records: R, cfg: &SpannedConfig) -> usize where R: Records, { let (_, total) = get_table_widths_with_total(records, cfg); (total * self.0) / 100 } } impl Measurement for Percent { fn measure(&self, records: R, cfg: &SpannedConfig) -> usize where R: Records + ExactRecords, { let (_, total) = get_table_heights_width_total(records, cfg); (total * self.0) / 100 } } fn grid_widths( records: &R, ) -> impl Iterator + '_> + '_ { let (count_rows, count_cols) = (records.count_rows(), records.count_columns()); (0..count_rows).map(move |row| { (0..count_cols).map(move |col| string_width_multiline(records.get_text((row, col)))) }) } fn get_table_widths_with_total(records: R, cfg: &SpannedConfig) -> (Vec, usize) where R: Records, { let widths = SpannedGridDimension::width(records, cfg); let total_width = get_table_total_width(&widths, cfg); (widths, total_width) } fn get_table_total_width(list: &[usize], cfg: &SpannedConfig) -> usize { let total = list.iter().sum::(); total + cfg.count_vertical(list.len()) } fn records_heights(records: &R) -> impl Iterator + '_> + '_ where R: Records + ExactRecords + PeekableRecords, { (0..records.count_rows()).map(move |row| { (0..records.count_columns()) .map(move |col| string::count_lines(records.get_text((row, col)))) }) } fn get_table_heights_width_total(records: R, cfg: &SpannedConfig) -> (Vec, usize) where R: Records, { let list = SpannedGridDimension::height(records, cfg); let total = get_table_total_height(&list, cfg); (list, total) } fn get_table_total_height(list: &[usize], cfg: &SpannedConfig) -> usize { let total = list.iter().sum::(); let counth = cfg.count_horizontal(list.len()); total + counth }