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;
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])
}
#[deprecated(since="0.8.0", note="Will become private in future release. See [issue #87](https://github.com/phsym/prettytable-rs/issues/87)")]
pub fn column_count(&self) -> usize {
self.cells.iter().map(|c| c.get_hspan()).sum()
}
pub fn len(&self) -> usize {
self.cells.len()
}
pub fn is_empty(&self) -> bool {
self.cells.is_empty()
}
#[deprecated(since="0.8.0", note="Will become private in future release. See [issue #87](https://github.com/phsym/prettytable-rs/issues/87)")]
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
}
#[deprecated(since="0.8.0", note="Will become private in future release. See [issue #87](https://github.com/phsym/prettytable-rs/issues/87)")]
pub fn get_column_width(&self, column: usize, format: &TableFormat) -> usize {
let mut i = 0;
for c in &self.cells {
if i + c.get_hspan()-1 >= column {
if c.get_hspan() == 1 {
return c.get_width();
}
let (lp, rp) = format.get_padding();
let sep = format.get_column_separator(ColumnPosition::Intern).map(|_| 1).unwrap_or_default();
let rem = lp + rp +sep;
let mut w = c.get_width();
if w > rem {
w -= rem;
} else {
w = 0;
}
return (w as f64 / c.get_hspan() as f64).ceil() as usize;
}
i += c.get_hspan();
}
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, idx: usize) -> Result<(), &str> {
if idx >= self.len() {
return Err("Cannot find cell");
}
self.cells[idx] = 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<usize, Error>
where F: Fn(&Cell, &mut T, usize, usize, bool) -> Result<(), Error>
{
let height = self.get_height();
for i in 0..height {
out.write_all(&vec![b' '; format.get_indent()])?;
format.print_column_separator(out, ColumnPosition::Left)?;
let (lp, rp) = format.get_padding();
let mut j = 0;
let mut hspan = 0; while j+hspan < 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) => {
let mut w = col_width[j+hspan..j+hspan+c.get_hspan()].iter().sum();
let real_span = c.get_hspan()-1;
w += real_span * (lp + rp) + real_span * format.get_column_separator(ColumnPosition::Intern).map(|_| 1).unwrap_or_default();
f(c, out, i, w, skip_r_fill)?;
hspan += real_span; },
None => f(&Cell::default(), out, i, col_width[j+hspan], skip_r_fill)?,
};
out.write_all(&vec![b' '; rp])?; if j+hspan < col_width.len() - 1 {
format.print_column_separator(out, ColumnPosition::Intern)?;
}
j+=1;
}
format.print_column_separator(out, ColumnPosition::Right)?;
out.write_all(NEWLINE)?;
}
Ok(height)
}
#[deprecated(since="0.8.0", note="Will become private in future release. See [issue #87](https://github.com/phsym/prettytable-rs/issues/87)")]
pub fn print<T: Write + ?Sized>(&self,
out: &mut T,
format: &TableFormat,
col_width: &[usize])
-> Result<usize, Error> {
self.__print(out, format, col_width, Cell::print)
}
#[deprecated(since="0.8.0", note="Will become private in future release. See [issue #87](https://github.com/phsym/prettytable-rs/issues/87)")]
pub fn print_term<T: Terminal + ?Sized>(&self,
out: &mut T,
format: &TableFormat,
col_width: &[usize])
-> Result<usize, 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::new(vec![$(cell!($content)), *])); ($style:ident => $($content:expr), *) => ($crate::Row::new(vec![$(cell!($style -> $content)), *]));
($style:ident => $($content:expr,) *) => ($crate::Row::new(vec![$(cell!($style -> $content)), *]));
($($content:tt)*) => ($crate::Row::new(row!((); $($content)*)));
}
#[cfg(test)]
mod tests {
use super::*;
use 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");
}
}