extern crate unicode_width;
extern crate term;
use std::io;
use std::io::{Write, Error};
use std::fmt;
use std::iter::{FromIterator, IntoIterator};
use std::ops::{Index, IndexMut};
use std::mem::transmute;
use term::{Terminal, stdout};
pub mod cell;
pub mod row;
pub mod format;
mod utils;
use row::Row;
use cell::Cell;
use format::{TableFormat, FORMAT_DEFAULT};
use utils::StringWriter;
#[derive(Clone, Debug)]
pub struct Table {
format: Box<TableFormat>,
titles: Box<Option<Row>>,
rows: Vec<Row>
}
#[derive(Clone, Debug)]
pub struct TableSlice<'a> {
format: &'a TableFormat,
titles: &'a Option<Row>,
rows: &'a [Row]
}
impl <'a> TableSlice<'a> {
pub fn get_column_num(&self) -> usize {
let mut cnum = 0;
for r in self.rows {
let l = r.len();
if l > cnum {
cnum = l;
}
}
return cnum;
}
pub fn len(&self) -> usize {
return self.rows.len();
}
pub fn get_row(&self, row: usize) -> Option<&Row> {
return self.rows.get(row);
}
fn get_column_width(&self, col_idx: usize) -> usize {
let mut width = match *self.titles {
Some(ref t) => t.get_cell_width(col_idx),
None => 0
};
for r in self.rows {
let l = r.get_cell_width(col_idx);
if l > width {
width = l;
}
}
return width;
}
fn get_all_column_width(&self) -> Vec<usize> {
let colnum = self.get_column_num();
let mut col_width = vec![0usize; colnum];
for i in 0..colnum {
col_width[i] = self.get_column_width(i);
}
return col_width;
}
pub fn column_iter(&self, column: usize) -> ColumnIter {
return ColumnIter(self.rows.iter(), column);
}
fn __print<T: Write+?Sized, F>(&self, out: &mut T, f: F) -> Result<(), Error>
where F: Fn(&Row, &mut T, &TableFormat, &[usize]) -> Result<(), Error> {
let col_width = self.get_all_column_width();
try!(self.format.print_line_separator(out, &col_width));
if let Some(ref t) = *self.titles {
try!(f(t, out, &self.format, &col_width));
try!(self.format.print_title_separator(out, &col_width));
}
for r in self.rows {
try!(f(r, out, &self.format, &col_width));
try!(self.format.print_line_separator(out, &col_width));
}
return out.flush();
}
pub fn print<T: Write+?Sized>(&self, out: &mut T) -> Result<(), Error> {
return self.__print(out, Row::print);
}
pub fn print_term<T: Terminal+?Sized>(&self, out: &mut T) -> Result<(), Error> {
return self.__print(out, Row::print_term);
}
pub fn printstd(&self) {
let r = match stdout() {
Some(mut o) => self.print_term(&mut *o),
None => self.print(&mut io::stdout()),
};
if let Err(e) = r {
panic!("Cannot print table to standard output : {}", e);
}
}
}
impl Table {
pub fn new() -> Table {
return Self::init(Vec::new());
}
pub fn init(rows: Vec<Row>) -> Table {
return Table {
rows: rows,
titles: Box::new(None),
format: Box::new(FORMAT_DEFAULT)
};
}
pub fn set_format(&mut self, format: TableFormat) {
*self.format = format;
}
pub fn get_column_num(&self) -> usize {
return self.as_ref().get_column_num();
}
pub fn len(&self) -> usize {
return self.rows.len();
}
pub fn set_titles(&mut self, titles: Row) {
*self.titles = Some(titles);
}
pub fn unset_titles(&mut self) {
*self.titles = None;
}
pub fn get_mut_row(&mut self, row: usize) -> Option<&mut Row> {
return self.rows.get_mut(row);
}
pub fn get_row(&self, row: usize) -> Option<&Row> {
return self.rows.get(row);
}
pub fn add_row(&mut self, row: Row) -> &mut Row {
self.rows.push(row);
let l = self.rows.len()-1;
return &mut self.rows[l];
}
pub fn add_empty_row(&mut self) -> &mut Row {
return self.add_row(Row::default());
}
pub fn insert_row(&mut self, index: usize, row: Row) -> &mut Row {
if index < self.rows.len() {
self.rows.insert(index, row);
return &mut self.rows[index];
} else {
return self.add_row(row);
}
}
pub fn set_element(&mut self, element: &str, column: usize, row: usize) -> Result<(), &str> {
let rowline = try!(self.get_mut_row(row).ok_or("Cannot find row"));
return rowline.set_cell(Cell::new(element), column);
}
pub fn remove_row(&mut self, index: usize) {
if index < self.rows.len() {
self.rows.remove(index);
}
}
pub fn get_column_width(&self, col_idx: usize) -> usize {
return self.as_ref().get_column_width(col_idx);
}
pub fn get_all_column_width(&self) -> Vec<usize> {
return self.as_ref().get_all_column_width();
}
pub fn column_iter(&self, column: usize) -> ColumnIter {
return ColumnIter(self.rows.iter(), column);
}
pub fn column_iter_mut(&mut self, column: usize) -> ColumnIterMut {
return ColumnIterMut(self.rows.iter_mut(), column);
}
pub fn print<T: Write+?Sized>(&self, out: &mut T) -> Result<(), Error> {
return self.as_ref().print(out);
}
pub fn print_term<T: Terminal+?Sized>(&self, out: &mut T) -> Result<(), Error> {
return self.as_ref().print_term(out);
}
pub fn printstd(&self) {
self.as_ref().printstd();
}
}
impl Index<usize> for Table {
type Output = Row;
fn index(&self, idx: usize) -> &Self::Output {
return &self.rows[idx];
}
}
impl <'a> Index<usize> for TableSlice<'a> {
type Output = Row;
fn index(&self, idx: usize) -> &Self::Output {
return &self.rows[idx];
}
}
impl IndexMut<usize> for Table {
fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
return &mut self.rows[idx];
}
}
impl fmt::Display for Table {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
return self.as_ref().fmt(fmt);
}
}
impl <'a> fmt::Display for TableSlice<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let mut writer = StringWriter::new();
if let Err(_) = self.print(&mut writer) {
return Err(fmt::Error)
}
return fmt.write_str(writer.as_string());
}
}
impl <B: ToString, A: IntoIterator<Item=B>> FromIterator<A> for Table {
fn from_iter<T>(iterator: T) -> Table where T: IntoIterator<Item=A> {
return Self::init(iterator.into_iter().map(|r| Row::from(r)).collect());
}
}
impl <T, A, B> From<T> for Table where B: ToString, A: IntoIterator<Item=B>, T : IntoIterator<Item=A> {
fn from(it: T) -> Table {
return Self::from_iter(it);
}
}
pub struct ColumnIter<'a>(std::slice::Iter<'a, Row>, usize);
impl <'a> std::iter::Iterator for ColumnIter<'a> {
type Item = &'a Cell;
fn next(&mut self) -> Option<&'a Cell> {
return match self.0.next() {
None => None,
Some(row) => row.get_cell(self.1)
}
}
}
pub struct ColumnIterMut<'a>(std::slice::IterMut<'a, Row>, usize);
impl <'a> std::iter::Iterator for ColumnIterMut<'a> {
type Item = &'a mut Cell;
fn next(&mut self) -> Option<&'a mut Cell> {
return match self.0.next() {
None => None,
Some(row) => row.get_mut_cell(self.1)
}
}
}
impl <'a> AsRef<TableSlice<'a>> for TableSlice<'a> {
fn as_ref(&self) -> &TableSlice<'a> {
return self;
}
}
impl <'a> AsRef<TableSlice<'a>> for Table {
fn as_ref(&self) -> &TableSlice<'a> {
return unsafe {
let s = &mut *((self as *const Table) as *mut Table);
s.rows.shrink_to_fit();
return transmute(self);
};
}
}
pub trait Slice<'a, E> {
type Output: 'a;
fn slice(&'a self, arg: E) -> Self::Output;
}
impl <'a, T, E> Slice<'a, E> for T where T: AsRef<TableSlice<'a>>, [Row]: Index<E, Output=[Row]> {
type Output = TableSlice<'a>;
fn slice(&'a self, arg: E) -> Self::Output {
let sl = self.as_ref();
return TableSlice {
format: sl.format,
titles: sl.titles,
rows: sl.rows.index(arg)
}
}
}
#[macro_export]
macro_rules! table {
($([$($content:tt)*]), *) => (
$crate::Table::init(vec![$(row![$($content)*]), *])
);
}
#[macro_export]
macro_rules! ptable {
($($content:tt)*) => (
{
let tab = table!($($content)*);
tab.printstd();
tab
}
);
}
#[cfg(test)]
mod tests {
use Table;
use Slice;
use row::Row;
use cell::Cell;
use format::{FORMAT_NO_LINESEP, FORMAT_NO_COLSEP, FORMAT_NO_BORDER};
#[test]
fn table() {
let mut table = Table::new();
table.add_row(Row::new(vec![Cell::new("a"), Cell::new("bc"), Cell::new("def")]));
table.add_row(Row::new(vec![Cell::new("def"), Cell::new("bc"), Cell::new("a")]));
table.set_titles(Row::new(vec![Cell::new("t1"), Cell::new("t2"), Cell::new("t3")]));
let out = "\
+-----+----+-----+
| t1 | t2 | t3 |
+=====+====+=====+
| a | bc | def |
+-----+----+-----+
| def | bc | a |
+-----+----+-----+
";
assert_eq!(table.to_string().replace("\r\n", "\n"), out);
}
#[test]
fn index() {
let mut table = Table::new();
table.add_row(Row::new(vec![Cell::new("a"), Cell::new("bc"), Cell::new("def")]));
table.add_row(Row::new(vec![Cell::new("def"), Cell::new("bc"), Cell::new("a")]));
table.set_titles(Row::new(vec![Cell::new("t1"), Cell::new("t2"), Cell::new("t3")]));
assert_eq!(table[1][1].get_content(), "bc");
table[1][1] = Cell::new("newval");
assert_eq!(table[1][1].get_content(), "newval");
let out = "\
+-----+--------+-----+
| t1 | t2 | t3 |
+=====+========+=====+
| a | bc | def |
+-----+--------+-----+
| def | newval | a |
+-----+--------+-----+
";
assert_eq!(table.to_string().replace("\r\n", "\n"), out);
}
#[test]
fn no_linesep() {
let mut table = Table::new();
table.set_format(FORMAT_NO_LINESEP);
table.add_row(Row::new(vec![Cell::new("a"), Cell::new("bc"), Cell::new("def")]));
table.add_row(Row::new(vec![Cell::new("def"), Cell::new("bc"), Cell::new("a")]));
table.set_titles(Row::new(vec![Cell::new("t1"), Cell::new("t2"), Cell::new("t3")]));
assert_eq!(table[1][1].get_content(), "bc");
table[1][1] = Cell::new("newval");
assert_eq!(table[1][1].get_content(), "newval");
let out = "\
| t1 | t2 | t3 |
| a | bc | def |
| def | newval | a |
";
assert_eq!(table.to_string().replace("\r\n", "\n"), out);
}
#[test]
fn no_colsep() {
let mut table = Table::new();
table.set_format(FORMAT_NO_COLSEP);
table.add_row(Row::new(vec![Cell::new("a"), Cell::new("bc"), Cell::new("def")]));
table.add_row(Row::new(vec![Cell::new("def"), Cell::new("bc"), Cell::new("a")]));
table.set_titles(Row::new(vec![Cell::new("t1"), Cell::new("t2"), Cell::new("t3")]));
assert_eq!(table[1][1].get_content(), "bc");
table[1][1] = Cell::new("newval");
assert_eq!(table[1][1].get_content(), "newval");
let out = "\
------------------
t1 t2 t3 \n\
==================
a bc def \n\
------------------
def newval a \n\
------------------
";
println!("{}", out);
println!("____");
println!("{}", table.to_string().replace("\r\n", "\n"));
assert_eq!(table.to_string().replace("\r\n", "\n"), out);
}
#[test]
fn no_borders() {
let mut table = Table::new();
table.set_format(FORMAT_NO_BORDER);
table.add_row(Row::new(vec![Cell::new("a"), Cell::new("bc"), Cell::new("def")]));
table.add_row(Row::new(vec![Cell::new("def"), Cell::new("bc"), Cell::new("a")]));
table.set_titles(Row::new(vec![Cell::new("t1"), Cell::new("t2"), Cell::new("t3")]));
assert_eq!(table[1][1].get_content(), "bc");
table[1][1] = Cell::new("newval");
assert_eq!(table[1][1].get_content(), "newval");
let out = "\
\u{0020}t1 t2 t3 \n\
\u{0020}a bc def \n\
\u{0020}def newval a \n\
";
println!("{}", out);
println!("____");
println!("{}", table.to_string().replace("\r\n", "\n"));
assert_eq!(out, table.to_string().replace("\r\n", "\n"));
}
#[test]
fn slices() {
let mut table = Table::new();
table.set_titles(Row::new(vec![Cell::new("t1"), Cell::new("t2"), Cell::new("t3")]));
table.add_row(Row::new(vec![Cell::new("0"), Cell::new("0"), Cell::new("0")]));
table.add_row(Row::new(vec![Cell::new("1"), Cell::new("1"), Cell::new("1")]));
table.add_row(Row::new(vec![Cell::new("2"), Cell::new("2"), Cell::new("2")]));
table.add_row(Row::new(vec![Cell::new("3"), Cell::new("3"), Cell::new("3")]));
table.add_row(Row::new(vec![Cell::new("4"), Cell::new("4"), Cell::new("4")]));
table.add_row(Row::new(vec![Cell::new("5"), Cell::new("5"), Cell::new("5")]));
let out = "\
+----+----+----+
| t1 | t2 | t3 |
+====+====+====+
| 1 | 1 | 1 |
+----+----+----+
| 2 | 2 | 2 |
+----+----+----+
| 3 | 3 | 3 |
+----+----+----+
";
let slice = table.slice(..);
let slice = slice.slice(1..);
let slice = slice.slice(..3);
assert_eq!(out, slice.to_string().replace("\r\n", "\n"));
assert_eq!(out, table.slice(1..4).to_string().replace("\r\n", "\n"));
}
}