blob: dcc7370396e259793eb7b415821ab7fb04b21d5e [file] [log] [blame]
use std::{
fmt::{self, Display},
iter::FromIterator,
string::ToString,
};
use tabled::{
grid::config::ColoredConfig,
grid::dimension::CompleteDimensionVecRecords,
grid::records::vec_records::{CellInfo, 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<Vec<String>>,
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<Vec<String>> {
Self::new(rows, columns).to_vec()
}
pub fn table(rows: usize, columns: usize) -> Table {
Self::new(rows, columns).to_table()
}
pub fn list<const ROWS: usize, const COLUMNS: usize>() -> Vec<MatrixList<COLUMNS, true>> {
create_list::<ROWS, COLUMNS>()
}
pub fn iter<I, T>(iter: I) -> Table
where
I: IntoIterator<Item = T>,
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<V: ToString>(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<Vec<String>> {
self.data.clone()
}
pub fn with<O>(self, opt: O) -> Table
where
for<'a> O: TableOption<
VecRecords<CellInfo<String>>,
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<Vec<String>> {
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<Vec<String>>, columns: usize) {
data.insert(
0,
(0..columns)
.map(|n| format!("column {n}"))
.collect::<Vec<_>>(),
);
}
fn set_index(data: &mut [Vec<String>]) {
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<const ROWS: usize, const COLUMNS: usize>() -> Vec<MatrixList<COLUMNS, true>> {
let mut arr = Vec::with_capacity(ROWS);
for row in 0..ROWS {
let data = (0..COLUMNS)
.map(|column| format!("{row}-{column}"))
.collect::<Vec<_>>();
let list = MatrixList::with_index(row, data);
arr.push(list);
}
arr
}