Repository: zhiburt/tabled
Pull request #487 (2025-01-24 13:48:54)

Add tabled::iter::LayoutIterator
ref #472


Patch:
diff --git a/tabled/src/iter/layout_iterator.rs b/tabled/src/iter/layout_iterator.rs
new file mode 100644
index 0000000..4c491a9
--- /dev/null
+++ b/tabled/src/iter/layout_iterator.rs
@@ -0,0 +1,77 @@
+#[cfg(feature = "std")]
+use crate::{Table, Tabled};
+
+/// [`LayoutIterator`] is a convient abstraction to iterate over rows/columns.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+pub struct LayoutIterator {
+    from: usize,
+    to: usize,
+    batch: usize,
+    i: usize,
+}
+
+impl LayoutIterator {
+    /// Creates a custom [`LayoutIterator`] instance.
+    pub fn new(from: usize, to: usize, batch: usize) -> Self {
+        Self {
+            from,
+            to,
+            batch,
+            i: 0,
+        }
+    }
+
+    /// Creates a record iterator for KV table created by [`Table::kv`].
+    /// So it basically skips all rows until next record starts.
+    #[cfg(feature = "std")]
+    pub fn kv_batches<T>(t: &Table) -> Self
+    where
+        T: Tabled,
+    {
+        Self::new(0, t.count_rows(), T::LENGTH)
+    }
+}
+
+impl Iterator for LayoutIterator {
+    type Item = usize;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.batch == 0 {
+            return None;
+        }
+
+        if self.from >= self.to {
+            return None;
+        }
+
+        let value = self.i * self.batch;
+        self.from += self.batch;
+        self.i += 1;
+
+        Some(value)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::iter::LayoutIterator;
+
+    #[test]
+    fn test_layout_iterator() {
+        assert_eq!(
+            LayoutIterator::new(0, 5, 1).collect::<Vec<_>>(),
+            vec![0, 1, 2, 3, 4]
+        );
+        assert_eq!(
+            LayoutIterator::new(0, 5, 2).collect::<Vec<_>>(),
+            vec![0, 2, 4]
+        );
+        assert_eq!(
+            LayoutIterator::new(0, 6, 2).collect::<Vec<_>>(),
+            vec![0, 2, 4]
+        );
+        assert_eq!(LayoutIterator::new(0, 0, 2).collect::<Vec<_>>(), vec![]);
+        assert_eq!(LayoutIterator::new(0, 5, 0).collect::<Vec<_>>(), vec![]);
+        assert_eq!(LayoutIterator::new(0, 0, 0).collect::<Vec<_>>(), vec![]);
+    }
+}
diff --git a/tabled/src/iter/mod.rs b/tabled/src/iter/mod.rs
new file mode 100644
index 0000000..1256783
--- /dev/null
+++ b/tabled/src/iter/mod.rs
@@ -0,0 +1,5 @@
+//! A module for iterator structures.
+
+mod layout_iterator;
+
+pub use layout_iterator::LayoutIterator;
diff --git a/tabled/src/lib.rs b/tabled/src/lib.rs
index 5468206..36c79ac 100644
--- a/tabled/src/lib.rs
+++ b/tabled/src/lib.rs
@@ -289,6 +289,7 @@ mod tabled;
 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
 pub mod builder;
 pub mod grid;
+pub mod iter;
 pub mod settings;
 pub mod tables;
 


Test patch:
diff --git a/tabled/tests/core/iter_test.rs b/tabled/tests/core/iter_test.rs
new file mode 100644
index 0000000..88c7726
--- /dev/null
+++ b/tabled/tests/core/iter_test.rs
@@ -0,0 +1,56 @@
+#![cfg(all(feature = "std", feature = "derive"))]
+
+use tabled::{
+    iter::LayoutIterator,
+    settings::{style::BorderSpanCorrection, Span, Style},
+    Table, Tabled,
+};
+
+use testing_table::test_table;
+
+test_table!(
+    push_record,
+    {
+        #[derive(Tabled)]
+        struct Company<'a> {
+            name: &'a str,
+            street: &'a str,
+            city: &'a str,
+            zip_code: &'a str,
+        }
+
+
+        let companies = vec![
+            Company { name: "INTEL CORP", city: "SANTA CLARA", street: "2200 MISSION COLLEGE BLVD, RNB-4-151", zip_code: "95054" },
+            Company { name: "Apple Inc.", city: "CUPERTINO", street: "ONE APPLE PARK WAY", zip_code: "95014" },
+        ];
+
+        let mut table = Table::kv(&companies);
+
+        for row in LayoutIterator::kv_batches::<Company>(&table) {
+            table.modify((row, 1), Span::column(-1));
+        }
+
+        table.with(Style::modern());
+        table.with(BorderSpanCorrection);
+
+        table
+    },
+    "┌─────────────────────────────────────────────────┐"
+    "│ INTEL CORP                                      │"
+    "├──────────┬──────────────────────────────────────┤"
+    "│ street   │ 2200 MISSION COLLEGE BLVD, RNB-4-151 │"
+    "├──────────┼──────────────────────────────────────┤"
+    "│ city     │ SANTA CLARA                          │"
+    "├──────────┼──────────────────────────────────────┤"
+    "│ zip_code │ 95054                                │"
+    "├──────────┴──────────────────────────────────────┤"
+    "│ Apple Inc.                                      │"
+    "├──────────┬──────────────────────────────────────┤"
+    "│ street   │ ONE APPLE PARK WAY                   │"
+    "├──────────┼──────────────────────────────────────┤"
+    "│ city     │ CUPERTINO                            │"
+    "├──────────┼──────────────────────────────────────┤"
+    "│ zip_code │ 95014                                │"
+    "└──────────┴──────────────────────────────────────┘"
+);
diff --git a/tabled/tests/core/mod.rs b/tabled/tests/core/mod.rs
index 4c6f90f..ffd373b 100644
--- a/tabled/tests/core/mod.rs
+++ b/tabled/tests/core/mod.rs
@@ -3,6 +3,7 @@ mod compact_table;
 mod extended_table_test;
 mod index_test;
 mod iter_table;
+mod iter_test;
 mod kv_test;
 mod pool_table;
 mod table_test;