use std::{ fmt::{self, Display}, iter::FromIterator, string::ToString, }; use tabled::{ grid::config::ColoredConfig, grid::dimension::CompleteDimensionVecRecords, grid::records::vec_records::{Text, VecRecords}, settings::{object::Segment, Alignment, Modify, TableOption}, Table, Tabled, }; use super::matrix_list::MatrixList; /// A helper table factory. /// /// It uses center alignment by default, because it's more complex and may spot more issues. #[derive(Debug, Clone)] pub struct Matrix { data: Vec>, size: (usize, usize), } impl Matrix { pub fn empty() -> Self { Self { data: vec![], size: (0, 0), } } pub fn with_no_frame(rows: usize, columns: usize) -> Self { Self { data: create_matrix(rows, columns), size: (rows, columns), } } pub fn new(rows: usize, columns: usize) -> Self { Self::with_no_frame(rows, columns) .with_header() .with_index() } pub fn vec(rows: usize, columns: usize) -> Vec> { Self::new(rows, columns).to_vec() } pub fn table(rows: usize, columns: usize) -> Table { Self::new(rows, columns).to_table() } pub fn list() -> Vec> { create_list::() } pub fn iter(iter: I) -> Table where I: IntoIterator, T: Tabled, { let mut table = tabled::Table::new(iter); table.with(Modify::new(Segment::all()).with(Alignment::center())); table } pub fn with_index(mut self) -> Self { set_index(&mut self.data); self } pub fn with_header(mut self) -> Self { set_header(&mut self.data, self.size.1); self } pub fn insert(mut self, pos: tabled::grid::config::Position, value: V) -> Self { self.data[pos.0][pos.1] = value.to_string(); self } pub fn to_table(&self) -> Table { let mut table = tabled::Table::from_iter(self.data.clone()); table.with(Modify::new(Segment::all()).with(Alignment::center())); table } pub fn to_vec(&self) -> Vec> { self.data.clone() } pub fn with(self, opt: O) -> Table where for<'a> O: TableOption>, ColoredConfig, CompleteDimensionVecRecords<'a>>, { let mut table = self.to_table(); table.with(opt); table } } impl Display for Matrix { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.clone().to_table().fmt(f) } } fn create_matrix(rows: usize, columns: usize) -> Vec> { let mut arr = Vec::with_capacity(rows); for row in 0..rows { let mut data = Vec::with_capacity(columns); for column in 0..columns { let text = format!("{row}-{column}"); data.push(text); } arr.push(data); } arr } fn set_header(data: &mut Vec>, columns: usize) { data.insert( 0, (0..columns) .map(|n| format!("column {n}")) .collect::>(), ); } fn set_index(data: &mut [Vec]) { if data.is_empty() { return; } data[0].insert(0, "N".to_owned()); for (n, row) in data.iter_mut().skip(1).enumerate() { row.insert(0, n.to_string()); } } fn create_list() -> Vec> { let mut arr = Vec::with_capacity(ROWS); for row in 0..ROWS { let data = (0..COLUMNS) .map(|column| format!("{row}-{column}")) .collect::>(); let list = MatrixList::with_index(row, data); arr.push(list); } arr }