cli_table/
row.rs

1use std::io::Result;
2
3use termcolor::{Buffer, BufferWriter, ColorSpec};
4
5use crate::{
6    buffers::Buffers,
7    cell::{Cell, CellStruct, Dimension as CellDimension},
8    table::{Dimension as TableDimension, TableFormat},
9    utils::{print_char, print_vertical_line, println, transpose},
10};
11
12/// Concrete row of a table
13pub struct RowStruct {
14    pub(crate) cells: Vec<CellStruct>,
15}
16
17impl RowStruct {
18    pub(crate) fn required_dimension(&self) -> Dimension {
19        let mut widths = Vec::with_capacity(self.cells.len());
20        let mut height = 0;
21
22        for cell in self.cells.iter() {
23            let cell_dimension = cell.required_dimension();
24
25            widths.push(cell_dimension.width);
26
27            height = std::cmp::max(cell_dimension.height, height);
28        }
29
30        Dimension { widths, height }
31    }
32
33    pub(crate) fn buffers(
34        &self,
35        writer: &BufferWriter,
36        available_dimension: Dimension,
37        format: &TableFormat,
38        color_spec: &ColorSpec,
39    ) -> Result<Vec<Buffer>> {
40        let available_cell_dimensions: Vec<CellDimension> = available_dimension.into();
41
42        let cell_buffers = self
43            .cells
44            .iter()
45            .zip(available_cell_dimensions.into_iter())
46            .map(|(cell, available_dimension)| cell.buffers(writer, available_dimension))
47            .collect::<Result<Vec<Vec<Buffer>>>>()?;
48
49        let cell_buffers = transpose(cell_buffers);
50
51        let mut buffers = Buffers::new(writer);
52
53        for line in cell_buffers {
54            print_vertical_line(&mut buffers, format.border.left.as_ref(), color_spec)?;
55
56            let mut line_buffers = line.into_iter().peekable();
57
58            while let Some(line_buffer) = line_buffers.next() {
59                print_char(&mut buffers, ' ', color_spec)?;
60                buffers.push(line_buffer)?;
61                print_char(&mut buffers, ' ', color_spec)?;
62
63                match line_buffers.peek() {
64                    Some(_) => print_vertical_line(
65                        &mut buffers,
66                        format.separator.column.as_ref(),
67                        color_spec,
68                    )?,
69                    None => {
70                        print_vertical_line(&mut buffers, format.border.right.as_ref(), color_spec)?
71                    }
72                }
73            }
74
75            println(&mut buffers)?;
76        }
77
78        buffers.into_vec()
79    }
80}
81
82/// Trait to convert raw types into rows
83pub trait Row {
84    /// Converts raw type to rows of a table
85    fn row(self) -> RowStruct;
86}
87
88impl<T, C> Row for T
89where
90    T: IntoIterator<Item = C>,
91    C: Cell,
92{
93    fn row(self) -> RowStruct {
94        let cells = self.into_iter().map(|cell| cell.cell()).collect();
95        RowStruct { cells }
96    }
97}
98
99impl Row for RowStruct {
100    fn row(self) -> RowStruct {
101        self
102    }
103}
104
105/// Dimensions of a row
106#[derive(Debug, Default, Clone, Eq, PartialEq)]
107pub(crate) struct Dimension {
108    /// Widths of each cell of row
109    pub(crate) widths: Vec<usize>,
110    /// Height of row
111    pub(crate) height: usize,
112}
113
114impl From<TableDimension> for Vec<Dimension> {
115    fn from(table_dimension: TableDimension) -> Self {
116        let heights = table_dimension.heights;
117        let widths = table_dimension.widths;
118
119        heights
120            .into_iter()
121            .map(|height| Dimension {
122                widths: widths.clone(),
123                height,
124            })
125            .collect()
126    }
127}
128
129#[cfg(test)]
130mod tests {
131    use crate::style::Style;
132
133    use super::*;
134
135    #[test]
136    fn test_into_row_with_style() {
137        let row = vec!["Hello".cell().bold(true), "World".cell()].row();
138        assert_eq!(2, row.cells.len());
139    }
140
141    #[test]
142    fn test_into_row() {
143        let row = &["Hello", "World"].row();
144        assert_eq!(2, row.cells.len());
145    }
146}