blob: 46893c71d2c985b97302222bf8ff3fcd9cbccc99 [file] [log] [blame]
//! 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<R> {
/// An [`Iterator`] which returns a list of cells.
type Iter: Iterator<Item = Entity>;
/// Cells returns a set of coordinates of cells.
fn cells(&self, records: &R) -> Self::Iter;
/// Combines cells.
/// It doesn't repeat cells.
fn and<O>(self, rhs: O) -> UnionCombination<Self, O, R>
where
Self: Sized,
{
UnionCombination::new(self, rhs)
}
/// Excludes rhs cells from this cells.
fn not<O>(self, rhs: O) -> DiffCombination<Self, O, R>
where
Self: Sized,
{
DiffCombination::new(self, rhs)
}
/// Returns cells which are present in both [`Object`]s only.
fn intersect<O>(self, rhs: O) -> IntersectionCombination<Self, O, R>
where
Self: Sized,
{
IntersectionCombination::new(self, rhs)
}
/// Returns cells which are not present in target [`Object`].
fn inverse(self) -> InversionCombination<Self, R>
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<L, R, I> {
lhs: L,
rhs: R,
_records: PhantomData<I>,
}
impl<L, R, I> UnionCombination<L, R, I> {
fn new(lhs: L, rhs: R) -> Self {
Self {
lhs,
rhs,
_records: PhantomData,
}
}
}
impl<I, L, R> Object<I> for UnionCombination<L, R, I>
where
L: Object<I>,
R: Object<I>,
I: Records + ExactRecords,
{
type Iter = UnionIter<L::Iter, R::Iter>;
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<L, R, I> {
lhs: L,
rhs: R,
_records: PhantomData<I>,
}
impl<L, R, I> DiffCombination<L, R, I> {
fn new(lhs: L, rhs: R) -> Self {
Self {
lhs,
rhs,
_records: PhantomData,
}
}
}
impl<I, L, R> Object<I> for DiffCombination<L, R, I>
where
L: Object<I>,
R: Object<I>,
I: Records + ExactRecords,
{
type Iter = DiffIter<L::Iter>;
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<L, R, I> {
lhs: L,
rhs: R,
_records: PhantomData<I>,
}
impl<L, R, I> IntersectionCombination<L, R, I> {
fn new(lhs: L, rhs: R) -> Self {
Self {
lhs,
rhs,
_records: PhantomData,
}
}
}
impl<I, L, R> Object<I> for IntersectionCombination<L, R, I>
where
L: Object<I>,
R: Object<I>,
I: Records + ExactRecords,
{
type Iter = IntersectIter<L::Iter>;
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<O, I> {
obj: O,
_records: PhantomData<I>,
}
impl<O, I> InversionCombination<O, I> {
fn new(obj: O) -> Self {
Self {
obj,
_records: PhantomData,
}
}
}
impl<I, O> Object<I> for InversionCombination<O, I>
where
O: Object<I>,
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<L, R> {
lhs: Option<L>,
rhs: R,
seen: HashSet<(usize, usize)>,
current: Option<EntityIterator>,
count_rows: usize,
count_cols: usize,
}
impl<L, R> UnionIter<L, R>
where
L: Iterator<Item = Entity>,
R: Iterator<Item = Entity>,
{
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<L, R> Iterator for UnionIter<L, R>
where
L: Iterator<Item = Entity>,
R: Iterator<Item = Entity>,
{
type Item = Entity;
fn next(&mut self) -> Option<Self::Item> {
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<L> {
lhs: L,
seen: HashSet<(usize, usize)>,
count_rows: usize,
count_cols: usize,
current: Option<EntityIterator>,
}
impl<L> DiffIter<L>
where
L: Iterator<Item = Entity>,
{
fn new<R>(lhs: L, rhs: R, count_rows: usize, count_cols: usize) -> Self
where
R: Iterator<Item = Entity>,
{
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<L> Iterator for DiffIter<L>
where
L: Iterator<Item = Entity>,
{
type Item = Entity;
fn next(&mut self) -> Option<Self::Item> {
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<L> {
lhs: L,
seen: HashSet<(usize, usize)>,
count_rows: usize,
count_cols: usize,
current: Option<EntityIterator>,
}
impl<L> IntersectIter<L>
where
L: Iterator<Item = Entity>,
{
fn new<R>(lhs: L, rhs: R, count_rows: usize, count_cols: usize) -> Self
where
R: Iterator<Item = Entity>,
{
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<L> Iterator for IntersectIter<L>
where
L: Iterator<Item = Entity>,
{
type Item = Entity;
fn next(&mut self) -> Option<Self::Item> {
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<O>(obj: O, count_rows: usize, count_columns: usize) -> Self
where
O: Iterator<Item = Entity>,
{
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<Self::Item> {
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: Object<VecRecords<String>>>(
o: O,
count_rows: usize,
count_cols: usize,
) -> Vec<Entity> {
let data = vec![vec![String::default(); count_cols]; count_rows];
let records = VecRecords::new(data);
o.cells(&records).collect::<Vec<_>>()
}
}