pretty_table/
table.rs

1//! # Table
2//!
3
4use crate::TableOptions;
5use std::ops::Div;
6
7const THIN_HR_LINE_CHAR: &'static str = "-";
8const THICK_HR_LINE_CHAR: &'static str = "=";
9const THIN_VR_LINE_CHAR: &'static str = "|";
10
11/// This is a utility function used to convert raw 2-D Vectors of strings into a formatter vector of strings
12/// that represents table structure.
13pub fn generate_table_string_vec<S>(rows: Vec<Vec<S>>, options: Option<TableOptions>) -> Vec<String>
14where
15    S: Into<String>,
16{
17    let mut table_string_vec: Vec<String> = Vec::new();
18    let _options = options.unwrap_or_default();
19    let mut size_arr: Vec<usize> = vec![0; rows[0].len()];
20
21    let rows = rows
22        .into_iter()
23        .map(|row| {
24            row.into_iter()
25                .enumerate()
26                .map(|(cell_no, cell)| {
27                    let cell_string: String = cell.into();
28
29                    if (cell_string.len() + 2) > size_arr[cell_no] {
30                        size_arr[cell_no] = cell_string.len() + 2;
31                    }
32
33                    cell_string
34                })
35                .collect::<Vec<String>>()
36        })
37        .collect::<Vec<Vec<String>>>();
38
39    enum HrLineType {
40        Header,
41        Cell,
42    }
43
44    let draw_hr_line = |line_type: HrLineType| -> String {
45        let mut line_string = String::from("+");
46
47        for size in size_arr.iter() {
48            match line_type {
49                HrLineType::Header => line_string.push_str(&THICK_HR_LINE_CHAR.repeat(*size)),
50                HrLineType::Cell => line_string.push_str(&THIN_HR_LINE_CHAR.repeat(*size)),
51            }
52
53            line_string.push('+');
54        }
55
56        line_string
57    };
58
59    let compute_spaces = |string_size: usize, reserved_size: usize| -> (usize, usize) {
60        let partitioned_space = (reserved_size - string_size).div(2);
61
62        match (reserved_size - string_size) % 2 == 0 {
63            true => (partitioned_space, partitioned_space),
64            false => (partitioned_space, partitioned_space + 1),
65        }
66    };
67
68    table_string_vec.push(draw_hr_line(HrLineType::Header));
69    table_string_vec.push({
70        // processing headers to form the first row
71        let mut header_row: String = String::from(THIN_VR_LINE_CHAR.to_string());
72
73        for i in 0..rows[0].len() {
74            let spaces = compute_spaces(rows[0][i].len(), size_arr[i]);
75            header_row.push_str(&format!(
76                "{}{}{}{THIN_VR_LINE_CHAR}",
77                " ".repeat(spaces.0),
78                rows[0][i],
79                " ".repeat(spaces.1)
80            ));
81        }
82
83        header_row
84    });
85    table_string_vec.push(draw_hr_line(HrLineType::Header));
86
87    // processing all data rows in the table
88    for row_no in 1..rows.len() {
89        let mut row_string: String = String::from(THIN_VR_LINE_CHAR.to_string());
90        for col_no in 0..rows[row_no].len() {
91            let spaces = compute_spaces(rows[row_no][col_no].len(), size_arr[col_no]);
92            row_string.push_str(&format!(
93                "{}{}{}{THIN_VR_LINE_CHAR}",
94                " ".repeat(spaces.0),
95                rows[row_no][col_no],
96                " ".repeat(spaces.1)
97            ));
98        }
99        table_string_vec.push(row_string);
100        table_string_vec.push(draw_hr_line(HrLineType::Cell));
101    }
102
103    table_string_vec
104}