From ef24de24a82fe681581cc130f342363c47c0969a Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 7 Jun 2024 07:48:48 +0200 Subject: Merging upstream version 1.75.0+dfsg1. Signed-off-by: Daniel Baumann --- .../src/grid/dimension/complete_dimension.rs | 136 +++++++++ .../dimension/complete_dimension_vec_records.rs | 128 ++++++++ .../tabled/src/grid/dimension/const_dimension.rs | 70 +++++ vendor/tabled/src/grid/dimension/mod.rs | 32 ++ .../src/grid/dimension/peekable_dimension.rs | 335 +++++++++++++++++++++ .../src/grid/dimension/pool_table_dimension.rs | 36 +++ .../tabled/src/grid/dimension/static_dimension.rs | 63 ++++ 7 files changed, 800 insertions(+) create mode 100644 vendor/tabled/src/grid/dimension/complete_dimension.rs create mode 100644 vendor/tabled/src/grid/dimension/complete_dimension_vec_records.rs create mode 100644 vendor/tabled/src/grid/dimension/const_dimension.rs create mode 100644 vendor/tabled/src/grid/dimension/mod.rs create mode 100644 vendor/tabled/src/grid/dimension/peekable_dimension.rs create mode 100644 vendor/tabled/src/grid/dimension/pool_table_dimension.rs create mode 100644 vendor/tabled/src/grid/dimension/static_dimension.rs (limited to 'vendor/tabled/src/grid/dimension') diff --git a/vendor/tabled/src/grid/dimension/complete_dimension.rs b/vendor/tabled/src/grid/dimension/complete_dimension.rs new file mode 100644 index 000000000..3147cb27a --- /dev/null +++ b/vendor/tabled/src/grid/dimension/complete_dimension.rs @@ -0,0 +1,136 @@ +use std::borrow::Cow; + +use crate::grid::{ + config::{ColoredConfig, SpannedConfig}, + dimension::{Dimension, Estimate, SpannedGridDimension}, + records::Records, +}; + +/// CompleteDimension is a [`Dimension`] implementation for a [`Table`] +/// +/// [`Table`]: crate::Table +#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Clone)] +pub struct CompleteDimension<'a> { + width: Option>, + height: Option>, +} + +impl CompleteDimension<'_> { + /// Checks whether is the dimensions is set. + pub fn is_complete(&self) -> bool { + self.width.is_some() && self.height.is_some() + } + + /// Checks whether is nothing was set. + pub fn is_empty(&self) -> bool { + self.width.is_none() && self.height.is_none() + } + + /// Set column widths. + /// + /// In general the method is only considered to be useful to a [`TableOption`]. + /// + /// BE CAREFUL WITH THIS METHOD as it supposed that the content is not bigger than the provided widths. + /// + /// [`TableOption`]: crate::settings::TableOption + pub fn set_widths(&mut self, columns: Vec) -> bool { + self.width = Some(Cow::Owned(columns)); + + true + } + + /// Set rows heights. + /// + /// In general the method is only considered to be useful to a [`TableOption`]. + /// + /// BE CAREFUL WITH THIS METHOD as it supposed that the content is not bigger than the provided heights. + /// + /// [`TableOption`]: crate::settings::TableOption + pub fn set_heights(&mut self, rows: Vec) -> bool { + self.height = Some(Cow::Owned(rows)); + + true + } + + /// Force width estimation. + pub fn clear_width(&mut self) { + self.width = None; + } + + /// Force height estimation. + pub fn clear_height(&mut self) { + self.height = None; + } + + /// Copies a reference from self. + pub fn from_origin(&self) -> CompleteDimension<'_> { + let width = self.width.as_deref().map(Cow::Borrowed); + let height = self.height.as_deref().map(Cow::Borrowed); + + CompleteDimension { width, height } + } +} + +impl Dimension for CompleteDimension<'_> { + fn get_width(&self, column: usize) -> usize { + let width = self + .width + .as_ref() + .expect("It must always be Some at this point"); + + width[column] + } + + fn get_height(&self, row: usize) -> usize { + let height = self + .height + .as_ref() + .expect("It must always be Some at this point"); + + height[row] + } +} + +impl Estimate for CompleteDimension<'_> { + fn estimate(&mut self, records: R, cfg: &SpannedConfig) { + match (self.width.is_some(), self.height.is_some()) { + (true, true) => {} + (true, false) => { + self.height = Some(Cow::Owned(SpannedGridDimension::height(records, cfg))); + } + (false, true) => { + self.width = Some(Cow::Owned(SpannedGridDimension::width(records, cfg))); + } + (false, false) => { + let mut dims = SpannedGridDimension::default(); + dims.estimate(records, cfg); + + let (width, height) = dims.get_values(); + self.width = Some(Cow::Owned(width)); + self.height = Some(Cow::Owned(height)); + } + } + } +} + +impl Estimate for CompleteDimension<'_> { + fn estimate(&mut self, records: R, cfg: &ColoredConfig) { + match (self.width.is_some(), self.height.is_some()) { + (true, true) => {} + (true, false) => { + self.height = Some(Cow::Owned(SpannedGridDimension::height(records, cfg))); + } + (false, true) => { + self.width = Some(Cow::Owned(SpannedGridDimension::width(records, cfg))); + } + (false, false) => { + let mut dims = SpannedGridDimension::default(); + dims.estimate(records, cfg); + + let (width, height) = dims.get_values(); + self.width = Some(Cow::Owned(width)); + self.height = Some(Cow::Owned(height)); + } + } + } +} diff --git a/vendor/tabled/src/grid/dimension/complete_dimension_vec_records.rs b/vendor/tabled/src/grid/dimension/complete_dimension_vec_records.rs new file mode 100644 index 000000000..ddc806a45 --- /dev/null +++ b/vendor/tabled/src/grid/dimension/complete_dimension_vec_records.rs @@ -0,0 +1,128 @@ +use std::borrow::Cow; + +use papergrid::{ + dimension::spanned_vec_records::SpannedVecRecordsDimension, records::vec_records::VecRecords, +}; + +use crate::grid::{ + config::{ColoredConfig, SpannedConfig}, + dimension::{Dimension, Estimate}, + records::vec_records::Cell, +}; + +/// CompleteDimension is a [`Dimension`] implementation for a [`Table`] +/// +/// [`Table`]: crate::Table +#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Clone)] +pub struct CompleteDimensionVecRecords<'a> { + width: Option>, + height: Option>, +} + +impl CompleteDimensionVecRecords<'_> { + /// Checks whether is the dimensions is set. + pub fn is_complete(&self) -> bool { + self.width.is_some() && self.height.is_some() + } + + /// Checks whether is nothing was set. + pub fn is_empty(&self) -> bool { + self.width.is_none() && self.height.is_none() + } + + /// Set column widths. + /// + /// In general the method is only considered to be useful to a [`TableOption`]. + /// + /// BE CAREFUL WITH THIS METHOD as it supposed that the content is not bigger than the provided widths. + /// + /// [`TableOption`]: crate::settings::TableOption + pub fn set_widths(&mut self, columns: Vec) -> bool { + self.width = Some(Cow::Owned(columns)); + + true + } + + /// Set rows heights. + /// + /// In general the method is only considered to be useful to a [`TableOption`]. + /// + /// BE CAREFUL WITH THIS METHOD as it supposed that the content is not bigger than the provided heights. + /// + /// [`TableOption`]: crate::settings::TableOption + pub fn set_heights(&mut self, rows: Vec) -> bool { + self.height = Some(Cow::Owned(rows)); + + true + } + + /// Force width estimation. + pub fn clear_width(&mut self) { + self.width = None; + } + + /// Force height estimation. + pub fn clear_height(&mut self) { + self.height = None; + } + + /// Copies a reference from self. + pub fn from_origin(&self) -> CompleteDimensionVecRecords<'_> { + let width = self.width.as_deref().map(Cow::Borrowed); + let height = self.height.as_deref().map(Cow::Borrowed); + + CompleteDimensionVecRecords { width, height } + } +} + +impl Dimension for CompleteDimensionVecRecords<'_> { + fn get_width(&self, column: usize) -> usize { + let width = self + .width + .as_ref() + .expect("It must always be Some at this point"); + + width[column] + } + + fn get_height(&self, row: usize) -> usize { + let height = self + .height + .as_ref() + .expect("It must always be Some at this point"); + + height[row] + } +} + +impl + Cell> Estimate<&VecRecords, SpannedConfig> + for CompleteDimensionVecRecords<'_> +{ + fn estimate(&mut self, records: &VecRecords, cfg: &SpannedConfig) { + match (self.width.is_some(), self.height.is_some()) { + (true, true) => {} + (true, false) => { + self.height = Some(Cow::Owned(SpannedVecRecordsDimension::height(records, cfg))); + } + (false, true) => { + self.width = Some(Cow::Owned(SpannedVecRecordsDimension::width(records, cfg))); + } + (false, false) => { + let mut dims = SpannedVecRecordsDimension::default(); + dims.estimate(records, cfg); + + let (width, height) = dims.get_values(); + self.width = Some(Cow::Owned(width)); + self.height = Some(Cow::Owned(height)); + } + } + } +} + +impl + Cell> Estimate<&VecRecords, ColoredConfig> + for CompleteDimensionVecRecords<'_> +{ + fn estimate(&mut self, records: &VecRecords, cfg: &ColoredConfig) { + self.estimate(records, cfg.as_ref()) + } +} diff --git a/vendor/tabled/src/grid/dimension/const_dimension.rs b/vendor/tabled/src/grid/dimension/const_dimension.rs new file mode 100644 index 000000000..450b1abfe --- /dev/null +++ b/vendor/tabled/src/grid/dimension/const_dimension.rs @@ -0,0 +1,70 @@ +//! Module contains a dimension estimator for [`CompactTable`] +//! +//! [`CompactTable`]: crate::tables::CompactTable + +use crate::grid::dimension::{Dimension, Estimate}; + +/// A constant size dimension or a value dimension. +#[derive(Debug, Clone, Copy)] +pub struct ConstDimension { + height: ConstSize, + width: ConstSize, +} + +impl ConstDimension { + /// Returns a new dimension object with a given estimates. + pub const fn new(width: ConstSize, height: ConstSize) -> Self { + Self { width, height } + } +} + +impl Dimension for ConstDimension { + fn get_width(&self, column: usize) -> usize { + match self.width { + ConstSize::List(list) => list[column], + ConstSize::Value(val) => val, + } + } + + fn get_height(&self, row: usize) -> usize { + match self.height { + ConstSize::List(list) => list[row], + ConstSize::Value(val) => val, + } + } +} + +impl From> + for (ConstSize, ConstSize) +{ + fn from(value: ConstDimension) -> Self { + (value.width, value.height) + } +} + +impl Estimate + for ConstDimension +{ + fn estimate(&mut self, _: R, _: &D) {} +} + +/// Const size represents either a const array values or a single value which responsible for the whole list. +#[derive(Debug, Clone, Copy)] +pub enum ConstSize { + /// A constant array of estimates. + List([usize; N]), + /// A value which act as a single estimate for all entries. + Value(usize), +} + +impl From for ConstSize<0> { + fn from(value: usize) -> Self { + ConstSize::Value(value) + } +} + +impl From<[usize; N]> for ConstSize { + fn from(value: [usize; N]) -> Self { + ConstSize::List(value) + } +} diff --git a/vendor/tabled/src/grid/dimension/mod.rs b/vendor/tabled/src/grid/dimension/mod.rs new file mode 100644 index 000000000..2f67b402f --- /dev/null +++ b/vendor/tabled/src/grid/dimension/mod.rs @@ -0,0 +1,32 @@ +//! Module contains a list of implementations of [`Estimate`] and [`Dimension`]. + +mod const_dimension; +mod pool_table_dimension; + +#[cfg(feature = "std")] +mod complete_dimension; +#[cfg(feature = "std")] +mod complete_dimension_vec_records; +#[cfg(feature = "std")] +mod peekable_dimension; +#[cfg(feature = "std")] +mod static_dimension; + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +pub use self::{ + complete_dimension::CompleteDimension, + complete_dimension_vec_records::CompleteDimensionVecRecords, + peekable_dimension::PeekableDimension, + static_dimension::{DimensionValue, StaticDimension}, +}; +pub use const_dimension::{ConstDimension, ConstSize}; +pub use papergrid::dimension::{Dimension, Estimate}; +pub use pool_table_dimension::{DimensionPriority, PoolTableDimension}; + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +pub use papergrid::dimension::{ + compact::CompactGridDimension, spanned::SpannedGridDimension, + spanned_vec_records::SpannedVecRecordsDimension, +}; diff --git a/vendor/tabled/src/grid/dimension/peekable_dimension.rs b/vendor/tabled/src/grid/dimension/peekable_dimension.rs new file mode 100644 index 000000000..1ba6fda21 --- /dev/null +++ b/vendor/tabled/src/grid/dimension/peekable_dimension.rs @@ -0,0 +1,335 @@ +use papergrid::records::vec_records::{CellInfo, VecRecords}; + +use crate::grid::{ + config::SpannedConfig, + dimension::{Dimension, Estimate}, + records::Records, +}; + +/// PeekableDimension is a [`Dimension`] implementation for a [`Table`] +/// +/// [`Table`]: crate::Table +#[derive(Debug, Default, Clone)] +pub struct PeekableDimension { + width: Vec, + height: Vec, +} + +impl PeekableDimension { + /// Calculates height of rows. + pub fn height>( + records: &VecRecords>, + cfg: &SpannedConfig, + ) -> Vec { + estimation::build_height(records, cfg) + } + + /// Calculates width of columns. + pub fn width>( + records: &VecRecords>, + cfg: &SpannedConfig, + ) -> Vec { + estimation::build_width(records, cfg) + } + + /// Return width and height lists. + pub fn get_values(self) -> (Vec, Vec) { + (self.width, self.height) + } +} + +impl Dimension for PeekableDimension { + fn get_width(&self, column: usize) -> usize { + self.width[column] + } + + fn get_height(&self, row: usize) -> usize { + self.height[row] + } +} + +impl Estimate<&VecRecords>, SpannedConfig> for PeekableDimension +where + T: AsRef, +{ + fn estimate(&mut self, records: &VecRecords>, cfg: &SpannedConfig) { + let (width, height) = estimation::build_dimensions(records, cfg); + self.width = width; + self.height = height; + } +} + +mod estimation { + use core::cmp::{max, Ordering}; + use std::collections::HashMap; + + use papergrid::{ + config::Position, + records::vec_records::{Cell, CellInfo, VecRecords}, + }; + + use super::*; + + pub(super) fn build_dimensions>( + records: &VecRecords>, + cfg: &SpannedConfig, + ) -> (Vec, Vec) { + let count_columns = records.count_columns(); + + let mut widths = vec![0; count_columns]; + let mut heights = vec![]; + + let mut vspans = HashMap::new(); + let mut hspans = HashMap::new(); + + for (row, columns) in records.iter_rows().enumerate() { + let mut row_height = 0; + for (col, cell) in columns.iter().enumerate() { + let pos = (row, col); + if !cfg.is_cell_visible(pos) { + continue; + } + + let height = cell.count_lines(); + let width = cell.width(); + + let pad = cfg.get_padding(pos.into()); + let width = width + pad.left.size + pad.right.size; + let height = height + pad.top.size + pad.bottom.size; + + match cfg.get_column_span(pos) { + Some(n) if n > 1 => { + let _ = vspans.insert(pos, (n, width)); + } + _ => widths[col] = max(widths[col], width), + } + + match cfg.get_row_span(pos) { + Some(n) if n > 1 => { + let _ = hspans.insert(pos, (n, height)); + } + _ => row_height = max(row_height, height), + } + } + + heights.push(row_height); + } + + let count_rows = heights.len(); + + adjust_vspans(cfg, count_columns, &vspans, &mut widths); + adjust_hspans(cfg, count_rows, &hspans, &mut heights); + + (widths, heights) + } + + fn adjust_hspans( + cfg: &SpannedConfig, + len: usize, + spans: &HashMap, + heights: &mut [usize], + ) { + if spans.is_empty() { + return; + } + + let mut spans_ordered = spans + .iter() + .map(|(k, v)| ((k.0, k.1), *v)) + .collect::>(); + spans_ordered.sort_unstable_by(|(arow, acol), (brow, bcol)| match arow.cmp(brow) { + Ordering::Equal => acol.cmp(bcol), + ord => ord, + }); + + for ((row, _), (span, height)) in spans_ordered { + adjust_row_range(cfg, height, len, row, row + span, heights); + } + } + + fn adjust_row_range( + cfg: &SpannedConfig, + max_span_height: usize, + len: usize, + start: usize, + end: usize, + heights: &mut [usize], + ) { + let range_height = range_height(cfg, len, start, end, heights); + if range_height >= max_span_height { + return; + } + + inc_range(heights, max_span_height - range_height, start, end); + } + + fn range_height( + cfg: &SpannedConfig, + len: usize, + start: usize, + end: usize, + heights: &[usize], + ) -> usize { + let count_borders = count_horizontal_borders(cfg, len, start, end); + let range_height = heights[start..end].iter().sum::(); + count_borders + range_height + } + + fn count_horizontal_borders( + cfg: &SpannedConfig, + len: usize, + start: usize, + end: usize, + ) -> usize { + (start..end) + .skip(1) + .filter(|&i| cfg.has_horizontal(i, len)) + .count() + } + + fn inc_range(list: &mut [usize], size: usize, start: usize, end: usize) { + if list.is_empty() { + return; + } + + let span = end - start; + let one = size / span; + let rest = size - span * one; + + let mut i = start; + while i < end { + if i == start { + list[i] += one + rest; + } else { + list[i] += one; + } + + i += 1; + } + } + + fn adjust_vspans( + cfg: &SpannedConfig, + len: usize, + spans: &HashMap, + widths: &mut [usize], + ) { + if spans.is_empty() { + return; + } + + // The overall width distribution will be different depend on the order. + // + // We sort spans in order to prioritize the smaller spans first. + let mut spans_ordered = spans + .iter() + .map(|(k, v)| ((k.0, k.1), *v)) + .collect::>(); + spans_ordered.sort_unstable_by(|a, b| match a.1 .0.cmp(&b.1 .0) { + Ordering::Equal => a.0.cmp(&b.0), + o => o, + }); + + for ((_, col), (span, width)) in spans_ordered { + adjust_column_range(cfg, width, len, col, col + span, widths); + } + } + + fn adjust_column_range( + cfg: &SpannedConfig, + max_span_width: usize, + len: usize, + start: usize, + end: usize, + widths: &mut [usize], + ) { + let range_width = range_width(cfg, len, start, end, widths); + if range_width >= max_span_width { + return; + } + + inc_range(widths, max_span_width - range_width, start, end); + } + + fn range_width( + cfg: &SpannedConfig, + len: usize, + start: usize, + end: usize, + widths: &[usize], + ) -> usize { + let count_borders = count_vertical_borders(cfg, len, start, end); + let range_width = widths[start..end].iter().sum::(); + count_borders + range_width + } + + fn count_vertical_borders(cfg: &SpannedConfig, len: usize, start: usize, end: usize) -> usize { + (start..end) + .skip(1) + .filter(|&i| cfg.has_vertical(i, len)) + .count() + } + + pub(super) fn build_height>( + records: &VecRecords>, + cfg: &SpannedConfig, + ) -> Vec { + let mut heights = vec![]; + let mut hspans = HashMap::new(); + + for (row, columns) in records.iter_rows().enumerate() { + let mut row_height = 0; + for (col, cell) in columns.iter().enumerate() { + let pos = (row, col); + if !cfg.is_cell_visible(pos) { + continue; + } + + let height = cell.count_lines(); + match cfg.get_row_span(pos) { + Some(n) if n > 1 => { + let _ = hspans.insert(pos, (n, height)); + } + _ => row_height = max(row_height, height), + } + } + + heights.push(row_height); + } + + adjust_hspans(cfg, heights.len(), &hspans, &mut heights); + + heights + } + + pub(super) fn build_width>( + records: &VecRecords>, + cfg: &SpannedConfig, + ) -> Vec { + let count_columns = records.count_columns(); + + let mut widths = vec![0; count_columns]; + let mut vspans = HashMap::new(); + + for (row, columns) in records.iter_rows().enumerate() { + for (col, cell) in columns.iter().enumerate() { + let pos = (row, col); + if !cfg.is_cell_visible(pos) { + continue; + } + + let width = cell.width(); + match cfg.get_column_span(pos) { + Some(n) if n > 1 => { + let _ = vspans.insert(pos, (n, width)); + } + _ => widths[col] = max(widths[col], width), + } + } + } + + adjust_vspans(cfg, count_columns, &vspans, &mut widths); + + widths + } +} diff --git a/vendor/tabled/src/grid/dimension/pool_table_dimension.rs b/vendor/tabled/src/grid/dimension/pool_table_dimension.rs new file mode 100644 index 000000000..9909c661d --- /dev/null +++ b/vendor/tabled/src/grid/dimension/pool_table_dimension.rs @@ -0,0 +1,36 @@ +/// PoolTableDimension is a dimension resolve strategy for [`PoolTable`] +/// +/// [`PoolTable`]: crate::tables::PoolTable +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] +pub struct PoolTableDimension { + width: DimensionPriority, + height: DimensionPriority, +} + +impl PoolTableDimension { + /// Creates a new object. + pub fn new(width: DimensionPriority, height: DimensionPriority) -> Self { + Self { width, height } + } + + /// Return a width priority. + pub fn width(&self) -> DimensionPriority { + self.width + } + + /// Return a height priority. + pub fn height(&self) -> DimensionPriority { + self.height + } +} + +/// A control of width/height logic for situations where we must increase some cell to align columns/row. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub enum DimensionPriority { + /// Increase first cell width/height in a row/column. + First, + /// Increase last cell width/height in a row/column. + Last, + /// Increase cells width/height 1 by 1 in a row/column. + List, +} diff --git a/vendor/tabled/src/grid/dimension/static_dimension.rs b/vendor/tabled/src/grid/dimension/static_dimension.rs new file mode 100644 index 000000000..f9474f212 --- /dev/null +++ b/vendor/tabled/src/grid/dimension/static_dimension.rs @@ -0,0 +1,63 @@ +use crate::grid::dimension::{Dimension, Estimate}; + +/// A constant dimension. +#[derive(Debug, Clone)] +pub struct StaticDimension { + width: DimensionValue, + height: DimensionValue, +} + +impl StaticDimension { + /// Creates a constant dimension. + pub fn new(width: DimensionValue, height: DimensionValue) -> Self { + Self { width, height } + } +} + +impl From for (DimensionValue, DimensionValue) { + fn from(value: StaticDimension) -> Self { + (value.width, value.height) + } +} + +impl Dimension for StaticDimension { + fn get_width(&self, column: usize) -> usize { + self.width.get(column) + } + + fn get_height(&self, row: usize) -> usize { + self.height.get(row) + } +} + +impl Estimate for StaticDimension { + fn estimate(&mut self, _: R, _: &C) {} +} + +/// A dimension value. +#[derive(Debug, Clone)] +pub enum DimensionValue { + /// Const width value. + Exact(usize), + /// A list of width values for columns. + List(Vec), + /// A list of width values for columns and a value for the rest. + Partial(Vec, usize), +} + +impl DimensionValue { + /// Get a width by column. + pub fn get(&self, col: usize) -> usize { + match self { + DimensionValue::Exact(val) => *val, + DimensionValue::List(cols) => cols[col], + DimensionValue::Partial(cols, val) => { + if cols.len() > col { + cols[col] + } else { + *val + } + } + } + } +} -- cgit v1.2.3