Skip to main content

vimwiki_core/lang/elements/blocks/
tables.rs

1use crate::{
2    lang::elements::{
3        InlineElement, InlineElementContainer, IntoChildren, Located,
4    },
5    StrictEq,
6};
7use derive_more::{Constructor, Display, Error, From, IntoIterator};
8use serde::{Deserialize, Serialize};
9use std::collections::HashMap;
10use std::{num::ParseIntError, str::FromStr};
11
12/// Represents the position of a cell in a table
13#[derive(
14    Constructor,
15    Copy,
16    Clone,
17    Debug,
18    Eq,
19    PartialEq,
20    Hash,
21    Display,
22    Serialize,
23    Deserialize,
24)]
25#[display(fmt = "{},{}", row, col)]
26pub struct CellPos {
27    /// Represents the row number of a cell starting from 0
28    pub row: usize,
29
30    /// Represents the coumn number of a cell starting from 0
31    pub col: usize,
32}
33
34#[derive(Debug, Display, Error)]
35pub enum ParseCellPosError {
36    TooFewItems,
37    TooManyItems,
38    BadRow(#[error(source)] ParseIntError),
39    BadCol(#[error(source)] ParseIntError),
40}
41
42impl FromStr for CellPos {
43    type Err = ParseCellPosError;
44
45    /// Parses "{row},{col}" into [`CellPos`]
46    fn from_str(s: &str) -> Result<Self, Self::Err> {
47        let mut iter = s.split(',');
48        let row_str = iter.next();
49        let col_str = iter.next();
50
51        if iter.next().is_some() {
52            Err(ParseCellPosError::TooManyItems)
53        } else {
54            match (row_str, col_str) {
55                (Some(row_str), Some(col_str)) => {
56                    let row: usize = row_str
57                        .trim()
58                        .parse()
59                        .map_err(ParseCellPosError::BadRow)?;
60                    let col: usize = col_str
61                        .trim()
62                        .parse()
63                        .map_err(ParseCellPosError::BadCol)?;
64                    Ok(Self { row, col })
65                }
66                _ => Err(ParseCellPosError::TooFewItems),
67            }
68        }
69    }
70}
71
72#[derive(Clone, Debug, Eq, PartialEq, IntoIterator, Serialize, Deserialize)]
73pub struct Table<'a> {
74    /// Represents the table's data (cells) as a mapping between a cell's
75    /// position and its actual content (private)
76    #[into_iterator(owned, ref, ref_mut)]
77    #[serde(with = "serde_with::rust::map_as_tuple_list")]
78    cells: HashMap<CellPos, Located<Cell<'a>>>,
79
80    /// Represents the total rows contained in the table (private)
81    row_cnt: usize,
82
83    /// Represents the total columns contained in the table (private)
84    col_cnt: usize,
85
86    /// Represents whether or not the table is centered
87    pub centered: bool,
88}
89
90impl Table<'_> {
91    pub fn to_borrowed(&self) -> Table {
92        Table {
93            cells: self
94                .cells
95                .iter()
96                .map(|(k, v)| (*k, v.as_ref().map(Cell::to_borrowed)))
97                .collect(),
98            row_cnt: self.row_cnt,
99            col_cnt: self.col_cnt,
100            centered: self.centered,
101        }
102    }
103
104    pub fn into_owned(self) -> Table<'static> {
105        Table {
106            cells: self
107                .cells
108                .into_iter()
109                .map(|(k, v)| (k, v.map(Cell::into_owned)))
110                .collect(),
111            row_cnt: self.row_cnt,
112            col_cnt: self.col_cnt,
113            centered: self.centered,
114        }
115    }
116}
117
118impl<'a> Table<'a> {
119    pub fn new<I: IntoIterator<Item = (CellPos, Located<Cell<'a>>)>>(
120        cells: I,
121        centered: bool,
122    ) -> Self {
123        let cells: HashMap<CellPos, Located<Cell>> =
124            cells.into_iter().collect();
125        let (max_row, max_col) = cells.keys().fold((0, 0), |acc, pos| {
126            (
127                std::cmp::max(acc.0, pos.row + 1),
128                std::cmp::max(acc.1, pos.col + 1),
129            )
130        });
131
132        Self {
133            cells,
134            row_cnt: max_row,
135            col_cnt: max_col,
136            centered,
137        }
138    }
139
140    /// Returns an iterator over all rows that are considered header rows,
141    /// which is all rows leading up to a divider row. If there is no divider
142    /// row, then there are no header rows
143    pub fn header_rows(&self) -> iter::HeaderRows<'_, 'a> {
144        iter::HeaderRows::new(self)
145    }
146
147    /// Returns an iterator over all rows that are considered body rows,
148    /// which is all rows following a divider row. If there is no divider
149    /// row in the table, then all rows are considered body rows
150    pub fn body_rows(&self) -> iter::BodyRows<'_, 'a> {
151        iter::BodyRows::new(self)
152    }
153
154    /// Returns true if contains header rows
155    pub fn has_header_rows(&self) -> bool {
156        self.header_rows().next().is_some()
157    }
158
159    /// Returns true if contains body rows
160    pub fn has_body_rows(&self) -> bool {
161        self.body_rows().next().is_some()
162    }
163
164    /// Returns true if the table contains a divider row
165    #[inline]
166    pub fn has_divider_row(&self) -> bool {
167        self.get_divider_row_index().is_some()
168    }
169
170    /// Returns the row index representing the divider row of the table
171    /// (separation between header and body) if it exists
172    pub fn get_divider_row_index(&self) -> Option<usize> {
173        self.rows().enumerate().find_map(|(idx, row)| {
174            if row.is_divider_row() {
175                Some(idx)
176            } else {
177                None
178            }
179        })
180    }
181
182    /// Returns the alignment of the specified column within the table
183    ///
184    /// NOTE: This will always return an alignment, even if the column
185    ///       does not exist, by using the default column alignment
186    pub fn get_column_alignment(&self, col: usize) -> ColumnAlign {
187        self.column(col)
188            .find_map(|cell| cell.get_align().copied())
189            .unwrap_or_default()
190    }
191
192    /// Returns the total rows contained in the table
193    #[inline]
194    pub fn row_cnt(&self) -> usize {
195        self.row_cnt
196    }
197
198    /// Returns the total columns contained in the table
199    #[inline]
200    pub fn col_cnt(&self) -> usize {
201        self.col_cnt
202    }
203
204    /// Returns the total cells (rows * columns) contained in the table
205    #[inline]
206    pub fn len(&self) -> usize {
207        self.cells.len()
208    }
209
210    /// Returns true if the total cells (rows * columns) contained in the table
211    /// is zero
212    #[inline]
213    pub fn is_empty(&self) -> bool {
214        self.cells.is_empty()
215    }
216
217    /// Returns raw table cell data as a reference to the hashmap
218    #[inline]
219    pub fn as_data(&self) -> &HashMap<CellPos, Located<Cell<'a>>> {
220        &self.cells
221    }
222
223    /// Returns an iterator of refs through all rows in the table
224    pub fn rows(&self) -> iter::Rows<'_, 'a> {
225        iter::Rows::new(self)
226    }
227
228    /// Returns an iterator of refs through a specific row in the table
229    pub fn row(&self, idx: usize) -> iter::Row<'_, 'a> {
230        iter::Row::new(self, idx, 0)
231    }
232
233    /// Consumes the table and returns an iterator through a specific row in the table
234    pub fn into_row(self, idx: usize) -> iter::IntoRow<'a> {
235        iter::IntoRow::new(self, idx, 0)
236    }
237
238    /// Returns an iterator of refs through all columns in the table
239    pub fn columns(&self) -> iter::Columns<'_, 'a> {
240        iter::Columns::new(self)
241    }
242
243    /// Returns an iterator of refs through a specific column in the table
244    pub fn column(&self, idx: usize) -> iter::Column<'_, 'a> {
245        iter::Column::new(self, 0, idx)
246    }
247
248    /// Consumes the table and returns an iterator through a specific column in the table
249    pub fn into_column(self, idx: usize) -> iter::IntoColumn<'a> {
250        iter::IntoColumn::new(self, 0, idx)
251    }
252
253    /// Returns an iterator of refs through all cells in the table, starting
254    /// from the first row, iterating through all cells from beginning to end,
255    /// and then moving on to the next row
256    pub fn cells(&self) -> iter::Cells<'_, 'a> {
257        iter::Cells::new(self)
258    }
259
260    /// Consumes the table and returns an iterator through all cells in the
261    /// table, starting from the first row, iterating through all cells from
262    /// beginning to end, and then moving on to the next row
263    pub fn into_cells(self) -> iter::IntoCells<'a> {
264        iter::IntoCells::new(self)
265    }
266
267    /// Returns reference to the cell found at the specified row and column
268    pub fn get_cell(
269        &self,
270        row: usize,
271        col: usize,
272    ) -> Option<&Located<Cell<'a>>> {
273        self.cells.get(&CellPos { row, col })
274    }
275
276    /// Returns mut reference to the cell found at the specified row and column
277    pub fn get_mut_cell(
278        &mut self,
279        row: usize,
280        col: usize,
281    ) -> Option<&mut Located<Cell<'a>>> {
282        self.cells.get_mut(&CellPos { row, col })
283    }
284
285    /// Returns the cell's rowspan, which is the number of rows (including
286    /// itself) that the cell spans. 1 means that the cell only spans its
287    /// starting row whereas >1 indicates it is 1 or more rows below its
288    /// starting row
289    ///
290    /// Returns 0 for a non-content cell or a cell that doesn't exist
291    pub fn get_cell_rowspan(&self, row: usize, col: usize) -> usize {
292        let mut it = self.column(col).skip(row);
293
294        // Verify that the cell at the specified location is content,
295        // otherwise we return 0
296        match it.next() {
297            Some(cell) if cell.is_content() => {}
298            _ => return 0,
299        }
300
301        it.take_while(|cell| {
302            matches!(cell.get_span().copied(), Some(CellSpan::FromAbove))
303        })
304        .count()
305            + 1
306    }
307
308    /// Returns the cell's colspan, which is the number of columns (including
309    /// itself) that the cell spans. 1 means that the cell only spans its
310    /// starting column whereas >1 indicates it is 1 or more columns after its
311    /// starting column
312    ///
313    /// Returns 0 for a non-content cell or a cell that doesn't exist
314    pub fn get_cell_colspan(&self, row: usize, col: usize) -> usize {
315        let mut it = self.row(row).skip(col);
316
317        // Verify that the cell at the specified location is content,
318        // otherwise we return 0
319        match it.next() {
320            Some(cell) if cell.is_content() => {}
321            _ => return 0,
322        }
323
324        it.take_while(|cell| {
325            matches!(cell.get_span().copied(), Some(CellSpan::FromLeft))
326        })
327        .count()
328            + 1
329    }
330}
331
332impl<'a> IntoChildren for Table<'a> {
333    type Child = Located<InlineElement<'a>>;
334
335    fn into_children(self) -> Vec<Self::Child> {
336        self.cells
337            .into_iter()
338            .flat_map(|(_, x)| x.into_inner().into_children())
339            .collect()
340    }
341}
342
343impl<'a> StrictEq for Table<'a> {
344    /// Performs strict_eq on cells and centered status
345    fn strict_eq(&self, other: &Self) -> bool {
346        self.centered == other.centered
347            && self.cells.len() == other.cells.len()
348            && self.cells.iter().all(|(k, v)| {
349                other.cells.get(k).map_or(false, |v2| v.strict_eq(v2))
350            })
351    }
352}
353
354/// Represents a cell within a table that is either content, span (indicating
355/// that another cell fills this cell), or a column alignment indicator
356#[derive(Clone, Debug, From, Eq, PartialEq, Hash, Serialize, Deserialize)]
357pub enum Cell<'a> {
358    Content(InlineElementContainer<'a>),
359    Span(CellSpan),
360    Align(ColumnAlign),
361}
362
363impl Cell<'_> {
364    pub fn to_borrowed(&self) -> Cell {
365        match self {
366            Self::Content(x) => Cell::Content(x.to_borrowed()),
367            Self::Span(x) => Cell::Span(*x),
368            Self::Align(x) => Cell::Align(*x),
369        }
370    }
371
372    pub fn into_owned(self) -> Cell<'static> {
373        match self {
374            Self::Content(x) => Cell::Content(x.into_owned()),
375            Self::Span(x) => Cell::Span(x),
376            Self::Align(x) => Cell::Align(x),
377        }
378    }
379}
380
381impl<'a> Cell<'a> {
382    /// Returns true if cell represents a content cell
383    #[inline]
384    pub fn is_content(&self) -> bool {
385        matches!(self, Cell::Content(_))
386    }
387
388    /// Returns true if cell represents a span cell
389    #[inline]
390    pub fn is_span(&self) -> bool {
391        matches!(self, Cell::Span(_))
392    }
393
394    /// Returns true if cell represents a column alignment cell
395    #[inline]
396    pub fn is_align(&self) -> bool {
397        matches!(self, Cell::Align(_))
398    }
399
400    /// Returns a reference to the content of the cell if it has content
401    #[inline]
402    pub fn get_content(&self) -> Option<&InlineElementContainer<'a>> {
403        match self {
404            Self::Content(x) => Some(x),
405            _ => None,
406        }
407    }
408
409    /// Returns a reference to the span of the cell if it is a span
410    #[inline]
411    pub fn get_span(&self) -> Option<&CellSpan> {
412        match self {
413            Self::Span(x) => Some(x),
414            _ => None,
415        }
416    }
417
418    /// Returns a reference to the column alignment of the cell if it is a
419    /// column alignment
420    #[inline]
421    pub fn get_align(&self) -> Option<&ColumnAlign> {
422        match self {
423            Self::Align(x) => Some(x),
424            _ => None,
425        }
426    }
427}
428
429impl<'a> IntoChildren for Cell<'a> {
430    type Child = Located<InlineElement<'a>>;
431
432    fn into_children(self) -> Vec<Self::Child> {
433        match self {
434            Self::Content(x) => x.into_children(),
435            _ => vec![],
436        }
437    }
438}
439
440impl<'a> StrictEq for Cell<'a> {
441    /// Performs strict_eq on cell content
442    fn strict_eq(&self, other: &Self) -> bool {
443        match (self, other) {
444            (Self::Content(x), Self::Content(y)) => x.strict_eq(y),
445            (Self::Span(x), Self::Span(y)) => x == y,
446            (Self::Align(x), Self::Align(y)) => x == y,
447            _ => false,
448        }
449    }
450}
451
452#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
453pub enum CellSpan {
454    FromLeft,
455    FromAbove,
456}
457
458impl StrictEq for CellSpan {
459    /// Same as PartialEq
460    fn strict_eq(&self, other: &Self) -> bool {
461        self == other
462    }
463}
464
465#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
466pub enum ColumnAlign {
467    Left,
468    Center,
469    Right,
470}
471
472impl Default for ColumnAlign {
473    /// By default, columns align to the left
474    fn default() -> Self {
475        Self::Left
476    }
477}
478
479impl StrictEq for ColumnAlign {
480    /// Same as PartialEq
481    fn strict_eq(&self, other: &Self) -> bool {
482        self == other
483    }
484}
485
486pub mod iter {
487    use super::{Cell, CellPos, Located, Table};
488    use derive_more::Constructor;
489
490    pub struct Rows<'a, 'b> {
491        table: &'a Table<'b>,
492        idx: usize,
493    }
494
495    impl<'a, 'b> Rows<'a, 'b> {
496        /// Produces an iterator that will iterator through all rows from the
497        /// beginning of the table
498        pub fn new(table: &'a Table<'b>) -> Self {
499            Self { table, idx: 0 }
500        }
501
502        /// Produces an iterator that will return no rows
503        pub fn empty(table: &'a Table<'b>) -> Self {
504            Self {
505                table,
506                idx: table.row_cnt(),
507            }
508        }
509
510        /// Returns true if the iterator has at least one row remaining that
511        /// contains a content cell
512        pub fn has_content(&self) -> bool {
513            let mut rows = Rows {
514                table: self.table,
515                idx: self.idx,
516            };
517
518            rows.any(|row| row.has_content())
519        }
520    }
521
522    impl<'a, 'b> Iterator for Rows<'a, 'b> {
523        type Item = Row<'a, 'b>;
524
525        fn next(&mut self) -> Option<Self::Item> {
526            if self.idx < self.table.row_cnt() {
527                let row = Row::new(self.table, self.idx, 0);
528                self.idx += 1;
529                Some(row)
530            } else {
531                None
532            }
533        }
534
535        fn size_hint(&self) -> (usize, Option<usize>) {
536            let remaining = self.table.row_cnt() - self.idx;
537            (remaining, Some(remaining))
538        }
539    }
540
541    pub struct HeaderRows<'a, 'b> {
542        table: &'a Table<'b>,
543        idx: usize,
544        len: usize,
545    }
546
547    impl<'a, 'b> HeaderRows<'a, 'b> {
548        /// Produces an iterator that will iterator through all header rows
549        /// from the beginning of the table (no divider rows included)
550        pub fn new(table: &'a Table<'b>) -> Self {
551            Self {
552                table,
553                idx: 0,
554                len: table.get_divider_row_index().unwrap_or_default(),
555            }
556        }
557
558        /// Returns true if the iterator has at least one row remaining that
559        /// contains a content cell
560        pub fn has_content(&self) -> bool {
561            let mut rows = HeaderRows {
562                table: self.table,
563                idx: self.idx,
564                len: self.len,
565            };
566
567            rows.any(|row| row.has_content())
568        }
569    }
570
571    impl<'a, 'b> Iterator for HeaderRows<'a, 'b> {
572        type Item = Row<'a, 'b>;
573
574        fn next(&mut self) -> Option<Self::Item> {
575            // Continually advance our ptr while we still have potential
576            // header rows AND our current row is a divider
577            while self.idx < self.len {
578                let row = Row::new(self.table, self.idx, 0);
579                self.idx += 1;
580
581                if !row.is_divider_row() {
582                    return Some(row);
583                }
584            }
585
586            None
587        }
588
589        fn size_hint(&self) -> (usize, Option<usize>) {
590            let remaining = self.len - self.idx;
591            (remaining, Some(remaining))
592        }
593    }
594
595    pub struct BodyRows<'a, 'b> {
596        table: &'a Table<'b>,
597        idx: usize,
598    }
599
600    impl<'a, 'b> BodyRows<'a, 'b> {
601        /// Produces an iterator that will iterator through all body rows
602        /// from the beginning of the table (no divider rows included)
603        pub fn new(table: &'a Table<'b>) -> Self {
604            Self {
605                table,
606                idx: table.get_divider_row_index().unwrap_or_default(),
607            }
608        }
609
610        /// Returns true if the iterator has at least one row remaining that
611        /// contains a content cell
612        pub fn has_content(&self) -> bool {
613            let mut rows = BodyRows {
614                table: self.table,
615                idx: self.idx,
616            };
617
618            rows.any(|row| row.has_content())
619        }
620    }
621
622    impl<'a, 'b> Iterator for BodyRows<'a, 'b> {
623        type Item = Row<'a, 'b>;
624
625        fn next(&mut self) -> Option<Self::Item> {
626            // Continually advance our ptr while we still have potential
627            // body rows AND our current row is a divider
628            while self.idx < self.table.row_cnt() {
629                let row = Row::new(self.table, self.idx, 0);
630                self.idx += 1;
631
632                if !row.is_divider_row() {
633                    return Some(row);
634                }
635            }
636
637            None
638        }
639
640        fn size_hint(&self) -> (usize, Option<usize>) {
641            let remaining = self.table.row_cnt() - self.idx;
642            (remaining, Some(remaining))
643        }
644    }
645
646    #[derive(Constructor)]
647    pub struct Row<'a, 'b> {
648        table: &'a Table<'b>,
649        row: usize,
650        col: usize,
651    }
652
653    impl<'a, 'b> Row<'a, 'b> {
654        pub fn is_divider_row(&self) -> bool {
655            // NOTE: Due to way that table is built, we only need to check
656            //       the first cell in a row to determine if it's a divider
657            self.table
658                .get_cell(self.row, 0)
659                .map_or(false, |cell| cell.is_align())
660        }
661
662        pub fn zip_with_position(
663            self,
664        ) -> impl Iterator<Item = (CellPos, &'a Located<Cell<'b>>)> {
665            let pos = CellPos::new(self.row, self.col);
666            self.map(move |cell| (pos, cell))
667        }
668
669        /// Returns true if the iterator has at least one content cell
670        pub fn has_content(&self) -> bool {
671            let mut row = Row {
672                table: self.table,
673                row: self.row,
674                col: self.col,
675            };
676
677            row.any(|cell| cell.is_content())
678        }
679    }
680
681    impl<'a, 'b> Iterator for Row<'a, 'b> {
682        type Item = &'a Located<Cell<'b>>;
683
684        fn next(&mut self) -> Option<Self::Item> {
685            let cell = self.table.get_cell(self.row, self.col);
686            if cell.is_some() {
687                self.col += 1;
688            }
689            cell
690        }
691
692        fn size_hint(&self) -> (usize, Option<usize>) {
693            let remaining = self.table.col_cnt() - self.col;
694            (remaining, Some(remaining))
695        }
696    }
697
698    #[derive(Constructor)]
699    pub struct IntoRow<'a> {
700        table: Table<'a>,
701        row: usize,
702        col: usize,
703    }
704
705    impl<'a> IntoRow<'a> {
706        pub fn is_divider_row(&self) -> bool {
707            // NOTE: Due to way that table is built, we only need to check
708            //       the first cell in a row to determine if it's a divider
709            self.table
710                .get_cell(self.row, 0)
711                .map_or(false, |cell| cell.is_align())
712        }
713
714        pub fn zip_with_position(
715            self,
716        ) -> impl Iterator<Item = (CellPos, Located<Cell<'a>>)> {
717            let pos = CellPos::new(self.row, self.col);
718            self.map(move |cell| (pos, cell))
719        }
720
721        /// Returns true if the iterator has at least one content cell
722        pub fn has_content(&self) -> bool {
723            Row::from(self).has_content()
724        }
725    }
726
727    impl<'a, 'b> From<&'a IntoRow<'b>> for Row<'a, 'b> {
728        fn from(it: &'a IntoRow<'b>) -> Self {
729            Self {
730                table: &it.table,
731                row: it.row,
732                col: it.col,
733            }
734        }
735    }
736
737    impl<'a> Iterator for IntoRow<'a> {
738        type Item = Located<Cell<'a>>;
739
740        fn next(&mut self) -> Option<Self::Item> {
741            let cell =
742                self.table.cells.remove(&CellPos::new(self.row, self.col));
743            if cell.is_some() {
744                self.col += 1;
745            }
746            cell
747        }
748
749        fn size_hint(&self) -> (usize, Option<usize>) {
750            let remaining = self.table.col_cnt() - self.col;
751            (remaining, Some(remaining))
752        }
753    }
754
755    pub struct Columns<'a, 'b> {
756        table: &'a Table<'b>,
757        idx: usize,
758    }
759
760    impl<'a, 'b> Columns<'a, 'b> {
761        /// Produces an iterator that will iterator through all columns from the
762        /// beginning of the table
763        pub fn new(table: &'a Table<'b>) -> Self {
764            Self { table, idx: 0 }
765        }
766
767        /// Produces an iterator that will return no columns
768        pub fn empty(table: &'a Table<'b>) -> Self {
769            Self {
770                table,
771                idx: table.col_cnt(),
772            }
773        }
774
775        /// Returns true if the iterator has at least one column remaining that
776        /// contains a content cell
777        pub fn has_content(&self) -> bool {
778            let mut columns = Columns {
779                table: self.table,
780                idx: self.idx,
781            };
782
783            columns.any(|column| column.has_content())
784        }
785    }
786
787    impl<'a, 'b> Iterator for Columns<'a, 'b> {
788        type Item = Column<'a, 'b>;
789
790        fn next(&mut self) -> Option<Self::Item> {
791            if self.idx < self.table.col_cnt() {
792                let col = Column::new(self.table, self.idx, 0);
793                self.idx += 1;
794                Some(col)
795            } else {
796                None
797            }
798        }
799
800        fn size_hint(&self) -> (usize, Option<usize>) {
801            let remaining = self.table.col_cnt() - self.idx;
802            (remaining, Some(remaining))
803        }
804    }
805
806    #[derive(Constructor)]
807    pub struct Column<'a, 'b> {
808        table: &'a Table<'b>,
809        row: usize,
810        col: usize,
811    }
812
813    impl<'a, 'b> Column<'a, 'b> {
814        pub fn zip_with_position(
815            self,
816        ) -> impl Iterator<Item = (CellPos, &'a Located<Cell<'b>>)> {
817            let pos = CellPos::new(self.row, self.col);
818            self.map(move |cell| (pos, cell))
819        }
820
821        /// Returns true if the iterator has at least one content cell
822        pub fn has_content(&self) -> bool {
823            let mut column = Column {
824                table: self.table,
825                row: self.row,
826                col: self.col,
827            };
828
829            column.any(|cell| cell.is_content())
830        }
831    }
832
833    impl<'a, 'b> Iterator for Column<'a, 'b> {
834        type Item = &'a Located<Cell<'b>>;
835
836        fn next(&mut self) -> Option<Self::Item> {
837            let cell = self.table.get_cell(self.row, self.col);
838            if cell.is_some() {
839                self.row += 1;
840            }
841            cell
842        }
843
844        fn size_hint(&self) -> (usize, Option<usize>) {
845            let remaining = self.table.row_cnt() - self.row;
846            (remaining, Some(remaining))
847        }
848    }
849
850    #[derive(Constructor)]
851    pub struct IntoColumn<'a> {
852        table: Table<'a>,
853        row: usize,
854        col: usize,
855    }
856
857    impl<'a> IntoColumn<'a> {
858        pub fn zip_with_position(
859            self,
860        ) -> impl Iterator<Item = (CellPos, Located<Cell<'a>>)> {
861            let pos = CellPos::new(self.row, self.col);
862            self.map(move |cell| (pos, cell))
863        }
864
865        /// Returns true if the iterator has at least one content cell
866        pub fn has_content(&self) -> bool {
867            Column::from(self).has_content()
868        }
869    }
870
871    impl<'a, 'b> From<&'a IntoColumn<'b>> for Column<'a, 'b> {
872        fn from(it: &'a IntoColumn<'b>) -> Self {
873            Self {
874                table: &it.table,
875                row: it.row,
876                col: it.col,
877            }
878        }
879    }
880
881    impl<'a> Iterator for IntoColumn<'a> {
882        type Item = Located<Cell<'a>>;
883
884        fn next(&mut self) -> Option<Self::Item> {
885            let cell =
886                self.table.cells.remove(&CellPos::new(self.row, self.col));
887            if cell.is_some() {
888                self.row += 1;
889            }
890            cell
891        }
892
893        fn size_hint(&self) -> (usize, Option<usize>) {
894            let remaining = self.table.row_cnt() - self.row;
895            (remaining, Some(remaining))
896        }
897    }
898
899    pub struct Cells<'a, 'b> {
900        table: &'a Table<'b>,
901        row: usize,
902        col: usize,
903    }
904
905    impl<'a, 'b> Cells<'a, 'b> {
906        pub fn new(table: &'a Table<'b>) -> Self {
907            Self {
908                table,
909                row: 0,
910                col: 0,
911            }
912        }
913
914        pub fn zip_with_position(
915            self,
916        ) -> impl Iterator<Item = (CellPos, &'a Located<Cell<'b>>)> {
917            let pos = CellPos::new(self.row, self.col);
918            self.map(move |cell| (pos, cell))
919        }
920
921        /// Returns true if the iterator has at least one content cell
922        pub fn has_content(&self) -> bool {
923            let mut cells = Cells {
924                table: self.table,
925                row: self.row,
926                col: self.col,
927            };
928
929            cells.any(|cell| cell.is_content())
930        }
931    }
932
933    impl<'a, 'b> Iterator for Cells<'a, 'b> {
934        type Item = &'a Located<Cell<'b>>;
935
936        fn next(&mut self) -> Option<Self::Item> {
937            let cell = self.table.get_cell(self.row, self.col);
938
939            // If not yet reached end of row, advance column ptr
940            if self.col < self.table.col_cnt() {
941                self.col += 1;
942
943            // Else if not yet reached end of all rows, advance row ptr and
944            // reset column ptr
945            } else if self.row < self.table.row_cnt() {
946                self.row += 1;
947                self.col = 0;
948            }
949
950            cell
951        }
952
953        fn size_hint(&self) -> (usize, Option<usize>) {
954            let remaining =
955                self.table.len() - (self.row * self.table.col_cnt()) - self.col;
956            (remaining, Some(remaining))
957        }
958    }
959
960    pub struct IntoCells<'a> {
961        table: Table<'a>,
962        row: usize,
963        col: usize,
964    }
965
966    impl<'a> IntoCells<'a> {
967        pub fn new(table: Table<'a>) -> Self {
968            Self {
969                table,
970                row: 0,
971                col: 0,
972            }
973        }
974
975        pub fn zip_with_position(
976            self,
977        ) -> impl Iterator<Item = (CellPos, Located<Cell<'a>>)> {
978            let pos = CellPos::new(self.row, self.col);
979            self.map(move |cell| (pos, cell))
980        }
981
982        /// Returns true if the iterator has at least one content cell
983        pub fn has_content(&self) -> bool {
984            Cells::from(self).has_content()
985        }
986    }
987
988    impl<'a, 'b> From<&'a IntoCells<'b>> for Cells<'a, 'b> {
989        fn from(it: &'a IntoCells<'b>) -> Self {
990            Self {
991                table: &it.table,
992                row: it.row,
993                col: it.col,
994            }
995        }
996    }
997
998    impl<'a> Iterator for IntoCells<'a> {
999        type Item = Located<Cell<'a>>;
1000
1001        fn next(&mut self) -> Option<Self::Item> {
1002            let cell =
1003                self.table.cells.remove(&CellPos::new(self.row, self.col));
1004
1005            // If not yet reached end of row, advance column ptr
1006            if self.col < self.table.col_cnt() {
1007                self.col += 1;
1008
1009            // Else if not yet reached end of all rows, advance row ptr and
1010            // reset column ptr
1011            } else if self.row < self.table.row_cnt() {
1012                self.row += 1;
1013                self.col = 0;
1014            }
1015
1016            cell
1017        }
1018
1019        fn size_hint(&self) -> (usize, Option<usize>) {
1020            let remaining =
1021                self.table.len() - (self.row * self.table.col_cnt()) - self.col;
1022            (remaining, Some(remaining))
1023        }
1024    }
1025}