tabled 0.20.0

An easy to use library for pretty print tables of Rust `struct`s and `enum`s.
Documentation
// TODO: simplify this module it's too complex for what it is
#![allow(unused_imports, dead_code)]

use std::{
    fmt::{self, Display},
    iter::FromIterator,
    string::ToString,
};

use tabled::{
    grid::config::ColoredConfig,
    grid::dimension::CompleteDimension,
    grid::records::vec_records::{Text, VecRecords},
    settings::{object::Segment, Alignment, Modify, TableOption},
    Table, Tabled,
};

use super::matrix_list::MatrixList;

// TODO: Remove the structure and make it a construction factory instead for original Table.

/// 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.row][pos.col] = 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
        O: TableOption<VecRecords<Text<String>>, ColoredConfig, CompleteDimension>,
    {
        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
}

// // TODO: simplify this module it's too complex for what it is
// #![allow(unused_imports, dead_code)]

// // todo: remame mod to util.

// use std::{
//     fmt::{self, Display},
//     iter::FromIterator,
//     string::ToString,
// };

// use tabled::{
//     builder::Builder,
//     grid::{
//         config::ColoredConfig,
//         dimension::CompleteDimension,
//         records::vec_records::{Text, VecRecords},
//     },
//     settings::{object::Segment, Alignment, Modify, TableOption},
//     Table, Tabled,
// };

// /// A helper table factory.
// ///
// /// It uses center alignment by default, because it's more complex and may spot more issues.
// #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
// pub struct Matrix;

// impl Matrix {
//     pub fn empty() -> Table {
//         Builder::new().build()
//     }

//     pub fn noframe(rows: usize, columns: usize) -> Table {
//         let data = create_matrix(rows, columns, false, false);
//         Builder::from(data).build()
//     }

//     pub fn with_index(rows: usize, columns: usize) -> Table {
//         let data = create_matrix(rows, columns, false, true);
//         Builder::from(data).build()
//     }

//     pub fn with_head(rows: usize, columns: usize) -> Table {
//         let data = create_matrix(rows, columns, false, false);
//         Builder::from(data).build()
//     }

//     pub fn new(rows: usize, columns: usize) -> Table {
//         let data = create_matrix(rows, columns, true, true);
//         Builder::from(data).build()
//     }
// }

// fn create_matrix(rows: usize, columns: usize, head: bool, index: bool) -> Vec<Vec<Text<String>>> {
//     let mut arr = Vec::with_capacity(rows + head as usize);

//     if head {
//         let mut data = Vec::with_capacity(columns + index as usize);
//         if index {
//             let text = Text::new(format!("N"));
//             data.push(text);
//         }

//         data.extend((0..columns).map(|n| Text::new(format!("column {n}"))));
//     }

//     for row in 0..rows {
//         let mut data = Vec::with_capacity(columns + index as usize);

//         if index {
//             let text = Text::new(format!("{row}"));
//             data.push(text);
//         }

//         for column in 0..columns {
//             let text = Text::new(format!("{row}-{column}"));
//             data.push(text);
//         }

//         arr.push(data);
//     }

//     arr
// }