Repository: zhiburt/tabled
Pull request #145 (2022-05-21 12:44:09)

tabled/ Refactoring `Object`


Patch:
diff --git a/src/highlight.rs b/src/highlight.rs
index 66a0ca3..96d8bab 100644
--- a/src/highlight.rs
+++ b/src/highlight.rs
@@ -123,7 +123,7 @@ where
     }
 }
 
-fn split_segments(cells: Vec<(usize, usize)>) -> Vec<HashSet<(usize, usize)>> {
+fn split_segments(cells: impl Iterator<Item = (usize, usize)>) -> Vec<HashSet<(usize, usize)>> {
     let mut segments: Vec<HashSet<(usize, usize)>> = Vec::new();
     for cell in cells {
         let found_segment = segments
diff --git a/src/object.rs b/src/object.rs
index fe9f321..c94b181 100644
--- a/src/object.rs
+++ b/src/object.rs
@@ -4,7 +4,7 @@
 //! [Table]: crate::Table
 
 use std::{
-    collections::BTreeSet,
+    collections::HashSet,
     ops::{Add, Bound, RangeBounds, RangeFull, Sub},
 };
 
@@ -12,26 +12,20 @@ use std::{
 ///
 /// [Table]: crate::Table
 pub trait Object: Sized {
+    type Iter: Iterator<Item = (usize, usize)>;
+
     /// Cells returns a set of cordinates of cells
-    fn cells(&self, count_rows: usize, count_columns: usize) -> Vec<(usize, usize)>;
+    fn cells(&self, count_rows: usize, count_columns: usize) -> Self::Iter;
 
     /// Combines cells.
     /// It doesn't repeat cells.
-    fn and<O: Object>(self, rhs: O) -> Combination<Self, O> {
-        Combination {
-            lhs: self,
-            rhs,
-            combinator: combine_cells,
-        }
+    fn and<O: Object>(self, rhs: O) -> UntionCombination<Self, O> {
+        UntionCombination { lhs: self, rhs }
     }
 
     /// Excludes rhs cells from this cells.
-    fn not<O: Object>(self, rhs: O) -> Combination<Self, O> {
-        Combination {
-            lhs: self,
-            rhs,
-            combinator: remove_cells,
-        }
+    fn not<O: Object>(self, rhs: O) -> DiffCombination<Self, O> {
+        DiffCombination { lhs: self, rhs }
     }
 }
 
@@ -68,21 +62,19 @@ where
     C: RangeBounds<usize>,
     R: RangeBounds<usize>,
 {
-    fn cells(&self, count_rows: usize, count_columns: usize) -> Vec<(usize, usize)> {
+    type Iter = SectorIter;
+
+    fn cells(&self, count_rows: usize, count_columns: usize) -> Self::Iter {
         let (rows_start, rows_end) =
             bounds_to_usize(self.rows.start_bound(), self.rows.end_bound(), count_rows);
 
-        let (columns_start, columns_end) = bounds_to_usize(
+        let (cols_start, cols_end) = bounds_to_usize(
             self.columns.start_bound(),
             self.columns.end_bound(),
             count_columns,
         );
 
-        let mut cells = Vec::new();
-        (rows_start..rows_end)
-            .for_each(|row| (columns_start..columns_end).for_each(|col| cells.push((row, col))));
-
-        cells
+        SectorIter::new(rows_start, rows_end, cols_start, cols_end)
     }
 }
 
@@ -91,30 +83,10 @@ where
 pub struct Frame;
 
 impl Object for Frame {
-    fn cells(&self, count_rows: usize, count_columns: usize) -> Vec<(usize, usize)> {
-        let mut cells = Vec::new();
+    type Iter = FrameIter;
 
-        if count_rows > 0 {
-            (0..count_columns).for_each(|col| {
-                cells.push((0, col));
-            });
-
-            (0..count_columns).for_each(|col| {
-                cells.push((count_rows - 1, col));
-            });
-        }
-
-        if count_columns > 0 {
-            (0..count_rows).for_each(|row| {
-                cells.push((row, 0));
-            });
-
-            (0..count_rows).for_each(|row| {
-                cells.push((row, count_columns - 1));
-            });
-        }
-
-        cells
+    fn cells(&self, count_rows: usize, count_columns: usize) -> Self::Iter {
+        FrameIter::new(count_rows, count_columns)
     }
 }
 
@@ -125,8 +97,10 @@ impl Object for Frame {
 pub struct FirstRow;
 
 impl Object for FirstRow {
-    fn cells(&self, _: usize, count_columns: usize) -> Vec<(usize, usize)> {
-        (0..count_columns).map(|column| (0, column)).collect()
+    type Iter = RowIter;
+
+    fn cells(&self, _: usize, count_columns: usize) -> Self::Iter {
+        RowIter::new(0, count_columns)
     }
 }
 
@@ -144,9 +118,11 @@ impl Add<usize> for FirstRow {
 pub struct LastRow;
 
 impl Object for LastRow {
-    fn cells(&self, count_rows: usize, count_columns: usize) -> Vec<(usize, usize)> {
+    type Iter = RowIter;
+
+    fn cells(&self, count_rows: usize, count_columns: usize) -> Self::Iter {
         let row = if count_rows == 0 { 0 } else { count_rows - 1 };
-        (0..count_columns).map(|column| (row, column)).collect()
+        RowIter::new(row, count_columns)
     }
 }
 
@@ -164,14 +140,14 @@ pub struct Row {
 }
 
 impl Object for Row {
-    fn cells(&self, count_rows: usize, count_columns: usize) -> Vec<(usize, usize)> {
+    type Iter = RowIter;
+
+    fn cells(&self, count_rows: usize, count_columns: usize) -> Self::Iter {
         if self.index >= count_rows {
-            return Vec::new();
+            return RowIter::new(0, 0);
         }
 
-        (0..count_columns)
-            .map(|column| (self.index, column))
-            .collect()
+        RowIter::new(self.index, count_columns)
     }
 }
 
@@ -181,29 +157,16 @@ pub struct LastRowOffset {
 }
 
 impl Object for LastRowOffset {
-    fn cells(&self, count_rows: usize, count_columns: usize) -> Vec<(usize, usize)> {
+    type Iter = RowIter;
+
+    fn cells(&self, count_rows: usize, count_columns: usize) -> Self::Iter {
         let row = if count_rows == 0 { 0 } else { count_rows - 1 };
         if self.offset > row {
-            return Vec::new();
+            return RowIter::new(0, 0);
         }
 
         let row = row - self.offset;
-        (0..count_columns).map(|column| (row, column)).collect()
-    }
-}
-
-/// Full represents all cells on a [Table].
-///
-/// [Table]: crate::Table
-#[deprecated(
-    note = "It was replaced because the name is not descriptive. Use Segment::all() instead."
-)]
-pub struct Full;
-
-#[allow(deprecated)]
-impl Object for Full {
-    fn cells(&self, count_rows: usize, count_columns: usize) -> Vec<(usize, usize)> {
-        Segment::new(.., ..).cells(count_rows, count_columns)
+        RowIter::new(row, count_columns)
     }
 }
 
@@ -253,13 +216,12 @@ impl<R> Object for Rows<R>
 where
     R: RangeBounds<usize>,
 {
-    fn cells(&self, count_rows: usize, count_columns: usize) -> Vec<(usize, usize)> {
+    type Iter = RowsIter;
+
+    fn cells(&self, count_rows: usize, count_columns: usize) -> Self::Iter {
         let (x, y) = bounds_to_usize(self.range.start_bound(), self.range.end_bound(), count_rows);
 
-        (x..y)
-            .map(|row| (0..count_columns).map(|column| (row, column)).collect())
-            .collect::<Vec<Vec<_>>>()
-            .concat()
+        RowsIter::new(x, y, count_columns)
     }
 }
 
@@ -309,17 +271,16 @@ impl<R> Object for Columns<R>
 where
     R: RangeBounds<usize>,
 {
-    fn cells(&self, count_rows: usize, count_columns: usize) -> Vec<(usize, usize)> {
+    type Iter = ColumnsIter;
+
+    fn cells(&self, count_rows: usize, count_columns: usize) -> Self::Iter {
         let (x, y) = bounds_to_usize(
             self.range.start_bound(),
             self.range.end_bound(),
             count_columns,
         );
 
-        (x..y)
-            .map(|column| (0..count_rows).map(|row| (row, column)).collect())
-            .collect::<Vec<Vec<_>>>()
-            .concat()
+        ColumnsIter::new(x, y, count_rows)
     }
 }
 
@@ -327,8 +288,10 @@ where
 pub struct FirstColumn;
 
 impl Object for FirstColumn {
-    fn cells(&self, count_rows: usize, _: usize) -> Vec<(usize, usize)> {
-        (0..count_rows).map(|row| (row, 0)).collect()
+    type Iter = ColumnIter;
+
+    fn cells(&self, count_rows: usize, _: usize) -> Self::Iter {
+        ColumnIter::new(0, count_rows)
     }
 }
 
@@ -344,9 +307,11 @@ impl Add<usize> for FirstColumn {
 pub struct LastColumn;
 
 impl Object for LastColumn {
-    fn cells(&self, count_rows: usize, count_columns: usize) -> Vec<(usize, usize)> {
+    type Iter = ColumnIter;
+
+    fn cells(&self, count_rows: usize, count_columns: usize) -> Self::Iter {
         let col = count_columns.saturating_sub(1);
-        (0..count_rows).map(|row| (row, col)).collect()
+        ColumnIter::new(col, count_rows)
     }
 }
 
@@ -362,13 +327,15 @@ impl Sub<usize> for LastColumn {
 pub struct Column(usize);
 
 impl Object for Column {
-    fn cells(&self, count_rows: usize, count_columns: usize) -> Vec<(usize, usize)> {
+    type Iter = ColumnIter;
+
+    fn cells(&self, count_rows: usize, count_columns: usize) -> Self::Iter {
         let col = self.0;
         if col >= count_columns {
-            return Vec::new();
+            return ColumnIter::new(0, 0);
         }
 
-        (0..count_rows).map(|row| (row, col)).collect()
+        ColumnIter::new(col, count_rows)
     }
 }
 
@@ -378,14 +345,16 @@ pub struct LastColumnOffset {
 }
 
 impl Object for LastColumnOffset {
-    fn cells(&self, count_rows: usize, count_columns: usize) -> Vec<(usize, usize)> {
+    type Iter = ColumnIter;
+
+    fn cells(&self, count_rows: usize, count_columns: usize) -> Self::Iter {
         let col = count_columns.saturating_sub(1);
         if self.offset > col {
-            return Vec::new();
+            return ColumnIter::new(0, 0);
         }
 
         let col = col - self.offset;
-        (0..count_rows).map(|row| (row, col)).collect()
+        ColumnIter::new(col, count_rows)
     }
 }
 
@@ -395,47 +364,412 @@ impl Object for LastColumnOffset {
 pub struct Cell(pub usize, pub usize);
 
 impl Object for Cell {
-    fn cells(&self, _: usize, _: usize) -> Vec<(usize, usize)> {
-        vec![(self.0, self.1)]
+    type Iter = CellIter;
+
+    fn cells(&self, _: usize, _: usize) -> Self::Iter {
+        CellIter::new(self.0, self.1)
     }
 }
 
-/// Combinator is a transformation function
-type Combinator = fn(Vec<(usize, usize)>, Vec<(usize, usize)>) -> Vec<(usize, usize)>;
-
 /// Combination struct used for chaning [Object]'s.
-pub struct Combination<L, R> {
+///
+/// Combines 2 sets of cells into one.
+///
+/// Dublicates are removed from the output set.
+pub struct UntionCombination<L, R> {
     lhs: L,
     rhs: R,
-    combinator: Combinator,
 }
 
-impl<L, R> Object for Combination<L, R>
+impl<L, R> Object for UntionCombination<L, R>
 where
     L: Object,
     R: Object,
 {
-    fn cells(&self, count_rows: usize, count_columns: usize) -> Vec<(usize, usize)> {
-        let l = self.lhs.cells(count_rows, count_columns);
-        let r = self.rhs.cells(count_rows, count_columns);
-        (self.combinator)(l, r)
+    type Iter = UnionIter<L::Iter, R::Iter>;
+
+    fn cells(&self, count_rows: usize, count_columns: usize) -> Self::Iter {
+        let lhs = self.lhs.cells(count_rows, count_columns);
+        let rhs = self.rhs.cells(count_rows, count_columns);
+
+        UnionIter::new(lhs, rhs)
     }
 }
 
-/// Combines 2 sets of cells into one.
+/// Difference struct used for chaning [Object]'s.
 ///
-/// Dublicates are removed from the output set.
-fn combine_cells(lhs: Vec<(usize, usize)>, rhs: Vec<(usize, usize)>) -> Vec<(usize, usize)> {
-    lhs.into_iter()
-        .chain(rhs.into_iter())
-        .collect::<BTreeSet<_>>()
-        .into_iter()
-        .collect()
+/// Retuns cells from 1st set with removed ones from the 2nd set.
+pub struct DiffCombination<L, R> {
+    lhs: L,
+    rhs: R,
+}
+
+impl<L, R> Object for DiffCombination<L, R>
+where
+    L: Object,
+    R: Object,
+{
+    type Iter = DiffIter<L::Iter>;
+
+    fn cells(&self, count_rows: usize, count_columns: usize) -> Self::Iter {
+        let lhs = self.lhs.cells(count_rows, count_columns);
+        let rhs = self.rhs.cells(count_rows, count_columns);
+
+        DiffIter::new(lhs, rhs)
+    }
 }
 
-/// Removes cells from fist set which are present in a second set.
-fn remove_cells(lhs: Vec<(usize, usize)>, rhs: Vec<(usize, usize)>) -> Vec<(usize, usize)> {
-    lhs.into_iter().filter(|l| !rhs.contains(l)).collect()
+pub struct SectorIter {
+    rows_end: usize,
+    cols_start: usize,
+    cols_end: usize,
+    row: usize,
+    col: usize,
+}
+
+impl SectorIter {
+    pub 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 SectorIter {
+    type Item = (usize, usize);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        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))
+    }
+}
+
+pub struct FrameIter {
+    rows: usize,
+    cols: usize,
+    row: usize,
+    col: usize,
+}
+
+impl FrameIter {
+    pub 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 = (usize, usize);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        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((row, col))
+    }
+}
+
+pub struct RowsIter {
+    rows: usize,
+    cols: usize,
+    col: usize,
+    row: usize,
+}
+
+impl RowsIter {
+    pub const fn new(rows_start: usize, rows_end: usize, count_columns: usize) -> Self {
+        Self {
+            rows: rows_end,
+            cols: count_columns,
+            row: rows_start,
+            col: 0,
+        }
+    }
+}
+
+impl Iterator for RowsIter {
+    type Item = (usize, usize);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        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((row, col))
+    }
+}
+
+pub struct RowIter {
+    cols: usize,
+    col: usize,
+    row: usize,
+}
+
+impl RowIter {
+    pub const fn new(row: usize, count_columns: usize) -> Self {
+        Self {
+            cols: count_columns,
+            row,
+            col: 0,
+        }
+    }
+}
+
+impl Iterator for RowIter {
+    type Item = (usize, usize);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.col == self.cols {
+            return None;
+        }
+
+        let col = self.col;
+
+        self.col += 1;
+
+        Some((self.row, col))
+    }
+}
+
+pub struct ColumnsIter {
+    rows: usize,
+    cols: usize,
+    col: usize,
+    row: usize,
+}
+
+impl ColumnsIter {
+    pub const fn new(cols_start: usize, cols_end: usize, count_rows: usize) -> Self {
+        Self {
+            rows: count_rows,
+            cols: cols_end,
+            row: 0,
+            col: cols_start,
+        }
+    }
+}
+
+impl Iterator for ColumnsIter {
+    type Item = (usize, usize);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.col == self.cols {
+            return None;
+        }
+
+        let row = self.row;
+        let col = self.col;
+
+        self.row += 1;
+
+        if self.row == self.rows {
+            self.col += 1;
+            self.row = 0;
+        }
+
+        Some((row, col))
+    }
+}
+
+pub struct ColumnIter {
+    rows: usize,
+    col: usize,
+    row: usize,
+}
+
+impl ColumnIter {
+    pub const fn new(col: usize, count_rows: usize) -> Self {
+        Self {
+            rows: count_rows,
+            row: 0,
+            col,
+        }
+    }
+}
+
+impl Iterator for ColumnIter {
+    type Item = (usize, usize);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.row == self.rows {
+            return None;
+        }
+
+        let row = self.row;
+        let col = self.col;
+
+        self.row += 1;
+
+        Some((row, col))
+    }
+}
+
+pub struct CellIter {
+    cell: Option<(usize, usize)>,
+}
+
+impl CellIter {
+    fn new(row: usize, col: usize) -> Self {
+        Self {
+            cell: Some((row, col)),
+        }
+    }
+}
+
+impl Iterator for CellIter {
+    type Item = (usize, usize);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.cell.take()
+    }
+}
+
+pub struct UnionIter<L, R> {
+    lhs: L,
+    rhs: R,
+    seen: HashSet<(usize, usize)>,
+}
+
+impl<L, R> UnionIter<L, R>
+where
+    L: Iterator<Item = (usize, usize)>,
+    R: Iterator<Item = (usize, usize)>,
+{
+    fn new(lhs: L, rhs: R) -> Self {
+        let size = match lhs.size_hint() {
+            (s1, Some(s2)) if s1 == s2 => s1,
+            _ => 0,
+        };
+
+        Self {
+            lhs,
+            rhs,
+            seen: HashSet::with_capacity(size),
+        }
+    }
+}
+
+impl<L, R> Iterator for UnionIter<L, R>
+where
+    L: Iterator<Item = (usize, usize)>,
+    R: Iterator<Item = (usize, usize)>,
+{
+    type Item = (usize, usize);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if let Some(p) = self.lhs.next() {
+            self.seen.insert(p);
+            return Some(p);
+        }
+
+        for p in self.rhs.by_ref() {
+            if !self.seen.contains(&p) {
+                self.seen.insert(p);
+                return Some(p);
+            }
+        }
+
+        None
+    }
+}
+
+pub struct DiffIter<L> {
+    lhs: L,
+    seen: HashSet<(usize, usize)>,
+}
+
+impl<L> DiffIter<L>
+where
+    L: Iterator<Item = (usize, usize)>,
+{
+    fn new<R>(lhs: L, rhs: R) -> Self
+    where
+        R: Iterator<Item = (usize, usize)>,
+    {
+        let size = match rhs.size_hint() {
+            (s1, Some(s2)) if s1 == s2 => s1,
+            _ => 0,
+        };
+
+        let mut seen = HashSet::with_capacity(size);
+        for p in rhs {
+            seen.insert(p);
+        }
+
+        Self { lhs, seen }
+    }
+}
+
+impl<L> Iterator for DiffIter<L>
+where
+    L: Iterator<Item = (usize, usize)>,
+{
+    type Item = (usize, usize);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        for p in self.lhs.by_ref() {
+            if !self.seen.contains(&p) {
+                return Some(p);
+            }
+        }
+
+        None
+    }
 }
 
 /// Converts a range bound to its indexes.
@@ -465,10 +799,10 @@ mod tests {
 
     #[test]
     fn first_column_test() {
-        assert_eq!((Columns::first()).cells(0, 0), vec![]);
+        assert_eq!((Columns::first()).cells(0, 0).collect::<Vec<_>>(), vec![]);
         // is this correct?
         assert_eq!(
-            (Columns::first()).cells(10, 0),
+            (Columns::first()).cells(10, 0).collect::<Vec<_>>(),
             vec![
                 (0, 0),
                 (1, 0),
@@ -482,19 +816,19 @@ mod tests {
                 (9, 0)
             ]
         );
-        assert_eq!((Columns::first()).cells(0, 10), vec![]);
+        assert_eq!((Columns::first()).cells(0, 10).collect::<Vec<_>>(), vec![]);
         assert_eq!(
-            (Columns::first()).cells(5, 2),
+            (Columns::first()).cells(5, 2).collect::<Vec<_>>(),
             vec![(0, 0), (1, 0), (2, 0), (3, 0), (4, 0)]
         );
     }
 
     #[test]
     fn last_column_test() {
-        assert_eq!((Columns::last()).cells(0, 0), vec![]);
+        assert_eq!((Columns::last()).cells(0, 0).collect::<Vec<_>>(), vec![]);
         // is this correct?
         assert_eq!(
-            (Columns::last()).cells(10, 0),
+            (Columns::last()).cells(10, 0).collect::<Vec<_>>(),
             vec![
                 (0, 0),
                 (1, 0),
@@ -508,9 +842,9 @@ mod tests {
                 (9, 0)
             ]
         );
-        assert_eq!((Columns::last()).cells(0, 10), vec![]);
+        assert_eq!((Columns::last()).cells(0, 10).collect::<Vec<_>>(), vec![]);
         assert_eq!(
-            (Columns::last()).cells(5, 2),
+            (Columns::last()).cells(5, 2).collect::<Vec<_>>(),
             vec![(0, 1), (1, 1), (2, 1), (3, 1), (4, 1)]
         );
     }
@@ -518,128 +852,235 @@ mod tests {
     #[test]
     fn last_column_sub_test() {
         assert_eq!(
-            (Columns::last()).cells(5, 2),
+            (Columns::last()).cells(5, 2).collect::<Vec<_>>(),
             vec![(0, 1), (1, 1), (2, 1), (3, 1), (4, 1)]
         );
         assert_eq!(
-            (Columns::last() - 0).cells(5, 2),
+            (Columns::last() - 0).cells(5, 2).collect::<Vec<_>>(),
             vec![(0, 1), (1, 1), (2, 1), (3, 1), (4, 1)]
         );
         assert_eq!(
-            (Columns::last() - 1).cells(5, 2),
+            (Columns::last() - 1).cells(5, 2).collect::<Vec<_>>(),
             vec![(0, 0), (1, 0), (2, 0), (3, 0), (4, 0)]
         );
-        assert_eq!((Columns::last() - 2).cells(5, 2), vec![]);
-        assert_eq!((Columns::last() - 100).cells(5, 2), vec![]);
+        assert_eq!(
+            (Columns::last() - 2).cells(5, 2).collect::<Vec<_>>(),
+            vec![]
+        );
+        assert_eq!(
+            (Columns::last() - 100).cells(5, 2).collect::<Vec<_>>(),
+            vec![]
+        );
     }
 
     #[test]
     fn first_column_sub_test() {
         assert_eq!(
-            (Columns::first()).cells(5, 2),
+            (Columns::first()).cells(5, 2).collect::<Vec<_>>(),
             [(0, 0), (1, 0), (2, 0), (3, 0), (4, 0)]
         );
         assert_eq!(
-            (Columns::first() + 0).cells(5, 2),
+            (Columns::first() + 0).cells(5, 2).collect::<Vec<_>>(),
             [(0, 0), (1, 0), (2, 0), (3, 0), (4, 0)]
         );
         assert_eq!(
-            (Columns::first() + 1).cells(5, 2),
+            (Columns::first() + 1).cells(5, 2).collect::<Vec<_>>(),
             [(0, 1), (1, 1), (2, 1), (3, 1), (4, 1)]
         );
-        assert_eq!((Columns::first() + 2).cells(5, 2), []);
-        assert_eq!((Columns::first() + 100).cells(5, 2), []);
+        assert_eq!((Columns::first() + 2).cells(5, 2).collect::<Vec<_>>(), []);
+        assert_eq!((Columns::first() + 100).cells(5, 2).collect::<Vec<_>>(), []);
     }
 
     #[test]
     fn last_row_sub_test() {
-        assert_eq!((Rows::last()).cells(5, 2), vec![(4, 0), (4, 1)]);
-        assert_eq!((Rows::last() - 0).cells(5, 2), vec![(4, 0), (4, 1)]);
-        assert_eq!((Rows::last() - 1).cells(5, 2), vec![(3, 0), (3, 1)]);
-        assert_eq!((Rows::last() - 2).cells(5, 2), vec![(2, 0), (2, 1)]);
-        assert_eq!((Rows::last() - 3).cells(5, 2), vec![(1, 0), (1, 1)]);
-        assert_eq!((Rows::last() - 4).cells(5, 2), vec![(0, 0), (0, 1)]);
-        assert_eq!((Rows::last() - 5).cells(5, 2), vec![]);
-        assert_eq!((Rows::last() - 100).cells(5, 2), vec![]);
+        assert_eq!(
+            (Rows::last()).cells(5, 2).collect::<Vec<_>>(),
+            vec![(4, 0), (4, 1)]
+        );
+        assert_eq!(
+            (Rows::last() - 0).cells(5, 2).collect::<Vec<_>>(),
+            vec![(4, 0), (4, 1)]
+        );
+        assert_eq!(
+            (Rows::last() - 1).cells(5, 2).collect::<Vec<_>>(),
+            vec![(3, 0), (3, 1)]
+        );
+        assert_eq!(
+            (Rows::last() - 2).cells(5, 2).collect::<Vec<_>>(),
+            vec![(2, 0), (2, 1)]
+        );
+        assert_eq!(
+            (Rows::last() - 3).cells(5, 2).collect::<Vec<_>>(),
+            vec![(1, 0), (1, 1)]
+        );
+        assert_eq!(
+            (Rows::last() - 4).cells(5, 2).collect::<Vec<_>>(),
+            vec![(0, 0), (0, 1)]
+        );
+        assert_eq!((Rows::last() - 5).cells(5, 2).collect::<Vec<_>>(), vec![]);
+        assert_eq!((Rows::last() - 100).cells(5, 2).collect::<Vec<_>>(), vec![]);
     }
 
     #[test]
     fn first_row_sub_test() {
-        assert_eq!((Rows::first()).cells(5, 2), vec![(0, 0), (0, 1)]);
-        assert_eq!((Rows::first() + 0).cells(5, 2), vec![(0, 0), (0, 1)]);
-        assert_eq!((Rows::first() + 1).cells(5, 2), vec![(1, 0), (1, 1)]);
-        assert_eq!((Rows::first() + 2).cells(5, 2), vec![(2, 0), (2, 1)]);
-        assert_eq!((Rows::first() + 3).cells(5, 2), vec![(3, 0), (3, 1)]);
-        assert_eq!((Rows::first() + 4).cells(5, 2), vec![(4, 0), (4, 1)]);
-        assert_eq!((Rows::first() + 5).cells(5, 2), vec![]);
-        assert_eq!((Rows::first() + 100).cells(5, 2), vec![]);
+        assert_eq!(
+            (Rows::first()).cells(5, 2).collect::<Vec<_>>(),
+            vec![(0, 0), (0, 1)]
+        );
+        assert_eq!(
+            (Rows::first() + 0).cells(5, 2).collect::<Vec<_>>(),
+            vec![(0, 0), (0, 1)]
+        );
+        assert_eq!(
+            (Rows::first() + 1).cells(5, 2).collect::<Vec<_>>(),
+            vec![(1, 0), (1, 1)]
+        );
+        assert_eq!(
+            (Rows::first() + 2).cells(5, 2).collect::<Vec<_>>(),
+            vec![(2, 0), (2, 1)]
+        );
+        assert_eq!(
+            (Rows::first() + 3).cells(5, 2).collect::<Vec<_>>(),
+            vec![(3, 0), (3, 1)]
+        );
+        assert_eq!(
+            (Rows::first() + 4).cells(5, 2).collect::<Vec<_>>(),
+            vec![(4, 0), (4, 1)]
+        );
+        assert_eq!((Rows::first() + 5).cells(5, 2).collect::<Vec<_>>(), vec![]);
+        assert_eq!(
+            (Rows::first() + 100).cells(5, 2).collect::<Vec<_>>(),
+            vec![]
+        );
     }
 
     #[test]
     fn rows_test() {
         assert_eq!(
-            (Rows::new(..)).cells(2, 3),
+            (Rows::new(..)).cells(2, 3).collect::<Vec<_>>(),
             vec![(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)]
         );
-        assert_eq!((Rows::new(1..)).cells(2, 3), vec![(1, 0), (1, 1), (1, 2)]);
-        assert_eq!((Rows::new(2..)).cells(2, 3), vec![]);
-        assert_eq!((Rows::new(1..2)).cells(2, 3), vec![(1, 0), (1, 1), (1, 2)]);
+        assert_eq!(
+            (Rows::new(1..)).cells(2, 3).collect::<Vec<_>>(),
+            vec![(1, 0), (1, 1), (1, 2)]
+        );
+        assert_eq!((Rows::new(2..)).cells(2, 3).collect::<Vec<_>>(), vec![]);
+        assert_eq!(
+            (Rows::new(1..2)).cells(2, 3).collect::<Vec<_>>(),
+            vec![(1, 0), (1, 1), (1, 2)]
+        );
     }
 
     #[test]
     fn columns_test() {
         assert_eq!(
-            (Columns::new(..)).cells(2, 3),
+            (Columns::new(..)).cells(2, 3).collect::<Vec<_>>(),
             vec![(0, 0), (1, 0), (0, 1), (1, 1), (0, 2), (1, 2)]
         );
         assert_eq!(
-            (Columns::new(1..)).cells(2, 3),
+            (Columns::new(1..)).cells(2, 3).collect::<Vec<_>>(),
             vec![(0, 1), (1, 1), (0, 2), (1, 2)]
         );
-        assert_eq!((Columns::new(2..)).cells(2, 3), vec![(0, 2), (1, 2)]);
-        assert_eq!((Columns::new(3..)).cells(2, 3), vec![]);
-        assert_eq!((Columns::new(1..2)).cells(2, 3), vec![(0, 1), (1, 1)]);
+        assert_eq!(
+            (Columns::new(2..)).cells(2, 3).collect::<Vec<_>>(),
+            vec![(0, 2), (1, 2)]
+        );
+        assert_eq!((Columns::new(3..)).cells(2, 3).collect::<Vec<_>>(), vec![]);
+        assert_eq!(
+            (Columns::new(1..2)).cells(2, 3).collect::<Vec<_>>(),
+            vec![(0, 1), (1, 1)]
+        );
+    }
+
+    #[test]
+    fn frame_test() {
+        assert_eq!(
+            Frame.cells(2, 3).collect::<Vec<_>>(),
+            vec![(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)]
+        );
+        assert_eq!(Frame.cells(0, 0).collect::<Vec<_>>(), vec![]);
+        assert_eq!(Frame.cells(2, 0).collect::<Vec<_>>(), vec![]);
+        assert_eq!(Frame.cells(0, 2).collect::<Vec<_>>(), vec![]);
     }
 
     #[test]
     fn segment_test() {
         assert_eq!(
-            (Segment::new(.., ..)).cells(2, 3),
+            (Segment::new(.., ..)).cells(2, 3).collect::<Vec<_>>(),
             vec![(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)]
         );
         assert_eq!(
-            (Segment::new(1.., ..)).cells(2, 3),
+            (Segment::new(1.., ..)).cells(2, 3).collect::<Vec<_>>(),
             vec![(1, 0), (1, 1), (1, 2)]
         );
-        assert_eq!((Segment::new(2.., ..)).cells(2, 3), vec![]);
+        assert_eq!(
+            (Segment::new(2.., ..)).cells(2, 3).collect::<Vec<_>>(),
+            vec![]
+        );
 
         assert_eq!(
-            (Segment::new(.., 1..)).cells(2, 3),
+            (Segment::new(.., 1..)).cells(2, 3).collect::<Vec<_>>(),
             vec![(0, 1), (0, 2), (1, 1), (1, 2)]
         );
-        assert_eq!((Segment::new(.., 2..)).cells(2, 3), vec![(0, 2), (1, 2)]);
-        assert_eq!((Segment::new(.., 3..)).cells(2, 3), vec![]);
+        assert_eq!(
+            (Segment::new(.., 2..)).cells(2, 3).collect::<Vec<_>>(),
+            vec![(0, 2), (1, 2)]
+        );
+        assert_eq!(
+            (Segment::new(.., 3..)).cells(2, 3).collect::<Vec<_>>(),
+            vec![]
+        );
 
-        assert_eq!((Segment::new(1.., 1..)).cells(2, 3), vec![(1, 1), (1, 2)]);
-        assert_eq!((Segment::new(1..2, 1..2)).cells(2, 3), vec![(1, 1)]);
+        assert_eq!(
+            (Segment::new(1.., 1..)).cells(2, 3).collect::<Vec<_>>(),
+            vec![(1, 1), (1, 2)]
+        );
+        assert_eq!(
+            (Segment::new(1..2, 1..2)).cells(2, 3).collect::<Vec<_>>(),
+            vec![(1, 1)]
+        );
 
-        assert_eq!((Segment::new(5.., 5..)).cells(2, 3), vec![]);
+        assert_eq!(
+            (Segment::new(5.., 5..)).cells(2, 3).collect::<Vec<_>>(),
+            vec![]
+        );
     }
 
     #[test]
     fn object_and_test() {
-        assert_eq!(Cell(0, 0).and(Cell(0, 0)).cells(2, 3), vec![(0, 0)]);
-        assert_eq!(Cell(0, 0).and(Cell(1, 2)).cells(2, 3), vec![(0, 0), (1, 2)]);
-        assert_eq!(Cell(0, 0).and(Cell(1, 2)).cells(0, 0), vec![(0, 0), (1, 2)]);
+        assert_eq!(
+            Cell(0, 0).and(Cell(0, 0)).cells(2, 3).collect::<Vec<_>>(),
+            vec![(0, 0)]
+        );
+        assert_eq!(
+            Cell(0, 0).and(Cell(1, 2)).cells(2, 3).collect::<Vec<_>>(),
+            vec![(0, 0), (1, 2)]
+        );
+        assert_eq!(
+            Cell(0, 0).and(Cell(1, 2)).cells(0, 0).collect::<Vec<_>>(),
+            vec![(0, 0), (1, 2)]
+        );
     }
 
     #[test]
     fn object_not_test() {
-        assert_eq!(Cell(0, 0).not(Cell(0, 0)).cells(2, 3), vec![]);
         assert_eq!(
-            Rows::first().not(Cell(0, 0)).cells(2, 3),
+            Cell(0, 0).not(Cell(0, 0)).cells(2, 3).collect::<Vec<_>>(),
+            vec![]
+        );
+        assert_eq!(
+            Rows::first()
+                .not(Cell(0, 0))
+                .cells(2, 3)
+                .collect::<Vec<_>>(),
             vec![(0, 1), (0, 2)]
         );
-        assert_eq!(Rows::first().not(Cell(0, 0)).cells(0, 0), vec![]);
+        assert_eq!(
+            Rows::first()
+                .not(Cell(0, 0))
+                .cells(0, 0)
+                .collect::<Vec<_>>(),
+            vec![]
+        );
     }
 }
diff --git a/src/table.rs b/src/table.rs
index 5b21d4e..df1922c 100644
--- a/src/table.rs
+++ b/src/table.rs
@@ -168,9 +168,11 @@ where
 
 /// Modify structure provide an abstraction, to be able to apply
 /// a set of [CellOption]s to the same object.
+///
+/// Be aware that the settings are applied all to a cell at a time.
+/// So sometimes you may need to make a several calls of [Modify] in order to achieve the desired affect.
 pub struct Modify<O> {
     obj: O,
-    modifiers: Vec<Box<dyn CellOption>>,
 }
 
 impl<O> Modify<O>
@@ -179,41 +181,85 @@ where
 {
     /// Creates a new [Modify] without any options.
     pub fn new(obj: O) -> Self {
-        Self {
-            obj,
-            modifiers: Vec::new(),
+        Self { obj }
+    }
+
+    /// It's a generic function which stores a [CellOption].
+    ///
+    /// IMPORTANT:
+    ///     The function *doesn't* changes a [Table].
+    ///     [Table] will be changed only after passing [Modify] object to [Table::with].
+    pub fn with<F>(self, s: F) -> ModifyList<O, F>
+    where
+        F: CellOption,
+    {
+        ModifyList {
+            obj: self.obj,
+            modifiers: s,
         }
     }
+}
+
+/// ModifyList is a container of [CellOption]s which are applied to a set [Object].
+pub struct ModifyList<O, S> {
+    obj: O,
+    modifiers: S,
+}
 
+impl<O, S> ModifyList<O, S>
+where
+    O: Object,
+    S: CellOption,
+{
     /// With a generic function which stores a [CellOption].
     ///
     /// IMPORTANT:
     ///     The function *doesn't* changes a [Table].
     ///     [Table] will be changed only after passing [Modify] object to [Table::with].
-    pub fn with<F>(mut self, f: F) -> Self
+    pub fn with<F>(self, s: F) -> ModifyList<O, CellSettingsList<S, F>>
     where
-        F: CellOption + 'static,
+        F: CellOption,
     {
-        let func = Box::new(f);
-        self.modifiers.push(func);
-        self
+        ModifyList {
+            obj: self.obj,
+            modifiers: CellSettingsList {
+                s1: self.modifiers,
+                s2: s,
+            },
+        }
     }
 }
 
-impl<O> TableOption for Modify<O>
+impl<O, S> TableOption for ModifyList<O, S>
 where
     O: Object,
+    S: CellOption,
 {
     fn change(&mut self, grid: &mut Grid) {
         let cells = self.obj.cells(grid.count_rows(), grid.count_columns());
-        for func in &mut self.modifiers {
-            for &(row, column) in &cells {
-                func.change_cell(grid, row, column)
-            }
+        for (row, column) in cells {
+            self.modifiers.change_cell(grid, row, column)
         }
     }
 }
 
+/// CellSettingsList is a container of [CellOption]s.
+pub struct CellSettingsList<S1, S2> {
+    s1: S1,
+    s2: S2,
+}
+
+impl<S1, S2> CellOption for CellSettingsList<S1, S2>
+where
+    S1: CellOption,
+    S2: CellOption,
+{
+    fn change_cell(&mut self, grid: &mut Grid, row: usize, column: usize) {
+        self.s1.change_cell(grid, row, column);
+        self.s2.change_cell(grid, row, column);
+    }
+}
+
 /// A trait for [IntoIterator] whose Item type is bound to [Tabled].
 /// Any type implements [IntoIterator] can call this function directly
 ///


Test patch:
diff --git a/tests/highlingt_test.rs b/tests/highlingt_test.rs
index e2f8842..dbe6ff8 100644
--- a/tests/highlingt_test.rs
+++ b/tests/highlingt_test.rs
@@ -167,11 +167,11 @@ fn highlingt_frame() {
     let expected = concat!(
         "*++++++++++++++++++++++++++++++++++++#\n",
         "+ N │ column 0 │ column 1 │ column 2 +\n",
-        "+───*+++++++++++++++++++++#──────────+\n",
-        "+ 0 +   0-0    │   0-1    +   0-2    +\n",
-        "+───+──────────┼──────────+──────────+\n",
-        "+ 1 +   1-0    │   1-1    +   1-2    +\n",
-        "+───@+++++++++++++++++++++.──────────+\n",
+        "+───┼──────────┼──────────┼──────────+\n",
+        "+ 0 │   0-0    │   0-1    │   0-2    +\n",
+        "+───┼──────────┼──────────┼──────────+\n",
+        "+ 1 │   1-0    │   1-1    │   1-2    +\n",
+        "+───┼──────────┼──────────┼──────────+\n",
         "+ 2 │   2-0    │   2-1    │   2-2    +\n",
         "@++++++++++++++++++++++++++++++++++++.\n",
     );
@@ -435,7 +435,7 @@ fn highlingt_complex_figures() {
 }
 
 #[test]
-fn highlingt_several_time() {
+fn highlingt_several_times() {
     let data = create_vector::<3, 3>();
     let table = Table::new(&data)
         .with(Style::modern())
@@ -447,11 +447,11 @@ fn highlingt_several_time() {
     let expected = concat!(
         "**************************xxxxxxxxxxxx\n",
         "* N │ column 0 │ column 1 x column 2 x\n",
-        "*───############**********x──────────x\n",
+        "*───############──────────x──────────x\n",
         "* 0 #   0-0    #   0-1    x   0-2    x\n",
         "*───############──────────x──────────x\n",
-        "* 1 *   1-0    │   1-1    x   1-2    x\n",
-        "*───**********************x──────────x\n",
+        "* 1 │   1-0    │   1-1    x   1-2    x\n",
+        "*───┼──────────┼──────────x──────────x\n",
         "* 2 │   2-0    │   2-1    x   2-2    x\n",
         "**************************xxxxxxxxxxxx\n",
     );
@@ -460,3 +460,26 @@ fn highlingt_several_time() {
 
     assert_eq!(table, expected);
 }
+
+// #[test]
+// fn highlingt_empty_border() {
+//     let data = create_vector::<3, 3>();
+//     let table = Table::new(&data)
+//         .with(Style::modern())
+//         .with(Highlight::new(Frame, Border::empty()))
+//         .to_string();
+
+//     let expected = concat!(
+//         " N │ column 0 │ column 1 │ column 2 \n",
+//         "───                       ──────────\n",
+//         " 0     0-0    │   0-1        0-2    \n",
+//         "─── ──────────┼────────── ──────────\n",
+//         " 1     1-0    │   1-1        1-2    \n",
+//         "───                       ──────────\n",
+//         " 2 │   2-0    │   2-1    │   2-2    \n",
+//     );
+
+//     println!("{}", table);
+
+//     assert_eq!(table, expected);
+// }