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
12pub 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
82pub trait Row {
84 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#[derive(Debug, Default, Clone, Eq, PartialEq)]
107pub(crate) struct Dimension {
108 pub(crate) widths: Vec<usize>,
110 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}