use std::io::{Write, Error};
use std::iter::FromIterator;
use std::slice::{Iter, IterMut};
use std::ops::{Index, IndexMut};
use super::Terminal;
use super::utils::NEWLINE;
use super::cell::Cell;
use super::format::{TableFormat, ColumnPosition};
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct Row {
cells: Vec<Cell>,
}
impl Row {
pub fn new(cells: Vec<Cell>) -> Row {
Row { cells: cells }
}
pub fn empty() -> Row {
Self::new(vec![Cell::default(); 0])
}
pub fn len(&self) -> usize {
self.cells.len()
}
pub fn is_empty(&self) -> bool {
self.cells.is_empty()
}
pub fn get_height(&self) -> usize {
let mut height = 1;
for cell in &self.cells {
let h = cell.get_height();
if h > height {
height = h;
}
}
height
}
pub fn get_cell_width(&self, column: usize) -> usize {
self.cells
.get(column)
.map(|cell| cell.get_width())
.unwrap_or(0)
}
pub fn get_cell(&self, idx: usize) -> Option<&Cell> {
self.cells.get(idx)
}
pub fn get_mut_cell(&mut self, idx: usize) -> Option<&mut Cell> {
self.cells.get_mut(idx)
}
pub fn set_cell(&mut self, cell: Cell, column: usize) -> Result<(), &str> {
if column >= self.len() {
return Err("Cannot find cell");
}
self.cells[column] = cell;
Ok(())
}
pub fn add_cell(&mut self, cell: Cell) {
self.cells.push(cell);
}
pub fn insert_cell(&mut self, index: usize, cell: Cell) {
if index < self.cells.len() {
self.cells.insert(index, cell);
} else {
self.add_cell(cell);
}
}
pub fn remove_cell(&mut self, index: usize) {
if index < self.cells.len() {
self.cells.remove(index);
}
}
pub fn iter(&self) -> Iter<Cell> {
self.cells.iter()
}
pub fn iter_mut(&mut self) -> IterMut<Cell> {
self.cells.iter_mut()
}
fn __print<T: Write + ?Sized, F>(&self,
out: &mut T,
format: &TableFormat,
col_width: &[usize],
f: F)
-> Result<(), Error>
where F: Fn(&Cell, &mut T, usize, usize, bool) -> Result<(), Error>
{
for i in 0..self.get_height() {
out.write_all(&vec![b' '; format.get_indent()])?;
format.print_column_separator(out, ColumnPosition::Left)?;
let (lp, rp) = format.get_padding();
for j in 0..col_width.len() {
out.write_all(&vec![b' '; lp])?;
let skip_r_fill = (j == col_width.len() - 1) &&
format.get_column_separator(ColumnPosition::Right).is_none();
match self.get_cell(j) {
Some(c) => f(c, out, i, col_width[j], skip_r_fill)?,
None => f(&Cell::default(), out, i, col_width[j], skip_r_fill)?,
};
out.write_all(&vec![b' '; rp])?;
if j < col_width.len() - 1 {
format.print_column_separator(out, ColumnPosition::Intern)?;
}
}
format.print_column_separator(out, ColumnPosition::Right)?;
out.write_all(NEWLINE)?;
}
Ok(())
}
pub fn print<T: Write + ?Sized>(&self,
out: &mut T,
format: &TableFormat,
col_width: &[usize])
-> Result<(), Error> {
self.__print(out, format, col_width, Cell::print)
}
pub fn print_term<T: Terminal + ?Sized>(&self,
out: &mut T,
format: &TableFormat,
col_width: &[usize])
-> Result<(), Error> {
self.__print(out, format, col_width, Cell::print_term)
}
}
impl Default for Row {
fn default() -> Row {
Row::empty()
}
}
impl Index<usize> for Row {
type Output = Cell;
fn index(&self, idx: usize) -> &Self::Output {
&self.cells[idx]
}
}
impl IndexMut<usize> for Row {
fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
&mut self.cells[idx]
}
}
impl<A: ToString> FromIterator<A> for Row {
fn from_iter<T>(iterator: T) -> Row
where T: IntoIterator<Item = A>
{
Self::new(iterator.into_iter().map(|ref e| Cell::from(e)).collect())
}
}
impl<T, A> From<T> for Row
where A: ToString,
T: IntoIterator<Item = A>
{
fn from(it: T) -> Row {
Self::from_iter(it)
}
}
impl<'a> IntoIterator for &'a Row {
type Item = &'a Cell;
type IntoIter = Iter<'a, Cell>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a> IntoIterator for &'a mut Row {
type Item = &'a mut Cell;
type IntoIter = IterMut<'a, Cell>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
impl <S: ToString> Extend<S> for Row {
fn extend<T: IntoIterator<Item=S>>(&mut self, iter: T) {
self.cells.extend(iter.into_iter().map(|s| Cell::new(&s.to_string())));
}
}
#[macro_export]
macro_rules! row {
(($($out:tt)*);) => (vec![$($out)*]);
(($($out:tt)*); $value:expr) => (vec![$($out)* cell!($value)]);
(($($out:tt)*); $value:expr, $($n:tt)*) => (row!(($($out)* cell!($value),); $($n)*));
(($($out:tt)*); $style:ident -> $value:expr) => (vec![$($out)* cell!($style -> $value)]);
(($($out:tt)*); $style:ident -> $value:expr, $($n: tt)*) => (row!(($($out)* cell!($style -> $value),); $($n)*));
($($content:expr), *) => ($crate::row::Row::new(vec![$(cell!($content)), *]));
($style:ident => $($content:expr), *) => ($crate::row::Row::new(vec![$(cell!($style -> $content)), *]));
($style:ident => $($content:expr,) *) => ($crate::row::Row::new(vec![$(cell!($style -> $content)), *]));
($($content:tt)*) => ($crate::row::Row::new(row!((); $($content)*)));
}
#[cfg(test)]
mod tests {
use super::*;
use cell::Cell;
#[test]
fn row_default_empty() {
let row1 = Row::default();
assert_eq!(row1.len(), 0);
assert!(row1.is_empty());
}
#[test]
fn get_add_set_cell() {
let mut row = Row::from(vec!["foo", "bar", "foobar"]);
assert_eq!(row.len(), 3);
assert!(row.get_mut_cell(12).is_none());
let c1 = row.get_mut_cell(0).unwrap().clone();
assert_eq!(c1.get_content(), "foo");
let c1 = Cell::from(&"baz");
assert!(row.set_cell(c1.clone(), 1000).is_err());
assert!(row.set_cell(c1.clone(), 0).is_ok());
assert_eq!(row.get_cell(0).unwrap().get_content(), "baz");
row.add_cell(c1.clone());
assert_eq!(row.len(), 4);
assert_eq!(row.get_cell(3).unwrap().get_content(), "baz");
}
#[test]
fn insert_cell() {
let mut row = Row::from(vec!["foo", "bar", "foobar"]);
assert_eq!(row.len(), 3);
let cell = Cell::new("baz");
row.insert_cell(1000, cell.clone());
assert_eq!(row.len(), 4);
assert_eq!(row.get_cell(3).unwrap().get_content(), "baz");
row.insert_cell(1, cell.clone());
assert_eq!(row.len(), 5);
assert_eq!(row.get_cell(1).unwrap().get_content(), "baz");
}
#[test]
fn remove_cell() {
let mut row = Row::from(vec!["foo", "bar", "foobar"]);
assert_eq!(row.len(), 3);
row.remove_cell(1000);
assert_eq!(row.len(), 3);
row.remove_cell(1);
assert_eq!(row.len(), 2);
assert_eq!(row.get_cell(0).unwrap().get_content(), "foo");
assert_eq!(row.get_cell(1).unwrap().get_content(), "foobar");
}
#[test]
fn extend_row() {
let mut row = Row::from(vec!["foo", "bar", "foobar"]);
row.extend(vec!["A", "B", "C"]);
assert_eq!(row.len(), 6);
assert_eq!(row.get_cell(3).unwrap().get_content(), "A");
assert_eq!(row.get_cell(4).unwrap().get_content(), "B");
assert_eq!(row.get_cell(5).unwrap().get_content(), "C");
}
}