use crate::{
grid::config::SpannedConfig,
grid::dimension::IterGridDimension,
grid::records::{ExactRecords, IntoRecords, PeekableRecords, Records},
grid::util::string::{self, get_text_width},
settings::{Height, Width},
};
pub trait Measurement<Attribute> {
fn measure<R>(&self, records: R, cfg: &SpannedConfig) -> usize
where
R: Records + ExactRecords + PeekableRecords,
<R::Iter as IntoRecords>::Cell: AsRef<str>;
}
impl<T> Measurement<T> for usize {
fn measure<R>(&self, _: R, _: &SpannedConfig) -> usize {
*self
}
}
#[derive(Debug)]
pub struct Max;
impl Measurement<Width> for Max {
fn measure<R: Records + ExactRecords + PeekableRecords>(
&self,
records: R,
_: &SpannedConfig,
) -> usize {
grid_widths(&records)
.map(|r| r.max().unwrap_or(0))
.max()
.unwrap_or(0)
}
}
impl Measurement<Height> for Max {
fn measure<R: Records + ExactRecords + PeekableRecords>(
&self,
records: R,
_: &SpannedConfig,
) -> usize {
records_heights(&records)
.map(|r| r.max().unwrap_or(0))
.max()
.unwrap_or(0)
}
}
#[derive(Debug)]
pub struct Min;
impl Measurement<Width> for Min {
fn measure<R: Records + ExactRecords + PeekableRecords>(
&self,
records: R,
_: &SpannedConfig,
) -> usize {
grid_widths(&records)
.map(|r| r.min().unwrap_or(0))
.max()
.unwrap_or(0)
}
}
impl Measurement<Height> for Min {
fn measure<R: Records + ExactRecords + PeekableRecords>(
&self,
records: R,
_: &SpannedConfig,
) -> usize {
records_heights(&records)
.map(|r| r.max().unwrap_or(0))
.min()
.unwrap_or(0)
}
}
#[derive(Debug)]
pub struct Percent(pub usize);
impl Measurement<Width> for Percent {
fn measure<R>(&self, records: R, cfg: &SpannedConfig) -> usize
where
R: Records,
<R::Iter as IntoRecords>::Cell: AsRef<str>,
{
let total = IterGridDimension::width_total(records, cfg);
(total * self.0) / 100
}
}
impl Measurement<Height> for Percent {
fn measure<R>(&self, records: R, cfg: &SpannedConfig) -> usize
where
R: Records + ExactRecords,
<R::Iter as IntoRecords>::Cell: AsRef<str>,
{
let total = IterGridDimension::height_total(records, cfg);
(total * self.0) / 100
}
}
fn grid_widths<R>(records: &R) -> impl Iterator<Item = impl Iterator<Item = usize> + '_> + '_
where
R: Records + ExactRecords + PeekableRecords,
{
let (count_rows, count_cols) = (records.count_rows(), records.count_columns());
(0..count_rows).map(move |row| {
(0..count_cols).map(move |col| get_text_width(records.get_text((row, col).into())))
})
}
fn records_heights<R>(records: &R) -> impl Iterator<Item = impl Iterator<Item = usize> + '_> + '_
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).into())))
})
}