prettytable/
row.rs

1//! This module contains definition of table rows stuff
2use std::io::{Write, Error};
3use std::iter::FromIterator;
4use std::slice::{Iter, IterMut};
5// use std::vec::IntoIter;
6use std::ops::{Index, IndexMut};
7
8use super::Terminal;
9
10use super::utils::NEWLINE;
11use super::Cell;
12use super::format::{TableFormat, ColumnPosition};
13
14/// Represent a table row made of cells
15#[derive(Clone, Debug, Hash, PartialEq, Eq)]
16pub struct Row {
17    cells: Vec<Cell>,
18}
19
20impl Row {
21    /// Create a new `Row` backed with `cells` vector
22    pub fn new(cells: Vec<Cell>) -> Row {
23        Row { cells: cells }
24    }
25
26    /// Create an row of length `size`, with empty strings stored
27    pub fn empty() -> Row {
28        Self::new(vec![Cell::default(); 0])
29    }
30
31    /// Count the number of column required in the table grid.
32    /// It takes into account horizontal spanning of cells. For
33    /// example, a cell with an hspan of 3 will add 3 column to the grid
34    #[deprecated(since="0.8.0", note="Will become private in future release. See [issue #87](https://github.com/phsym/prettytable-rs/issues/87)")]
35    pub fn column_count(&self) -> usize {
36        self.cells.iter().map(|c| c.get_hspan()).sum()
37    }
38
39    /// Get the number of cells in this row
40    pub fn len(&self) -> usize {
41        self.cells.len()
42        // self.cells.iter().map(|c| c.get_hspan()).sum()
43    }
44
45    /// Check if the row is empty (has no cell)
46    pub fn is_empty(&self) -> bool {
47        self.cells.is_empty()
48    }
49
50    /// Get the height of this row
51    #[deprecated(since="0.8.0", note="Will become private in future release. See [issue #87](https://github.com/phsym/prettytable-rs/issues/87)")]
52    pub fn get_height(&self) -> usize {
53        let mut height = 1; // Minimum height must be 1 to print empty rows
54        for cell in &self.cells {
55            let h = cell.get_height();
56            if h > height {
57                height = h;
58            }
59        }
60        height
61    }
62
63    /// Get the minimum width required by the cell in the column `column`.
64    /// Return 0 if the cell does not exist in this row
65    #[deprecated(since="0.8.0", note="Will become private in future release. See [issue #87](https://github.com/phsym/prettytable-rs/issues/87)")]
66    pub fn get_column_width(&self, column: usize, format: &TableFormat) -> usize {
67        let mut i = 0;
68        for c in &self.cells {
69            if i + c.get_hspan()-1 >= column {
70                if c.get_hspan() == 1 {
71                    return c.get_width();
72                }
73                let (lp, rp) = format.get_padding();
74                let sep = format.get_column_separator(ColumnPosition::Intern).map(|_| 1).unwrap_or_default();
75                let rem = lp + rp +sep;
76                let mut w = c.get_width();
77                if w > rem {
78                    w -= rem;
79                } else {
80                    w = 0;
81                }
82                return (w as f64 / c.get_hspan() as f64).ceil() as usize;
83            }
84            i += c.get_hspan();
85        }
86        0
87    }
88
89    /// Get the cell at index `idx`
90    pub fn get_cell(&self, idx: usize) -> Option<&Cell> {
91        self.cells.get(idx)
92    }
93
94    /// Get the mutable cell at index `idx`
95    pub fn get_mut_cell(&mut self, idx: usize) -> Option<&mut Cell> {
96        self.cells.get_mut(idx)
97    }
98
99    /// Set the `cell` in the row at the given `idx` index
100    pub fn set_cell(&mut self, cell: Cell, idx: usize) -> Result<(), &str> {
101        if idx >= self.len() {
102            return Err("Cannot find cell");
103        }
104        self.cells[idx] = cell;
105        Ok(())
106    }
107
108    /// Append a `cell` at the end of the row
109    pub fn add_cell(&mut self, cell: Cell) {
110        self.cells.push(cell);
111    }
112
113    /// Insert `cell` at position `index`. If `index` is higher than the row length,
114    /// the cell will be appended at the end
115    pub fn insert_cell(&mut self, index: usize, cell: Cell) {
116        if index < self.cells.len() {
117            self.cells.insert(index, cell);
118        } else {
119            self.add_cell(cell);
120        }
121    }
122
123    /// Remove the cell at position `index`. Silently skip if this cell does not exist
124    pub fn remove_cell(&mut self, index: usize) {
125        if index < self.cells.len() {
126            self.cells.remove(index);
127        }
128    }
129
130    /// Returns an immutable iterator over cells
131    pub fn iter(&self) -> Iter<Cell> {
132        self.cells.iter()
133    }
134
135    /// Returns an mutable iterator over cells
136    pub fn iter_mut(&mut self) -> IterMut<Cell> {
137        self.cells.iter_mut()
138    }
139
140    /// Internal only
141    fn __print<T: Write + ?Sized, F>(&self,
142                                     out: &mut T,
143                                     format: &TableFormat,
144                                     col_width: &[usize],
145                                     f: F)
146                                     -> Result<usize, Error>
147        where F: Fn(&Cell, &mut T, usize, usize, bool) -> Result<(), Error>
148    {
149        let height = self.get_height();
150        for i in 0..height {
151            //TODO: Wrap this into dedicated function one day
152            out.write_all(&vec![b' '; format.get_indent()])?;
153            format.print_column_separator(out, ColumnPosition::Left)?;
154            let (lp, rp) = format.get_padding();
155            let mut j = 0;
156            let mut hspan = 0; // The additional offset caused by cell's horizontal spanning
157            while j+hspan < col_width.len() {
158                out.write_all(&vec![b' '; lp])?; // Left padding
159                // skip_r_fill skip filling the end of the last cell if there's no character
160                // delimiting the end of the table
161                let skip_r_fill = (j == col_width.len() - 1) &&
162                                  format.get_column_separator(ColumnPosition::Right).is_none();
163                match self.get_cell(j) {
164                    Some(c) => {
165                        // In case of horizontal spanning, width is the sum of all spanned columns' width
166                        let mut w = col_width[j+hspan..j+hspan+c.get_hspan()].iter().sum();
167                        let real_span = c.get_hspan()-1;
168                        w += real_span * (lp + rp) + real_span * format.get_column_separator(ColumnPosition::Intern).map(|_| 1).unwrap_or_default();
169                        // Print cell content
170                        f(c, out, i, w, skip_r_fill)?;
171                        hspan += real_span; // Add span to offset
172                    },
173                    None => f(&Cell::default(), out, i, col_width[j+hspan], skip_r_fill)?,
174                };
175                out.write_all(&vec![b' '; rp])?; // Right padding
176                if j+hspan < col_width.len() - 1 {
177                    format.print_column_separator(out, ColumnPosition::Intern)?;
178                }
179                j+=1;
180            }
181            format.print_column_separator(out, ColumnPosition::Right)?;
182            out.write_all(NEWLINE)?;
183        }
184        Ok(height)
185    }
186
187    /// Print the row to `out`, with `separator` as column separator, and `col_width`
188    /// specifying the width of each columns. Returns the number of printed lines
189    #[deprecated(since="0.8.0", note="Will become private in future release. See [issue #87](https://github.com/phsym/prettytable-rs/issues/87)")]
190    pub fn print<T: Write + ?Sized>(&self,
191                                    out: &mut T,
192                                    format: &TableFormat,
193                                    col_width: &[usize])
194                                    -> Result<usize, Error> {
195        self.__print(out, format, col_width, Cell::print)
196    }
197
198    /// Print the row to terminal `out`, with `separator` as column separator, and `col_width`
199    /// specifying the width of each columns. Apply style when needed. returns the number of printed lines
200    #[deprecated(since="0.8.0", note="Will become private in future release. See [issue #87](https://github.com/phsym/prettytable-rs/issues/87)")]
201    pub fn print_term<T: Terminal + ?Sized>(&self,
202                                            out: &mut T,
203                                            format: &TableFormat,
204                                            col_width: &[usize])
205                                            -> Result<usize, Error> {
206        self.__print(out, format, col_width, Cell::print_term)
207    }
208}
209
210impl Default for Row {
211    fn default() -> Row {
212        Row::empty()
213    }
214}
215
216impl Index<usize> for Row {
217    type Output = Cell;
218    fn index(&self, idx: usize) -> &Self::Output {
219        &self.cells[idx]
220    }
221}
222
223impl IndexMut<usize> for Row {
224    fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
225        &mut self.cells[idx]
226    }
227}
228
229impl<A: ToString> FromIterator<A> for Row {
230    fn from_iter<T>(iterator: T) -> Row
231        where T: IntoIterator<Item = A>
232    {
233        Self::new(iterator.into_iter().map(|ref e| Cell::from(e)).collect())
234    }
235}
236
237impl<T, A> From<T> for Row
238    where A: ToString,
239          T: IntoIterator<Item = A>
240{
241    fn from(it: T) -> Row {
242        Self::from_iter(it)
243    }
244}
245
246impl<'a> IntoIterator for &'a Row {
247    type Item = &'a Cell;
248    type IntoIter = Iter<'a, Cell>;
249    fn into_iter(self) -> Self::IntoIter {
250        self.iter()
251    }
252}
253
254// impl IntoIterator for Row {
255//     type Item = Cell;
256//     type IntoIter = IntoIter<Cell>;
257//     fn into_iter(self) -> Self::IntoIter {
258//         self.cells.into_iter()
259//     }
260// }
261
262impl<'a> IntoIterator for &'a mut Row {
263    type Item = &'a mut Cell;
264    type IntoIter = IterMut<'a, Cell>;
265    fn into_iter(self) -> Self::IntoIter {
266        self.iter_mut()
267    }
268}
269
270impl <S: ToString> Extend<S> for Row {
271    fn extend<T: IntoIterator<Item=S>>(&mut self, iter: T) {
272        self.cells.extend(iter.into_iter().map(|s| Cell::new(&s.to_string())));
273    }
274}
275
276// impl <S: Into<Cell>> Extend<S> for Row {
277//     fn extend<T: IntoIterator<Item=S>>(&mut self, iter: T) {
278//         self.cells.extend(iter.into_iter().map(|s| s.into()));
279//     }
280// }
281
282/// This macro simplifies `Row` creation
283///
284/// The syntax support style spec
285/// # Example
286/// ```
287/// # #[macro_use] extern crate prettytable;
288/// # fn main() {
289/// // Create a normal row
290/// let row1 = row!["Element 1", "Element 2", "Element 3"];
291/// // Create a row with all cells formatted with red foreground color, yellow background color
292/// // bold, italic, align in the center of the cell
293/// let row2 = row![FrBybic => "Element 1", "Element 2", "Element 3"];
294/// // Create a row with first cell in blue, second one in red, and last one with default style
295/// let row3 = row![Fb->"blue", Fr->"red", "normal"];
296/// // Do something with rows
297/// # drop(row1);
298/// # drop(row2);
299/// # drop(row3);
300/// # }
301/// ```
302///
303/// For details about style specifier syntax, check doc for [`Cell::style_spec`](cell/struct.Cell.html#method.style_spec) method
304#[macro_export]
305macro_rules! row {
306    (($($out:tt)*);) => (vec![$($out)*]);
307    (($($out:tt)*); $value:expr) => (vec![$($out)* cell!($value)]);
308    (($($out:tt)*); $value:expr, $($n:tt)*) => (row!(($($out)* cell!($value),); $($n)*));
309    (($($out:tt)*); $style:ident -> $value:expr) => (vec![$($out)* cell!($style -> $value)]);
310    (($($out:tt)*); $style:ident -> $value:expr, $($n: tt)*) => (row!(($($out)* cell!($style -> $value),); $($n)*));
311
312    ($($content:expr), *) => ($crate::Row::new(vec![$(cell!($content)), *])); // This line may not be needed starting from Rust 1.20
313    ($style:ident => $($content:expr), *) => ($crate::Row::new(vec![$(cell!($style -> $content)), *]));
314    ($style:ident => $($content:expr,) *) => ($crate::Row::new(vec![$(cell!($style -> $content)), *]));
315    ($($content:tt)*) => ($crate::Row::new(row!((); $($content)*)));
316}
317
318#[cfg(test)]
319mod tests {
320    use super::*;
321    use Cell;
322
323    #[test]
324    fn row_default_empty() {
325        let row1 = Row::default();
326        assert_eq!(row1.len(), 0);
327        assert!(row1.is_empty());
328    }
329
330    #[test]
331    fn get_add_set_cell() {
332        let mut row = Row::from(vec!["foo", "bar", "foobar"]);
333        assert_eq!(row.len(), 3);
334        assert!(row.get_mut_cell(12).is_none());
335        let c1 = row.get_mut_cell(0).unwrap().clone();
336        assert_eq!(c1.get_content(), "foo");
337
338        let c1 = Cell::from(&"baz");
339        assert!(row.set_cell(c1.clone(), 1000).is_err());
340        assert!(row.set_cell(c1.clone(), 0).is_ok());
341        assert_eq!(row.get_cell(0).unwrap().get_content(), "baz");
342
343        row.add_cell(c1.clone());
344        assert_eq!(row.len(), 4);
345        assert_eq!(row.get_cell(3).unwrap().get_content(), "baz");
346    }
347
348    #[test]
349    fn insert_cell() {
350        let mut row = Row::from(vec!["foo", "bar", "foobar"]);
351        assert_eq!(row.len(), 3);
352        let cell = Cell::new("baz");
353        row.insert_cell(1000, cell.clone());
354        assert_eq!(row.len(), 4);
355        assert_eq!(row.get_cell(3).unwrap().get_content(), "baz");
356        row.insert_cell(1, cell.clone());
357        assert_eq!(row.len(), 5);
358        assert_eq!(row.get_cell(1).unwrap().get_content(), "baz");
359    }
360
361    #[test]
362    fn remove_cell() {
363        let mut row = Row::from(vec!["foo", "bar", "foobar"]);
364        assert_eq!(row.len(), 3);
365        row.remove_cell(1000);
366        assert_eq!(row.len(), 3);
367        row.remove_cell(1);
368        assert_eq!(row.len(), 2);
369        assert_eq!(row.get_cell(0).unwrap().get_content(), "foo");
370        assert_eq!(row.get_cell(1).unwrap().get_content(), "foobar");
371    }
372
373    #[test]
374    fn extend_row() {
375        let mut row = Row::from(vec!["foo", "bar", "foobar"]);
376        row.extend(vec!["A", "B", "C"]);
377        assert_eq!(row.len(), 6);
378        assert_eq!(row.get_cell(3).unwrap().get_content(), "A");
379        assert_eq!(row.get_cell(4).unwrap().get_content(), "B");
380        assert_eq!(row.get_cell(5).unwrap().get_content(), "C");
381    }
382}