mod cell;
mod row;
use std::{
collections::HashSet,
io::{self, Write},
path::Path,
};
use crate::file::{FileWriter, csv::CsvWriter};
pub use crate::table::{
cell::{Align, Style},
row::{ColumnJoinType, Row},
};
#[derive(Default)]
pub struct Table {
header: Option<Row>,
rows: Vec<Row>,
spacers: HashSet<usize>,
row_len: usize,
}
impl Table {
#[inline]
pub fn set_header(&mut self, header: Row) {
assert!(
self.rows.is_empty() || header.len() == self.row_len,
"Invalid number of columns in row.",
);
self.row_len = header.len();
self.header = Some(header);
self.spacers.insert(1);
}
#[inline]
pub fn add_row(&mut self, row: Row) {
assert!(
self.rows.is_empty() || row.len() == self.row_len,
"Invalid number of columns in row.",
);
self.row_len = row.len();
self.rows.push(row);
}
#[inline]
pub fn add_spacer(&mut self) {
let mut index = self.rows.len();
if self.header.is_some() {
index += 1;
}
self.spacers.insert(index);
}
pub fn print(&self, stdout: &mut impl Write) {
let mut index: usize = 0;
let column_lens = self.max_column_lens();
if self.spacers.contains(&index) {
print_spacer_row(stdout, &column_lens);
}
if let Some(header) = &self.header {
index += 1;
header.print(stdout, &column_lens, ColumnJoinType::Spaced);
if self.spacers.contains(&index) {
print_spacer_row(stdout, &column_lens);
}
}
for row in &self.rows {
index += 1;
row.print(stdout, &column_lens, ColumnJoinType::Spaced);
if self.spacers.contains(&index) {
print_spacer_row(stdout, &column_lens);
}
}
}
pub fn to_file<P>(&self, path: P) -> io::Result<()>
where
P: AsRef<Path>,
{
let mut writer = CsvWriter::<Row>::from_path(path)?;
if let Some(header) = &self.header {
writer.write_row(header).unwrap();
}
for row in &self.rows {
writer.write_row(row).unwrap();
}
Ok(())
}
fn max_column_lens(&self) -> Vec<usize> {
let mut sizes: Vec<usize> = vec![0; self.row_len];
if let Some(header) = &self.header {
for (index, size) in sizes.iter_mut().enumerate() {
let row_column_size = header.get_column_size(index);
if row_column_size > *size {
*size = row_column_size;
}
}
}
for row in &self.rows {
for (index, size) in sizes.iter_mut().enumerate() {
let row_column_size = row.get_column_size(index);
if row_column_size > *size {
*size = row_column_size;
}
}
}
sizes
}
}
fn print_spacer_row(stdout: &mut impl Write, sizes: &Vec<usize>) {
let mut row = Row::default();
for size in sizes {
let value = vec!["-"; *size + 2].join("");
row = row.push(value, Align::Left, Style::Normal);
}
row.print(stdout, sizes, ColumnJoinType::Plus);
}