//! 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::>() } }