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 --- vendor/tabled/src/settings/object/cell.rs | 70 +++ vendor/tabled/src/settings/object/columns.rs | 209 ++++++++ vendor/tabled/src/settings/object/frame.rs | 69 +++ vendor/tabled/src/settings/object/mod.rs | 765 +++++++++++++++++++++++++++ vendor/tabled/src/settings/object/rows.rs | 213 ++++++++ vendor/tabled/src/settings/object/segment.rs | 151 ++++++ vendor/tabled/src/settings/object/util.rs | 22 + 7 files changed, 1499 insertions(+) create mode 100644 vendor/tabled/src/settings/object/cell.rs create mode 100644 vendor/tabled/src/settings/object/columns.rs create mode 100644 vendor/tabled/src/settings/object/frame.rs create mode 100644 vendor/tabled/src/settings/object/mod.rs create mode 100644 vendor/tabled/src/settings/object/rows.rs create mode 100644 vendor/tabled/src/settings/object/segment.rs create mode 100644 vendor/tabled/src/settings/object/util.rs (limited to 'vendor/tabled/src/settings/object') diff --git a/vendor/tabled/src/settings/object/cell.rs b/vendor/tabled/src/settings/object/cell.rs new file mode 100644 index 000000000..0b0463c9a --- /dev/null +++ b/vendor/tabled/src/settings/object/cell.rs @@ -0,0 +1,70 @@ +use crate::{ + grid::config::{Entity, Position}, + settings::object::Object, +}; + +/// Cell denotes a particular cell on a [`Table`]. +/// +/// For example such table has 4 cells. +/// Which indexes are (0, 0), (0, 1), (1, 0), (1, 1). +/// +/// ```text +/// ┌───┬───┐ +/// │ 0 │ 1 │ +/// ├───┼───┤ +/// │ 1 │ 2 │ +/// └───┴───┘ +/// ``` +/// +/// [`Table`]: crate::Table +#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord)] +pub struct Cell(usize, usize); + +impl Cell { + /// Create new cell structure. + pub fn new(row: usize, col: usize) -> Self { + Self(row, col) + } +} + +impl From for Cell { + fn from((row, col): Position) -> Self { + Self(row, col) + } +} + +impl Object for Cell { + type Iter = EntityOnce; + + fn cells(&self, _: &I) -> Self::Iter { + EntityOnce::new(Some(Entity::Cell(self.0, self.1))) + } +} + +impl Object for Position { + type Iter = EntityOnce; + + fn cells(&self, _: &I) -> Self::Iter { + EntityOnce::new(Some(Entity::Cell(self.0, self.1))) + } +} + +/// An [`Iterator`] which returns an entity once. +#[derive(Debug)] +pub struct EntityOnce { + entity: Option, +} + +impl EntityOnce { + pub(crate) const fn new(entity: Option) -> Self { + Self { entity } + } +} + +impl Iterator for EntityOnce { + type Item = Entity; + + fn next(&mut self) -> Option { + self.entity.take() + } +} diff --git a/vendor/tabled/src/settings/object/columns.rs b/vendor/tabled/src/settings/object/columns.rs new file mode 100644 index 000000000..bcbe2acf5 --- /dev/null +++ b/vendor/tabled/src/settings/object/columns.rs @@ -0,0 +1,209 @@ +use std::ops::{Add, RangeBounds, Sub}; + +use crate::{ + grid::config::Entity, + grid::records::{ExactRecords, Records}, + settings::object::{cell::EntityOnce, Object}, +}; + +use super::util::bounds_to_usize; + +/// Column denotes a set of cells on given columns on a [`Table`]. +/// +/// [`Table`]: crate::Table +#[derive(Debug)] +pub struct Columns { + range: R, +} + +impl Columns { + /// Returns a new instance of [`Columns`] for a range of columns. + /// + /// If the boundaries are exceeded it may panic. + pub fn new(range: R) -> Self + where + R: RangeBounds, + { + Self { range } + } + + pub(crate) fn get_range(&self) -> &R { + &self.range + } +} + +impl Columns<()> { + /// Returns a new instance of [`Columns`] for a single column. + /// + /// If the boundaries are exceeded it may panic. + pub fn single(index: usize) -> Column { + Column(index) + } + + /// Returns a new instance of [`Columns`] for a first column. + /// + /// If the boundaries are exceeded the object will produce no cells. + pub fn first() -> FirstColumn { + FirstColumn + } + + /// Returns a new instance of [`Columns`] for a last column. + /// + /// If the boundaries are exceeded the object will produce no cells. + pub fn last() -> LastColumn { + LastColumn + } +} + +impl Object for Columns +where + R: RangeBounds, + I: Records, +{ + type Iter = ColumnsIter; + + fn cells(&self, records: &I) -> Self::Iter { + let max = records.count_columns(); + let start = self.range.start_bound(); + let end = self.range.end_bound(); + let (x, y) = bounds_to_usize(start, end, max); + + ColumnsIter::new(x, y) + } +} + +/// `FirstColumn` represents the first column on a grid. +#[derive(Debug)] +pub struct FirstColumn; + +impl Object for FirstColumn +where + I: Records + ExactRecords, +{ + type Iter = EntityOnce; + + fn cells(&self, records: &I) -> Self::Iter { + if records.count_rows() == 0 || records.count_columns() == 0 { + return EntityOnce::new(None); + } + + EntityOnce::new(Some(Entity::Column(0))) + } +} + +impl Add for FirstColumn { + type Output = Column; + + fn add(self, rhs: usize) -> Self::Output { + Column(rhs) + } +} + +/// `LastColumn` represents the last column on a grid. +#[derive(Debug)] +pub struct LastColumn; + +impl Object for LastColumn +where + I: Records + ExactRecords, +{ + type Iter = EntityOnce; + + fn cells(&self, records: &I) -> Self::Iter { + if records.count_rows() == 0 || records.count_columns() == 0 { + return EntityOnce::new(None); + } + + let col = records.count_columns().saturating_sub(1); + EntityOnce::new(Some(Entity::Column(col))) + } +} + +impl Sub for LastColumn { + type Output = LastColumnOffset; + + fn sub(self, rhs: usize) -> Self::Output { + LastColumnOffset { offset: rhs } + } +} + +/// Column represents a single column on a grid. +#[derive(Debug, Clone, Copy)] +pub struct Column(usize); + +impl Object for Column { + type Iter = EntityOnce; + + fn cells(&self, _: &I) -> Self::Iter { + EntityOnce::new(Some(Entity::Column(self.0))) + } +} + +impl From for Column { + fn from(i: usize) -> Self { + Self(i) + } +} + +impl From for usize { + fn from(val: Column) -> Self { + val.0 + } +} + +/// `LastColumnOffset` represents a single column on a grid indexed via offset from the last column. +#[derive(Debug)] +pub struct LastColumnOffset { + offset: usize, +} + +impl Object for LastColumnOffset +where + I: Records + ExactRecords, +{ + type Iter = EntityOnce; + + fn cells(&self, records: &I) -> Self::Iter { + if records.count_rows() == 0 || records.count_columns() == 0 { + return EntityOnce::new(None); + } + + let col = records.count_columns().saturating_sub(1); + if self.offset > col { + return EntityOnce::new(None); + } + + let col = col - self.offset; + EntityOnce::new(Some(Entity::Column(col))) + } +} + +/// An [`Iterator`] which goes goes over columns of a [`Table`]. +/// +/// [`Table`]: crate::Table +#[derive(Debug)] +pub struct ColumnsIter { + start: usize, + end: usize, +} + +impl ColumnsIter { + const fn new(start: usize, end: usize) -> Self { + Self { start, end } + } +} + +impl Iterator for ColumnsIter { + type Item = Entity; + + fn next(&mut self) -> Option { + if self.start >= self.end { + return None; + } + + let col = self.start; + self.start += 1; + + Some(Entity::Column(col)) + } +} diff --git a/vendor/tabled/src/settings/object/frame.rs b/vendor/tabled/src/settings/object/frame.rs new file mode 100644 index 000000000..caeb10640 --- /dev/null +++ b/vendor/tabled/src/settings/object/frame.rs @@ -0,0 +1,69 @@ +use crate::{ + grid::config::Entity, + grid::records::{ExactRecords, Records}, + settings::object::Object, +}; + +/// Frame includes cells which are on the edges of each side. +/// Therefore it's [`Object`] implementation returns a subset of cells which are present in frame. +#[derive(Debug)] +pub struct Frame; + +impl Object for Frame +where + I: Records + ExactRecords, +{ + type Iter = FrameIter; + + fn cells(&self, records: &I) -> Self::Iter { + FrameIter::new(records.count_rows(), records.count_columns()) + } +} + +/// An [`Iterator`] which goes goes over all cell on a frame of a [`Table`]. +/// +/// [`Table`]: crate::Table +#[derive(Debug)] +pub struct FrameIter { + rows: usize, + cols: usize, + row: usize, + col: usize, +} + +impl FrameIter { + const fn new(count_rows: usize, count_columns: usize) -> Self { + Self { + rows: count_rows, + cols: count_columns, + row: 0, + col: 0, + } + } +} + +impl Iterator for FrameIter { + type Item = Entity; + + fn next(&mut self) -> Option { + if self.cols == 0 || self.rows == 0 { + return None; + } + + if self.row == self.rows { + return None; + } + + let row = self.row; + let col = self.col; + + self.col += 1; + + if self.col == self.cols { + self.row += 1; + self.col = 0; + } + + Some(Entity::Cell(row, col)) + } +} diff --git a/vendor/tabled/src/settings/object/mod.rs b/vendor/tabled/src/settings/object/mod.rs new file mode 100644 index 000000000..46893c71d --- /dev/null +++ b/vendor/tabled/src/settings/object/mod.rs @@ -0,0 +1,765 @@ +//! This module contains a list of primitives that implement a [`Object`] trait. +//! They help to locate a necessary segment on a [`Table`]. +//! +//! [`Table`]: crate::Table + +mod cell; +mod columns; +mod frame; +mod rows; +mod segment; +pub(crate) mod util; + +use std::{collections::HashSet, marker::PhantomData}; + +use self::segment::SectorCellsIter; + +use crate::{ + grid::config::{Entity, EntityIterator}, + grid::records::{ExactRecords, Records}, +}; + +pub use cell::{Cell, EntityOnce}; +pub use columns::{Column, Columns, ColumnsIter, FirstColumn, LastColumn, LastColumnOffset}; +pub use frame::{Frame, FrameIter}; +pub use rows::{FirstRow, LastRow, LastRowOffset, Row, Rows, RowsIter}; +pub use segment::{SectorIter, Segment, SegmentAll}; + +/// Object helps to locate a necessary part of a [`Table`]. +/// +/// [`Table`]: crate::Table +pub trait Object { + /// An [`Iterator`] which returns a list of cells. + type Iter: Iterator; + + /// Cells returns a set of coordinates of cells. + fn cells(&self, records: &R) -> Self::Iter; + + /// Combines cells. + /// It doesn't repeat cells. + fn and(self, rhs: O) -> UnionCombination + where + Self: Sized, + { + UnionCombination::new(self, rhs) + } + + /// Excludes rhs cells from this cells. + fn not(self, rhs: O) -> DiffCombination + where + Self: Sized, + { + DiffCombination::new(self, rhs) + } + + /// Returns cells which are present in both [`Object`]s only. + fn intersect(self, rhs: O) -> IntersectionCombination + where + Self: Sized, + { + IntersectionCombination::new(self, rhs) + } + + /// Returns cells which are not present in target [`Object`]. + fn inverse(self) -> InversionCombination + where + Self: Sized, + { + InversionCombination::new(self) + } +} + +/// Combination struct used for chaining [`Object`]'s. +/// +/// Combines 2 sets of cells into one. +/// +/// Duplicates are removed from the output set. +#[derive(Debug)] +pub struct UnionCombination { + lhs: L, + rhs: R, + _records: PhantomData, +} + +impl UnionCombination { + fn new(lhs: L, rhs: R) -> Self { + Self { + lhs, + rhs, + _records: PhantomData, + } + } +} + +impl Object for UnionCombination +where + L: Object, + R: Object, + I: Records + ExactRecords, +{ + type Iter = UnionIter; + + fn cells(&self, records: &I) -> Self::Iter { + let lhs = self.lhs.cells(records); + let rhs = self.rhs.cells(records); + + UnionIter::new(lhs, rhs, records.count_rows(), records.count_columns()) + } +} + +/// Difference struct used for chaining [`Object`]'s. +/// +/// Returns cells from 1st set with removed ones from the 2nd set. +#[derive(Debug)] +pub struct DiffCombination { + lhs: L, + rhs: R, + _records: PhantomData, +} + +impl DiffCombination { + fn new(lhs: L, rhs: R) -> Self { + Self { + lhs, + rhs, + _records: PhantomData, + } + } +} + +impl Object for DiffCombination +where + L: Object, + R: Object, + I: Records + ExactRecords, +{ + type Iter = DiffIter; + + fn cells(&self, records: &I) -> Self::Iter { + let lhs = self.lhs.cells(records); + let rhs = self.rhs.cells(records); + + DiffIter::new(lhs, rhs, records.count_rows(), records.count_columns()) + } +} + +/// Intersection struct used for chaining [`Object`]'s. +/// +/// Returns cells which are present in 2 sets. +/// But not in one of them +#[derive(Debug)] +pub struct IntersectionCombination { + lhs: L, + rhs: R, + _records: PhantomData, +} + +impl IntersectionCombination { + fn new(lhs: L, rhs: R) -> Self { + Self { + lhs, + rhs, + _records: PhantomData, + } + } +} + +impl Object for IntersectionCombination +where + L: Object, + R: Object, + I: Records + ExactRecords, +{ + type Iter = IntersectIter; + + fn cells(&self, records: &I) -> Self::Iter { + let lhs = self.lhs.cells(records); + let rhs = self.rhs.cells(records); + + IntersectIter::new(lhs, rhs, records.count_rows(), records.count_columns()) + } +} + +/// Inversion struct used for chaining [`Object`]'s. +/// +/// Returns cells which are present in 2 sets. +/// But not in one of them +#[derive(Debug)] +pub struct InversionCombination { + obj: O, + _records: PhantomData, +} + +impl InversionCombination { + fn new(obj: O) -> Self { + Self { + obj, + _records: PhantomData, + } + } +} + +impl Object for InversionCombination +where + O: Object, + I: Records + ExactRecords, +{ + type Iter = InversionIter; + + fn cells(&self, records: &I) -> Self::Iter { + let obj = self.obj.cells(records); + + InversionIter::new(obj, records.count_rows(), records.count_columns()) + } +} + +/// An [`Iterator`] which goes over a combination [`Object::Iter`]. +#[derive(Debug)] +pub struct UnionIter { + lhs: Option, + rhs: R, + seen: HashSet<(usize, usize)>, + current: Option, + count_rows: usize, + count_cols: usize, +} + +impl UnionIter +where + L: Iterator, + R: Iterator, +{ + fn new(lhs: L, rhs: R, count_rows: usize, count_cols: usize) -> Self { + let size = match lhs.size_hint() { + (s1, Some(s2)) if s1 == s2 => s1, + _ => 0, + }; + + Self { + lhs: Some(lhs), + rhs, + seen: HashSet::with_capacity(size), + current: None, + count_rows, + count_cols, + } + } +} + +impl Iterator for UnionIter +where + L: Iterator, + R: Iterator, +{ + type Item = Entity; + + fn next(&mut self) -> Option { + if let Some(iter) = self.current.as_mut() { + for p in iter.by_ref() { + if self.lhs.is_none() && self.seen.contains(&p) { + continue; + } + + let _ = self.seen.insert(p); + return Some(Entity::Cell(p.0, p.1)); + } + } + + if let Some(lhs) = self.lhs.as_mut() { + for entity in lhs.by_ref() { + let mut iter = entity.iter(self.count_rows, self.count_cols); + if let Some(p) = iter.by_ref().next() { + let _ = self.seen.insert(p); + self.current = Some(iter); + return Some(Entity::Cell(p.0, p.1)); + } + } + + self.lhs = None; + } + + for entity in self.rhs.by_ref() { + let mut iter = entity.iter(self.count_rows, self.count_cols); + + for p in iter.by_ref() { + if !self.seen.contains(&p) { + let _ = self.seen.insert(p); + self.current = Some(iter); + return Some(Entity::Cell(p.0, p.1)); + } + } + } + + None + } +} + +/// An [`Iterator`] which goes over only cells which are present in first [`Object::Iter`] but not second. +#[derive(Debug)] +pub struct DiffIter { + lhs: L, + seen: HashSet<(usize, usize)>, + count_rows: usize, + count_cols: usize, + current: Option, +} + +impl DiffIter +where + L: Iterator, +{ + fn new(lhs: L, rhs: R, count_rows: usize, count_cols: usize) -> Self + where + R: Iterator, + { + let size = match rhs.size_hint() { + (s1, Some(s2)) if s1 == s2 => s1, + _ => 0, + }; + + let mut seen = HashSet::with_capacity(size); + for entity in rhs { + seen.extend(entity.iter(count_rows, count_cols)); + } + + Self { + lhs, + seen, + count_rows, + count_cols, + current: None, + } + } +} + +impl Iterator for DiffIter +where + L: Iterator, +{ + type Item = Entity; + + fn next(&mut self) -> Option { + if let Some(iter) = self.current.as_mut() { + for p in iter.by_ref() { + if !self.seen.contains(&p) { + return Some(Entity::Cell(p.0, p.1)); + } + } + } + + for entity in self.lhs.by_ref() { + let mut iter = entity.iter(self.count_rows, self.count_cols); + + for p in iter.by_ref() { + if !self.seen.contains(&p) { + self.current = Some(iter); + return Some(Entity::Cell(p.0, p.1)); + } + } + } + + None + } +} + +/// An [`Iterator`] which goes goes over cells which are present in both [`Object::Iter`]ators. +#[derive(Debug)] +pub struct IntersectIter { + lhs: L, + seen: HashSet<(usize, usize)>, + count_rows: usize, + count_cols: usize, + current: Option, +} + +impl IntersectIter +where + L: Iterator, +{ + fn new(lhs: L, rhs: R, count_rows: usize, count_cols: usize) -> Self + where + R: Iterator, + { + let size = match rhs.size_hint() { + (s1, Some(s2)) if s1 == s2 => s1, + _ => 0, + }; + + let mut seen = HashSet::with_capacity(size); + for entity in rhs { + seen.extend(entity.iter(count_rows, count_cols)); + } + + Self { + lhs, + seen, + count_rows, + count_cols, + current: None, + } + } +} + +impl Iterator for IntersectIter +where + L: Iterator, +{ + type Item = Entity; + + fn next(&mut self) -> Option { + if let Some(iter) = self.current.as_mut() { + for p in iter.by_ref() { + if self.seen.contains(&p) { + return Some(Entity::Cell(p.0, p.1)); + } + } + } + + for entity in self.lhs.by_ref() { + let mut iter = entity.iter(self.count_rows, self.count_cols); + + for p in iter.by_ref() { + if self.seen.contains(&p) { + self.current = Some(iter); + return Some(Entity::Cell(p.0, p.1)); + } + } + } + + None + } +} + +/// An [`Iterator`] which goes goes over cells which are not present an [`Object::Iter`]ator. +#[derive(Debug)] +pub struct InversionIter { + all: SectorCellsIter, + seen: HashSet<(usize, usize)>, +} + +impl InversionIter { + fn new(obj: O, count_rows: usize, count_columns: usize) -> Self + where + O: Iterator, + { + let size = match obj.size_hint() { + (s1, Some(s2)) if s1 == s2 => s1, + _ => 0, + }; + + let mut seen = HashSet::with_capacity(size); + for entity in obj { + seen.extend(entity.iter(count_rows, count_columns)); + } + + let all = SectorCellsIter::new(0, count_rows, 0, count_columns); + + Self { all, seen } + } +} + +impl Iterator for InversionIter { + type Item = Entity; + + fn next(&mut self) -> Option { + for p in self.all.by_ref() { + if !self.seen.contains(&p) { + return Some(Entity::Cell(p.0, p.1)); + } + } + + None + } +} + +#[cfg(test)] +mod tests { + use crate::grid::records::vec_records::VecRecords; + + use super::*; + + #[test] + fn cell_test() { + assert_eq!(vec_cells((0, 0), 2, 3), [Entity::Cell(0, 0)]); + assert_eq!(vec_cells((1, 1), 2, 3), [Entity::Cell(1, 1)]); + assert_eq!(vec_cells((1, 1), 0, 0), [Entity::Cell(1, 1)]); + assert_eq!(vec_cells((1, 100), 2, 3), [Entity::Cell(1, 100)]); + assert_eq!(vec_cells((100, 1), 2, 3), [Entity::Cell(100, 1)]); + } + + #[test] + fn columns_test() { + assert_eq!( + vec_cells(Columns::new(..), 2, 3), + [Entity::Column(0), Entity::Column(1), Entity::Column(2)] + ); + assert_eq!( + vec_cells(Columns::new(1..), 2, 3), + [Entity::Column(1), Entity::Column(2)] + ); + assert_eq!(vec_cells(Columns::new(2..), 2, 3), [Entity::Column(2)]); + assert_eq!(vec_cells(Columns::new(3..), 2, 3), []); + assert_eq!(vec_cells(Columns::new(3..), 0, 0), []); + assert_eq!(vec_cells(Columns::new(0..1), 2, 3), [Entity::Column(0)]); + assert_eq!(vec_cells(Columns::new(1..2), 2, 3), [Entity::Column(1)]); + assert_eq!(vec_cells(Columns::new(2..3), 2, 3), [Entity::Column(2)]); + assert_eq!(vec_cells(Columns::new(..), 0, 0), []); + assert_eq!(vec_cells(Columns::new(..), 2, 0), []); + assert_eq!(vec_cells(Columns::new(..), 0, 3), []); + } + + #[test] + fn first_column_test() { + assert_eq!(vec_cells(Columns::first(), 5, 2), [Entity::Column(0)]); + assert_eq!(vec_cells(Columns::first(), 0, 0), []); + assert_eq!(vec_cells(Columns::first(), 10, 0), []); + assert_eq!(vec_cells(Columns::first(), 0, 10), []); + } + + #[test] + fn last_column_test() { + assert_eq!(vec_cells(Columns::last(), 5, 2), [Entity::Column(1)]); + assert_eq!(vec_cells(Columns::last(), 5, 29), [Entity::Column(28)]); + assert_eq!(vec_cells(Columns::last(), 0, 0), []); + assert_eq!(vec_cells(Columns::last(), 10, 0), []); + assert_eq!(vec_cells(Columns::last(), 0, 10), []); + } + + #[test] + fn last_column_sub_test() { + assert_eq!(vec_cells(Columns::last(), 5, 2), [Entity::Column(1)]); + assert_eq!(vec_cells(Columns::last() - 0, 5, 2), [Entity::Column(1)]); + assert_eq!(vec_cells(Columns::last() - 1, 5, 2), [Entity::Column(0)]); + assert_eq!(vec_cells(Columns::last() - 2, 5, 2), []); + assert_eq!(vec_cells(Columns::last() - 100, 5, 2), []); + } + + #[test] + fn first_column_add_test() { + assert_eq!(vec_cells(Columns::first(), 5, 2), [Entity::Column(0)]); + assert_eq!(vec_cells(Columns::first() + 0, 5, 2), [Entity::Column(0)]); + assert_eq!(vec_cells(Columns::first() + 1, 5, 2), [Entity::Column(1)]); + assert_eq!(vec_cells(Columns::first() + 2, 5, 2), [Entity::Column(2)]); + assert_eq!( + vec_cells(Columns::first() + 100, 5, 2), + [Entity::Column(100)] + ); + } + + #[test] + fn rows_test() { + assert_eq!( + vec_cells(Rows::new(..), 2, 3), + [Entity::Row(0), Entity::Row(1)] + ); + assert_eq!(vec_cells(Rows::new(1..), 2, 3), [Entity::Row(1)]); + assert_eq!(vec_cells(Rows::new(2..), 2, 3), []); + assert_eq!(vec_cells(Rows::new(2..), 0, 0), []); + assert_eq!(vec_cells(Rows::new(0..1), 2, 3), [Entity::Row(0)],); + assert_eq!(vec_cells(Rows::new(1..2), 2, 3), [Entity::Row(1)],); + assert_eq!(vec_cells(Rows::new(..), 0, 0), []); + assert_eq!(vec_cells(Rows::new(..), 0, 3), []); + assert_eq!( + vec_cells(Rows::new(..), 2, 0), + [Entity::Row(0), Entity::Row(1)] + ); + } + + #[test] + fn last_row_test() { + assert_eq!(vec_cells(Rows::last(), 5, 2), [Entity::Row(4)]); + assert_eq!(vec_cells(Rows::last(), 100, 2), [Entity::Row(99)]); + assert_eq!(vec_cells(Rows::last(), 0, 0), []); + assert_eq!(vec_cells(Rows::last(), 5, 0), []); + assert_eq!(vec_cells(Rows::last(), 0, 2), []); + } + + #[test] + fn first_row_test() { + assert_eq!(vec_cells(Rows::first(), 5, 2), [Entity::Row(0)]); + assert_eq!(vec_cells(Rows::first(), 100, 2), [Entity::Row(0)]); + assert_eq!(vec_cells(Rows::first(), 0, 0), []); + assert_eq!(vec_cells(Rows::first(), 5, 0), []); + assert_eq!(vec_cells(Rows::first(), 0, 2), []); + } + + #[test] + fn last_row_sub_test() { + assert_eq!(vec_cells(Rows::last(), 5, 2), [Entity::Row(4)]); + assert_eq!(vec_cells(Rows::last() - 0, 5, 2), [Entity::Row(4)]); + assert_eq!(vec_cells(Rows::last() - 1, 5, 2), [Entity::Row(3)]); + assert_eq!(vec_cells(Rows::last() - 2, 5, 2), [Entity::Row(2)]); + assert_eq!(vec_cells(Rows::last() - 3, 5, 2), [Entity::Row(1)]); + assert_eq!(vec_cells(Rows::last() - 4, 5, 2), [Entity::Row(0)]); + assert_eq!(vec_cells(Rows::last() - 5, 5, 2), []); + assert_eq!(vec_cells(Rows::last() - 100, 5, 2), []); + assert_eq!(vec_cells(Rows::last() - 1, 0, 0), []); + assert_eq!(vec_cells(Rows::last() - 1, 5, 0), []); + assert_eq!(vec_cells(Rows::last() - 1, 0, 2), []); + } + + #[test] + fn first_row_add_test() { + assert_eq!(vec_cells(Rows::first(), 5, 2), [Entity::Row(0)]); + assert_eq!(vec_cells(Rows::first() + 0, 5, 2), [Entity::Row(0)]); + assert_eq!(vec_cells(Rows::first() + 1, 5, 2), [Entity::Row(1)]); + assert_eq!(vec_cells(Rows::first() + 2, 5, 2), [Entity::Row(2)]); + assert_eq!(vec_cells(Rows::first() + 3, 5, 2), [Entity::Row(3)]); + assert_eq!(vec_cells(Rows::first() + 4, 5, 2), [Entity::Row(4)]); + assert_eq!(vec_cells(Rows::first() + 5, 5, 2), [Entity::Row(5)]); + assert_eq!(vec_cells(Rows::first() + 100, 5, 2), [Entity::Row(100)]); + assert_eq!(vec_cells(Rows::first() + 1, 0, 0), [Entity::Row(1)]); + assert_eq!(vec_cells(Rows::first() + 1, 5, 0), [Entity::Row(1)]); + assert_eq!(vec_cells(Rows::first() + 1, 0, 2), [Entity::Row(1)]); + } + + #[test] + fn frame_test() { + assert_eq!( + vec_cells(Frame, 2, 3), + [ + Entity::Cell(0, 0), + Entity::Cell(0, 1), + Entity::Cell(0, 2), + Entity::Cell(1, 0), + Entity::Cell(1, 1), + Entity::Cell(1, 2) + ] + ); + assert_eq!(vec_cells(Frame, 0, 0), []); + assert_eq!(vec_cells(Frame, 2, 0), []); + assert_eq!(vec_cells(Frame, 0, 2), []); + } + + #[test] + fn segment_test() { + assert_eq!( + vec_cells(Segment::new(.., ..), 2, 3), + [ + Entity::Cell(0, 0), + Entity::Cell(0, 1), + Entity::Cell(0, 2), + Entity::Cell(1, 0), + Entity::Cell(1, 1), + Entity::Cell(1, 2) + ] + ); + assert_eq!( + vec_cells(Segment::new(1.., ..), 2, 3), + [Entity::Cell(1, 0), Entity::Cell(1, 1), Entity::Cell(1, 2)] + ); + assert_eq!(vec_cells(Segment::new(2.., ..), 2, 3), []); + + assert_eq!( + vec_cells(Segment::new(.., 1..), 2, 3), + [ + Entity::Cell(0, 1), + Entity::Cell(0, 2), + Entity::Cell(1, 1), + Entity::Cell(1, 2) + ] + ); + assert_eq!( + vec_cells(Segment::new(.., 2..), 2, 3), + [Entity::Cell(0, 2), Entity::Cell(1, 2)] + ); + assert_eq!(vec_cells(Segment::new(.., 3..), 2, 3), []); + + assert_eq!( + vec_cells(Segment::new(1.., 1..), 2, 3), + [Entity::Cell(1, 1), Entity::Cell(1, 2)] + ); + assert_eq!( + vec_cells(Segment::new(1..2, 1..2), 2, 3), + [Entity::Cell(1, 1)] + ); + + assert_eq!(vec_cells(Segment::new(5.., 5..), 2, 3), []); + } + + #[test] + fn object_and_test() { + assert_eq!( + vec_cells(Cell::new(0, 0).and(Cell::new(0, 0)), 2, 3), + [Entity::Cell(0, 0)] + ); + assert_eq!( + vec_cells(Cell::new(0, 0).and(Cell::new(1, 2)), 2, 3), + [Entity::Cell(0, 0), Entity::Cell(1, 2)] + ); + assert_eq!(vec_cells(Cell::new(0, 0).and(Cell::new(1, 2)), 0, 0), []); + } + + #[test] + fn object_not_test() { + assert_eq!(vec_cells(Rows::first().not(Cell::new(0, 0)), 0, 0), []); + assert_eq!(vec_cells(Cell::new(0, 0).not(Cell::new(0, 0)), 2, 3), []); + assert_eq!( + vec_cells(Rows::first().not(Cell::new(0, 0)), 2, 3), + [Entity::Cell(0, 1), Entity::Cell(0, 2)] + ); + assert_eq!( + vec_cells(Columns::single(1).not(Rows::single(1)), 3, 3), + [Entity::Cell(0, 1), Entity::Cell(2, 1)] + ); + assert_eq!( + vec_cells(Rows::single(1).not(Columns::single(1)), 3, 3), + [Entity::Cell(1, 0), Entity::Cell(1, 2)] + ); + } + + #[test] + fn object_intersect_test() { + assert_eq!( + vec_cells(Rows::first().intersect(Cell::new(0, 0)), 0, 0), + [] + ); + assert_eq!( + vec_cells(Segment::all().intersect(Rows::single(1)), 2, 3), + [Entity::Cell(1, 0), Entity::Cell(1, 1), Entity::Cell(1, 2)] + ); + assert_eq!( + vec_cells(Cell::new(0, 0).intersect(Cell::new(0, 0)), 2, 3), + [Entity::Cell(0, 0)] + ); + assert_eq!( + vec_cells(Rows::first().intersect(Cell::new(0, 0)), 2, 3), + [Entity::Cell(0, 0)] + ); + // maybe we somehow shall not limit the rows/columns by the max count? + assert_eq!( + vec_cells(Rows::single(1).intersect(Columns::single(1)), 2, 1), + [] + ); + } + + #[test] + fn object_inverse_test() { + assert_eq!(vec_cells(Segment::all().inverse(), 2, 3), []); + assert_eq!( + vec_cells(Cell::new(0, 0).inverse(), 2, 3), + [ + Entity::Cell(0, 1), + Entity::Cell(0, 2), + Entity::Cell(1, 0), + Entity::Cell(1, 1), + Entity::Cell(1, 2) + ] + ); + assert_eq!( + vec_cells(Rows::first().inverse(), 2, 3), + [Entity::Cell(1, 0), Entity::Cell(1, 1), Entity::Cell(1, 2)] + ); + assert_eq!(vec_cells(Rows::first().inverse(), 0, 0), []); + } + + fn vec_cells>>( + o: O, + count_rows: usize, + count_cols: usize, + ) -> Vec { + let data = vec![vec![String::default(); count_cols]; count_rows]; + let records = VecRecords::new(data); + o.cells(&records).collect::>() + } +} diff --git a/vendor/tabled/src/settings/object/rows.rs b/vendor/tabled/src/settings/object/rows.rs new file mode 100644 index 000000000..b32e79ad5 --- /dev/null +++ b/vendor/tabled/src/settings/object/rows.rs @@ -0,0 +1,213 @@ +use std::ops::{Add, RangeBounds, Sub}; + +use crate::{ + grid::config::Entity, + grid::records::{ExactRecords, Records}, + settings::object::{cell::EntityOnce, Object}, +}; + +use super::util::bounds_to_usize; + +/// Row denotes a set of cells on given rows on a [`Table`]. +/// +/// [`Table`]: crate::Table +#[derive(Debug)] +pub struct Rows { + range: R, +} + +impl Rows { + /// Returns a new instance of [`Rows`] for a range of rows. + /// + /// If the boundaries are exceeded it may panic. + pub fn new(range: R) -> Self + where + R: RangeBounds, + { + Self { range } + } + + pub(crate) const fn get_range(&self) -> &R { + &self.range + } +} + +impl Rows<()> { + /// Returns a new instance of [`Rows`] with a single row. + /// + /// If the boundaries are exceeded it may panic. + pub const fn single(index: usize) -> Row { + Row { index } + } + + /// Returns a first row [`Object`]. + /// + /// If the table has 0 rows returns an empty set of cells. + pub const fn first() -> FirstRow { + FirstRow + } + + /// Returns a last row [`Object`]. + /// + /// If the table has 0 rows returns an empty set of cells. + pub const fn last() -> LastRow { + LastRow + } +} + +impl Object for Rows +where + R: RangeBounds, + I: ExactRecords, +{ + type Iter = RowsIter; + + fn cells(&self, records: &I) -> Self::Iter { + let start = self.range.start_bound(); + let end = self.range.end_bound(); + let max = records.count_rows(); + let (x, y) = bounds_to_usize(start, end, max); + + RowsIter::new(x, y) + } +} + +/// A row which is located by an offset from the first row. +#[derive(Debug, Clone, Copy)] +pub struct Row { + index: usize, +} + +impl Object for Row { + type Iter = EntityOnce; + + fn cells(&self, _: &I) -> Self::Iter { + EntityOnce::new(Some(Entity::Row(self.index))) + } +} + +impl From for usize { + fn from(val: Row) -> Self { + val.index + } +} + +/// This structure represents the first row of a [`Table`]. +/// It's often contains headers data. +/// +/// [`Table`]: crate::Table +#[derive(Debug)] +pub struct FirstRow; + +impl Object for FirstRow +where + I: Records + ExactRecords, +{ + type Iter = EntityOnce; + + fn cells(&self, records: &I) -> Self::Iter { + if records.count_columns() == 0 || records.count_rows() == 0 { + return EntityOnce::new(None); + } + + EntityOnce::new(Some(Entity::Row(0))) + } +} + +impl Add for FirstRow { + type Output = Row; + + fn add(self, rhs: usize) -> Self::Output { + Row { index: rhs } + } +} + +/// This structure represents the last row of a [`Table`]. +/// +/// [`Table`]: crate::Table +#[derive(Debug)] +pub struct LastRow; + +impl Object for LastRow +where + I: Records + ExactRecords, +{ + type Iter = EntityOnce; + + fn cells(&self, records: &I) -> Self::Iter { + let count_rows = records.count_rows(); + if records.count_columns() == 0 || count_rows == 0 { + return EntityOnce::new(None); + } + + let row = if count_rows == 0 { 0 } else { count_rows - 1 }; + + EntityOnce::new(Some(Entity::Row(row))) + } +} + +impl Sub for LastRow { + type Output = LastRowOffset; + + fn sub(self, rhs: usize) -> Self::Output { + LastRowOffset { offset: rhs } + } +} + +/// A row which is located by an offset from the last row. +#[derive(Debug)] +pub struct LastRowOffset { + offset: usize, +} + +impl Object for LastRowOffset +where + I: Records + ExactRecords, +{ + type Iter = EntityOnce; + + fn cells(&self, records: &I) -> Self::Iter { + let count_rows = records.count_rows(); + if records.count_columns() == 0 || count_rows == 0 { + return EntityOnce::new(None); + } + + let row = if count_rows == 0 { 0 } else { count_rows - 1 }; + if self.offset > row { + return EntityOnce::new(None); + } + + let row = row - self.offset; + EntityOnce::new(Some(Entity::Row(row))) + } +} + +/// An [`Iterator`] which goes goes over all rows of a [`Table`]. +/// +/// [`Table`]: crate::Table +#[derive(Debug)] +pub struct RowsIter { + start: usize, + end: usize, +} + +impl RowsIter { + const fn new(start: usize, end: usize) -> Self { + Self { start, end } + } +} + +impl Iterator for RowsIter { + type Item = Entity; + + fn next(&mut self) -> Option { + if self.start >= self.end { + return None; + } + + let col = self.start; + self.start += 1; + + Some(Entity::Row(col)) + } +} diff --git a/vendor/tabled/src/settings/object/segment.rs b/vendor/tabled/src/settings/object/segment.rs new file mode 100644 index 000000000..9b59ada47 --- /dev/null +++ b/vendor/tabled/src/settings/object/segment.rs @@ -0,0 +1,151 @@ +use std::ops::{RangeBounds, RangeFull}; + +use crate::{ + grid::config::Entity, + grid::records::{ExactRecords, Records}, + settings::object::{cell::EntityOnce, Object}, +}; + +use super::util::bounds_to_usize; + +/// This structure represents a sub table of [`Table`]. +/// +/// [`Table`]: crate::Table +#[derive(Debug)] +pub struct Segment { + columns: C, + rows: R, +} + +impl Segment { + /// Returns a table segment on which are present all cells. + pub fn all() -> SegmentAll { + SegmentAll + } +} + +impl Segment +where + C: RangeBounds, + R: RangeBounds, +{ + /// This function builds a [`Segment`]. + pub fn new(rows: R, columns: C) -> Self { + Self { columns, rows } + } +} + +impl Object for Segment +where + C: RangeBounds, + R: RangeBounds, + I: Records + ExactRecords, +{ + type Iter = SectorIter; + + fn cells(&self, records: &I) -> Self::Iter { + let start = self.rows.start_bound(); + let end = self.rows.end_bound(); + let max = records.count_rows(); + let (rows_start, rows_end) = bounds_to_usize(start, end, max); + + let start = self.columns.start_bound(); + let end = self.columns.end_bound(); + let max = records.count_columns(); + let (cols_start, cols_end) = bounds_to_usize(start, end, max); + + SectorIter::new(rows_start, rows_end, cols_start, cols_end) + } +} + +/// This is a segment which contains all cells on the table. +/// +/// Can be created from [`Segment::all`]. +#[derive(Debug)] +pub struct SegmentAll; + +impl Object for SegmentAll { + type Iter = EntityOnce; + + fn cells(&self, _: &I) -> Self::Iter { + EntityOnce::new(Some(Entity::Global)) + } +} + +/// An [`Iterator`] which goes goes over all cell in a sector in a [`Table`]. +/// +/// [`Table`]: crate::Table +#[derive(Debug)] +pub struct SectorIter { + iter: SectorCellsIter, +} + +impl SectorIter { + const fn new(rows_start: usize, rows_end: usize, cols_start: usize, cols_end: usize) -> Self { + Self { + iter: SectorCellsIter::new(rows_start, rows_end, cols_start, cols_end), + } + } +} + +impl Iterator for SectorIter { + type Item = Entity; + + fn next(&mut self) -> Option { + let (row, col) = self.iter.next()?; + Some(Entity::Cell(row, col)) + } +} + +#[derive(Debug)] +pub(crate) struct SectorCellsIter { + rows_end: usize, + cols_start: usize, + cols_end: usize, + row: usize, + col: usize, +} + +impl SectorCellsIter { + /// Create an iterator from 1st row to last from 1st col to last. + pub(crate) const fn new( + rows_start: usize, + rows_end: usize, + cols_start: usize, + cols_end: usize, + ) -> Self { + Self { + rows_end, + cols_start, + cols_end, + row: rows_start, + col: cols_start, + } + } +} + +impl Iterator for SectorCellsIter { + type Item = (usize, usize); + + fn next(&mut self) -> Option { + if self.row >= self.rows_end { + return None; + } + + if self.col >= self.cols_end { + return None; + } + + let row = self.row; + let col = self.col; + + self.col += 1; + + if self.col == self.cols_end { + self.row += 1; + self.col = self.cols_start; + } + + Some((row, col)) + } +} diff --git a/vendor/tabled/src/settings/object/util.rs b/vendor/tabled/src/settings/object/util.rs new file mode 100644 index 000000000..94ca20e86 --- /dev/null +++ b/vendor/tabled/src/settings/object/util.rs @@ -0,0 +1,22 @@ +use std::ops::Bound; + +/// Converts a range bound to its indexes. +pub(super) fn bounds_to_usize( + left: Bound<&usize>, + right: Bound<&usize>, + count_elements: usize, +) -> (usize, usize) { + match (left, right) { + (Bound::Included(x), Bound::Included(y)) => (*x, y + 1), + (Bound::Included(x), Bound::Excluded(y)) => (*x, *y), + (Bound::Included(x), Bound::Unbounded) => (*x, count_elements), + (Bound::Unbounded, Bound::Unbounded) => (0, count_elements), + (Bound::Unbounded, Bound::Included(y)) => (0, y + 1), + (Bound::Unbounded, Bound::Excluded(y)) => (0, *y), + (Bound::Excluded(_), Bound::Unbounded) + | (Bound::Excluded(_), Bound::Included(_)) + | (Bound::Excluded(_), Bound::Excluded(_)) => { + unreachable!("A start bound can't be excluded") + } + } +} -- cgit v1.2.3