summaryrefslogtreecommitdiffstats
path: root/vendor/tabled/src/builder
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/tabled/src/builder')
-rw-r--r--vendor/tabled/src/builder/index_builder.rs318
-rw-r--r--vendor/tabled/src/builder/mod.rs118
-rw-r--r--vendor/tabled/src/builder/table_builder.rs506
3 files changed, 942 insertions, 0 deletions
diff --git a/vendor/tabled/src/builder/index_builder.rs b/vendor/tabled/src/builder/index_builder.rs
new file mode 100644
index 000000000..081f580df
--- /dev/null
+++ b/vendor/tabled/src/builder/index_builder.rs
@@ -0,0 +1,318 @@
+use crate::Table;
+
+use super::Builder;
+
+/// [`IndexBuilder`] helps to add an index to the table.
+///
+/// Index is a column on the left of the table.
+///
+/// It also can be used to transpose the table.
+///
+/// Creates a new [`IndexBuilder`] instance.
+///
+/// It creates a default index a range from 0 to N. (N - count rows)
+/// It also sets a default columns to the range 0 .. N (N - count columns).
+///nfo<'a>
+/// # Example
+///
+/// ```
+/// use tabled::builder::Builder;
+///
+/// let mut builder = Builder::default();
+/// builder.set_header(["i", "col-1", "col-2"]);
+/// builder.push_record(["0", "value-1", "value-2"]);
+///
+/// let table = builder.index().build().to_string();
+///
+/// assert_eq!(
+/// table,
+/// "+---+---+---------+---------+\n\
+/// | | i | col-1 | col-2 |\n\
+/// +---+---+---------+---------+\n\
+/// | 0 | 0 | value-1 | value-2 |\n\
+/// +---+---+---------+---------+"
+/// )
+/// ```
+///
+/// # Example
+///
+/// ```
+/// use tabled::builder::Builder;
+///
+/// let table = Builder::default()
+/// .index()
+/// .build();
+/// ```
+#[derive(Debug, Clone)]
+pub struct IndexBuilder {
+ /// Index is an index data.
+ /// It's always set.
+ index: Vec<String>,
+ /// Name of an index
+ name: Option<String>,
+ /// A flag which checks if we need to actually use index.
+ ///
+ /// It might happen when it's only necessary to [`Self::transpose`] table.
+ print_index: bool,
+ /// A flag which checks if table was transposed.
+ transposed: bool,
+ /// Data originated in [`Builder`].
+ data: Vec<Vec<String>>,
+}
+
+impl IndexBuilder {
+ /// No flag makes builder to not use an index.
+ ///
+ /// It may be useful when only [`Self::transpose`] need to be used.
+ ///
+ /// ```
+ /// use tabled::builder::Builder;
+ ///
+ /// let mut builder = Builder::default();
+ /// builder.set_header(["i", "col-1", "col-2"]);
+ /// builder.push_record(["0", "value-1", "value-2"]);
+ /// builder.push_record(["2", "value-3", "value-4"]);
+ ///
+ /// let table = builder.index().hide().build().to_string();
+ ///
+ /// assert_eq!(
+ /// table,
+ /// "+---+---------+---------+\n\
+ /// | i | col-1 | col-2 |\n\
+ /// +---+---------+---------+\n\
+ /// | 0 | value-1 | value-2 |\n\
+ /// +---+---------+---------+\n\
+ /// | 2 | value-3 | value-4 |\n\
+ /// +---+---------+---------+"
+ /// )
+ /// ```
+ pub fn hide(mut self) -> Self {
+ self.print_index = false;
+ self
+ }
+
+ /// Set an index name.
+ ///
+ /// When [`None`] the name won't be used.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use tabled::builder::Builder;
+ ///
+ /// let mut builder = Builder::default();
+ /// builder.set_header(["i", "column1", "column2"]);
+ /// builder.push_record(["0", "value1", "value2"]);
+ ///
+ /// let table = builder.index()
+ /// .column(1)
+ /// .name(Some(String::from("index")))
+ /// .build();
+ ///
+ /// assert_eq!(
+ /// table.to_string(),
+ /// "+--------+---+---------+\n\
+ /// | | i | column2 |\n\
+ /// +--------+---+---------+\n\
+ /// | index | | |\n\
+ /// +--------+---+---------+\n\
+ /// | value1 | 0 | value2 |\n\
+ /// +--------+---+---------+"
+ /// )
+ /// ```
+ pub fn name(mut self, name: Option<String>) -> Self {
+ self.name = name;
+ self
+ }
+
+ /// Sets a index to the chosen column.
+ ///
+ /// Also sets a name of the index to the column name.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use tabled::builder::Builder;
+ ///
+ /// let mut builder = Builder::default();
+ /// builder.set_header(["i", "column1", "column2"]);
+ /// builder.push_record(["0", "value1", "value2"]);
+ ///
+ /// let table = builder.index().column(1).build();
+ ///
+ /// assert_eq!(
+ /// table.to_string(),
+ /// "+---------+---+---------+\n\
+ /// | | i | column2 |\n\
+ /// +---------+---+---------+\n\
+ /// | column1 | | |\n\
+ /// +---------+---+---------+\n\
+ /// | value1 | 0 | value2 |\n\
+ /// +---------+---+---------+"
+ /// )
+ /// ```
+ pub fn column(mut self, column: usize) -> Self {
+ if column >= matrix_count_columns(&self.data) {
+ return self;
+ }
+
+ self.index = get_column(&mut self.data, column);
+
+ let name = remove_or_default(&mut self.index, 0);
+ self.name = Some(name);
+
+ self
+ }
+
+ /// Transpose index and columns.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use tabled::builder::Builder;
+ ///
+ /// let mut builder = Builder::default();
+ /// builder.set_header(["i", "column-1", "column-2", "column-3"]);
+ /// builder.push_record(["0", "value-1", "value-2", "value-3"]);
+ /// builder.push_record(["1", "value-4", "value-5", "value-6"]);
+ /// builder.push_record(["2", "value-7", "value-8", "value-9"]);
+ ///
+ /// let table = builder.index().column(1).transpose().build();
+ ///
+ /// assert_eq!(
+ /// table.to_string(),
+ /// "+----------+---------+---------+---------+\n\
+ /// | column-1 | value-1 | value-4 | value-7 |\n\
+ /// +----------+---------+---------+---------+\n\
+ /// | i | 0 | 1 | 2 |\n\
+ /// +----------+---------+---------+---------+\n\
+ /// | column-2 | value-2 | value-5 | value-8 |\n\
+ /// +----------+---------+---------+---------+\n\
+ /// | column-3 | value-3 | value-6 | value-9 |\n\
+ /// +----------+---------+---------+---------+"
+ /// )
+ /// ```
+ pub fn transpose(mut self) -> Self {
+ let columns = &mut self.data[0];
+ std::mem::swap(&mut self.index, columns);
+
+ let columns = self.data.remove(0);
+
+ make_rows_columns(&mut self.data);
+
+ self.data.insert(0, columns);
+
+ self.transposed = !self.transposed;
+
+ self
+ }
+
+ /// Builds a table.
+ pub fn build(self) -> Table {
+ let builder: Builder = self.into();
+ builder.build()
+ }
+}
+
+impl From<Builder> for IndexBuilder {
+ fn from(builder: Builder) -> Self {
+ let has_header = builder.has_header();
+
+ let mut data: Vec<Vec<_>> = builder.into();
+
+ if !has_header {
+ let count_columns = matrix_count_columns(&data);
+ data.insert(0, build_range_index(count_columns));
+ }
+
+ // we exclude first row which contains a header
+ let data_len = data.len().saturating_sub(1);
+ let index = build_range_index(data_len);
+
+ Self {
+ index,
+ name: None,
+ print_index: true,
+ transposed: false,
+ data,
+ }
+ }
+}
+
+impl From<IndexBuilder> for Builder {
+ fn from(b: IndexBuilder) -> Self {
+ build_index(b)
+ }
+}
+
+fn build_index(mut b: IndexBuilder) -> Builder {
+ if b.index.is_empty() {
+ return Builder::default();
+ }
+
+ // add index column
+ if b.print_index {
+ b.index.insert(0, String::default());
+
+ insert_column(&mut b.data, b.index, 0);
+ }
+
+ if let Some(name) = b.name {
+ if b.transposed && b.print_index {
+ b.data[0][0] = name;
+ } else {
+ b.data.insert(1, vec![name]);
+ }
+ }
+
+ Builder::from(b.data)
+}
+
+fn build_range_index(n: usize) -> Vec<String> {
+ (0..n).map(|i| i.to_string()).collect()
+}
+
+fn remove_or_default<T: Default>(v: &mut Vec<T>, i: usize) -> T {
+ if v.len() > i {
+ v.remove(i)
+ } else {
+ T::default()
+ }
+}
+
+fn get_column<T: Default>(v: &mut [Vec<T>], col: usize) -> Vec<T> {
+ let mut column = Vec::with_capacity(v.len());
+ for row in v.iter_mut() {
+ let value = remove_or_default(row, col);
+ column.push(value);
+ }
+
+ column
+}
+
+fn make_rows_columns<T: Default>(v: &mut Vec<Vec<T>>) {
+ let count_columns = matrix_count_columns(v);
+
+ let mut columns = Vec::with_capacity(count_columns);
+ for _ in 0..count_columns {
+ let column = get_column(v, 0);
+ columns.push(column);
+ }
+
+ v.clear();
+
+ for column in columns {
+ v.push(column);
+ }
+}
+
+fn insert_column<T: Default>(v: &mut [Vec<T>], mut column: Vec<T>, col: usize) {
+ for row in v.iter_mut() {
+ let value = remove_or_default(&mut column, col);
+ row.insert(col, value);
+ }
+}
+
+fn matrix_count_columns<T>(v: &[Vec<T>]) -> usize {
+ v.first().map_or(0, |row| row.len())
+}
diff --git a/vendor/tabled/src/builder/mod.rs b/vendor/tabled/src/builder/mod.rs
new file mode 100644
index 000000000..9002ba237
--- /dev/null
+++ b/vendor/tabled/src/builder/mod.rs
@@ -0,0 +1,118 @@
+//! Builder module provides a [`Builder`] type which helps building
+//! a [`Table`] dynamically.
+//!
+//! It also contains [`IndexBuilder`] which can help to build a table with index.
+//!
+//! # Examples
+//!
+//! Here's an example of [`IndexBuilder`] usage
+//!
+#![cfg_attr(feature = "derive", doc = "```")]
+#![cfg_attr(not(feature = "derive"), doc = "```ignore")]
+//! use tabled::{Table, Tabled, settings::Style};
+//!
+//! #[derive(Tabled)]
+//! struct Mission {
+//! name: &'static str,
+//! #[tabled(inline)]
+//! status: Status,
+//! }
+//!
+//! #[derive(Tabled)]
+//! enum Status {
+//! Complete,
+//! Started,
+//! Ready,
+//! Unknown,
+//! }
+//!
+//! let data = [
+//! Mission { name: "Algebra", status: Status::Unknown },
+//! Mission { name: "Apolo", status: Status::Complete },
+//! ];
+//!
+//! let mut builder = Table::builder(&data)
+//! .index()
+//! .column(0)
+//! .name(None)
+//! .transpose();
+//!
+//! let mut table = builder.build();
+//! table.with(Style::modern());
+//!
+//! println!("{}", table);
+//!
+//! assert_eq!(
+//! table.to_string(),
+//! concat!(
+//! "┌──────────┬─────────┬───────┐\n",
+//! "│ │ Algebra │ Apolo │\n",
+//! "├──────────┼─────────┼───────┤\n",
+//! "│ Complete │ │ + │\n",
+//! "├──────────┼─────────┼───────┤\n",
+//! "│ Started │ │ │\n",
+//! "├──────────┼─────────┼───────┤\n",
+//! "│ Ready │ │ │\n",
+//! "├──────────┼─────────┼───────┤\n",
+//! "│ Unknown │ + │ │\n",
+//! "└──────────┴─────────┴───────┘",
+//! ),
+//! )
+//! ```
+//!
+//! Example when we don't want to show empty data of enum where not all variants are used.
+//!
+#![cfg_attr(feature = "derive", doc = "```")]
+#![cfg_attr(not(feature = "derive"), doc = "```ignore")]
+//! use tabled::{Table, Tabled, settings::Style};
+//!
+//! #[derive(Tabled)]
+//! enum Status {
+//! #[tabled(inline)]
+//! Complete {
+//! started_timestamp: usize,
+//! finihsed_timestamp: usize,
+//! },
+//! #[tabled(inline)]
+//! Started {
+//! timestamp: usize,
+//! },
+//! Ready,
+//! Unknown,
+//! }
+//!
+//! let data = [
+//! Status::Unknown,
+//! Status::Complete { started_timestamp: 123, finihsed_timestamp: 234 },
+//! ];
+//!
+//! let mut builder = Table::builder(&data);
+//! builder.clean();
+//!
+//! let table = builder.build()
+//! .with(Style::modern())
+//! .to_string();
+//!
+//! println!("{}", table);
+//!
+//! assert_eq!(
+//! table,
+//! concat!(
+//! "┌───────────────────┬────────────────────┬─────────┐\n",
+//! "│ started_timestamp │ finihsed_timestamp │ Unknown │\n",
+//! "├───────────────────┼────────────────────┼─────────┤\n",
+//! "│ │ │ + │\n",
+//! "├───────────────────┼────────────────────┼─────────┤\n",
+//! "│ 123 │ 234 │ │\n",
+//! "└───────────────────┴────────────────────┴─────────┘",
+//! ),
+//! )
+//! ```
+//!
+//! [`Table`]: crate::Table
+
+mod index_builder;
+mod table_builder;
+
+pub use index_builder::IndexBuilder;
+pub use table_builder::Builder;
diff --git a/vendor/tabled/src/builder/table_builder.rs b/vendor/tabled/src/builder/table_builder.rs
new file mode 100644
index 000000000..40316494e
--- /dev/null
+++ b/vendor/tabled/src/builder/table_builder.rs
@@ -0,0 +1,506 @@
+use std::iter::FromIterator;
+
+use crate::{grid::records::vec_records::CellInfo, Table};
+
+use super::IndexBuilder;
+
+/// Builder creates a [`Table`] from dynamic data set.
+///
+/// It useful when the amount of columns or rows is not known statically.
+///
+/// ```rust
+/// use tabled::builder::Builder;
+///
+/// let mut builder = Builder::default();
+/// builder.set_header(["index", "measure", "value"]);
+/// builder.push_record(["0", "weight", "0.443"]);
+///
+/// let table = builder.build();
+///
+/// println!("{}", table);
+/// ```
+///
+/// It may be useful to use [`FromIterator`] for building.
+///
+/// ```rust
+/// use tabled::builder::Builder;
+/// use std::iter::FromIterator;
+///
+/// let data = vec![
+/// ["column1", "column2"],
+/// ["data1", "data2"],
+/// ["data3", "data4"],
+/// ];
+///
+/// let table = Builder::from_iter(data).build();
+///
+/// println!("{}", table);
+/// ```
+#[derive(Debug, Default, Clone)]
+pub struct Builder {
+ /// A list of rows.
+ data: Vec<Vec<CellInfo<String>>>,
+ /// A columns row.
+ columns: Option<Vec<CellInfo<String>>>,
+ /// A number of columns.
+ count_columns: usize,
+ /// A flag that the rows are not consistent.
+ is_consistent: bool,
+ /// A content of cells which are created in case rows has different length.
+ empty_cell_text: Option<String>,
+}
+
+impl Builder {
+ /// Creates a [`Builder`] instance.
+ ///
+ /// ```
+ /// use tabled::builder::Builder;
+ ///
+ /// let builder = Builder::new();
+ /// ```
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// Creates a [`Builder`] instance with a given row capacity.
+ ///
+ /// ```
+ /// use tabled::builder::Builder;
+ ///
+ /// let mut builder = Builder::with_capacity(2);
+ /// builder.push_record((0..3).map(|i| i.to_string()));
+ /// builder.push_record(["i", "surname", "lastname"]);
+ /// ```
+ pub fn with_capacity(capacity: usize) -> Self {
+ let mut b = Self::new();
+ b.data = Vec::with_capacity(capacity);
+
+ b
+ }
+
+ /// Sets a [`Table`] header.
+ ///
+ /// ```
+ /// # use tabled::builder::Builder;
+ /// let mut builder = Builder::default();
+ /// builder.set_header((0..3).map(|i| i.to_string()));
+ /// ```
+ pub fn set_header<H, T>(&mut self, columns: H) -> &mut Self
+ where
+ H: IntoIterator<Item = T>,
+ T: Into<String>,
+ {
+ let list = create_row(columns, self.count_columns);
+
+ self.update_size(list.len());
+ self.columns = Some(list);
+
+ self
+ }
+
+ /// Sets off a [`Table`] header.
+ ///
+ /// If not set its a nop.
+ ///
+ /// ```rust
+ /// use tabled::Table;
+ ///
+ /// let data = [("Hello", 1u8, false), ("World", 21u8, true)];
+ ///
+ /// let table = Table::builder(data).build().to_string();
+ ///
+ /// assert_eq!(
+ /// table,
+ /// "+-------+----+-------+\n\
+ /// | &str | u8 | bool |\n\
+ /// +-------+----+-------+\n\
+ /// | Hello | 1 | false |\n\
+ /// +-------+----+-------+\n\
+ /// | World | 21 | true |\n\
+ /// +-------+----+-------+"
+ /// );
+ ///
+ ///
+ /// let mut builder = Table::builder(data);
+ /// builder.remove_header();
+ /// let table = builder.build().to_string();
+ ///
+ /// assert_eq!(
+ /// table,
+ /// "+-------+----+-------+\n\
+ /// | Hello | 1 | false |\n\
+ /// +-------+----+-------+\n\
+ /// | World | 21 | true |\n\
+ /// +-------+----+-------+"
+ /// );
+ ///
+ /// ```
+ pub fn remove_header(&mut self) -> &mut Self {
+ self.columns = None;
+ self.count_columns = self.get_size();
+
+ self
+ }
+
+ /// Sets a content of cells which are created in case rows has different length.
+ ///
+ ///
+ /// ```rust
+ /// use tabled::builder::Builder;
+ ///
+ /// let mut builder = Builder::default();
+ /// builder
+ /// .set_default_text("undefined")
+ /// .set_header((0..3).map(|i| i.to_string()))
+ /// .push_record(["i"]);
+ /// ```
+ pub fn set_default_text<T>(&mut self, text: T) -> &mut Self
+ where
+ T: Into<String>,
+ {
+ self.empty_cell_text = Some(text.into());
+ self
+ }
+
+ /// Build creates a [`Table`] instance.
+ ///
+ /// ```rust
+ /// use tabled::builder::Builder;
+ ///
+ /// let mut builder = Builder::default();
+ /// builder.set_header(["i", "column1", "column2"]);
+ /// builder.push_record(["0", "value1", "value2"]);
+ /// ```
+ pub fn build(self) -> Table {
+ Table::from(self)
+ }
+
+ /// Add an index to the [`Table`].
+ ///
+ /// Default index is a range 0-N where N is amount of records.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use tabled::Table;
+ ///
+ /// let table = Table::builder(&["Hello", "World", "!"]).index().build();
+ ///
+ /// assert_eq!(
+ /// table.to_string(),
+ /// "+---+-------+\n\
+ /// | | &str |\n\
+ /// +---+-------+\n\
+ /// | 0 | Hello |\n\
+ /// +---+-------+\n\
+ /// | 1 | World |\n\
+ /// +---+-------+\n\
+ /// | 2 | ! |\n\
+ /// +---+-------+"
+ /// )
+ /// ```
+ pub fn index(self) -> IndexBuilder {
+ IndexBuilder::from(self)
+ }
+
+ /// Adds a row to a [`Table`].
+ ///
+ /// ```
+ /// use tabled::builder::Builder;
+ ///
+ /// let mut builder = Builder::default();
+ /// builder.push_record((0..3).map(|i| i.to_string()));
+ /// builder.push_record(["i", "surname", "lastname"]);
+ /// ```
+ pub fn push_record<R, T>(&mut self, row: R) -> &mut Self
+ where
+ R: IntoIterator<Item = T>,
+ T: Into<String>,
+ {
+ let list = create_row(row, self.count_columns);
+
+ self.update_size(list.len());
+ self.data.push(list);
+
+ self
+ }
+
+ /// Insert a row into a specific position.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `index > count_rows`.
+ pub fn insert_record<R>(&mut self, index: usize, record: R) -> bool
+ where
+ R: IntoIterator,
+ R::Item: Into<String>,
+ {
+ let list = create_row(record, self.count_columns);
+
+ self.update_size(list.len());
+ self.data.insert(index, list);
+
+ true
+ }
+
+ /// Clean removes empty columns and rows.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use tabled::Table;
+ ///
+ /// let mut builder = Table::builder(&["Hello", "World", ""]);
+ /// builder.clean();
+ ///
+ /// let table = builder.build();
+ ///
+ /// assert_eq!(
+ /// table.to_string(),
+ /// "+-------+\n\
+ /// | &str |\n\
+ /// +-------+\n\
+ /// | Hello |\n\
+ /// +-------+\n\
+ /// | World |\n\
+ /// +-------+"
+ /// )
+ /// ```
+ pub fn clean(&mut self) -> &mut Self {
+ self.clean_columns();
+ self.clean_rows();
+ self
+ }
+
+ /// Set a column size.
+ ///
+ /// If it make it lower then it was originally it is considered NOP.
+ pub fn hint_column_size(&mut self, size: usize) -> &mut Self {
+ self.count_columns = size;
+ self.is_consistent = true;
+ self
+ }
+
+ /// Returns an amount of columns which would be present in a built table.
+ pub fn count_columns(&self) -> usize {
+ self.count_columns
+ }
+
+ /// Returns an amount of rows which would be present in a built table.
+ pub fn count_rows(&self) -> usize {
+ self.data.len()
+ }
+
+ /// Checks whether a builder contains a header set.
+ pub fn has_header(&self) -> bool {
+ self.columns.is_some()
+ }
+
+ fn clean_columns(&mut self) {
+ let mut i = 0;
+ for col in 0..self.count_columns {
+ let col = col - i;
+
+ let mut is_empty = true;
+ for row in 0..self.data.len() {
+ let cell = &self.data[row][col];
+ if !cell.as_ref().is_empty() {
+ is_empty = false;
+ break;
+ }
+ }
+
+ if is_empty {
+ for row in 0..self.data.len() {
+ let _ = self.data[row].remove(col);
+ }
+
+ if let Some(columns) = self.columns.as_mut() {
+ if columns.len() > col {
+ let _ = columns.remove(col);
+ }
+ }
+
+ i += 1;
+ }
+ }
+
+ self.count_columns -= i;
+ }
+
+ fn clean_rows(&mut self) {
+ for row in (0..self.data.len()).rev() {
+ let mut is_empty = true;
+ for col in 0..self.count_columns {
+ let cell = &self.data[row][col];
+ if !cell.as_ref().is_empty() {
+ is_empty = false;
+ break;
+ }
+ }
+
+ if is_empty {
+ let _ = self.data.remove(row);
+ }
+
+ if row == 0 {
+ break;
+ }
+ }
+ }
+
+ fn update_size(&mut self, size: usize) {
+ use std::cmp::Ordering;
+
+ match size.cmp(&self.count_columns) {
+ Ordering::Less => {
+ if !self.data.is_empty() {
+ self.is_consistent = false;
+ }
+ }
+ Ordering::Greater => {
+ self.count_columns = size;
+
+ if !self.data.is_empty() || self.columns.is_some() {
+ self.is_consistent = false;
+ }
+ }
+ Ordering::Equal => (),
+ }
+ }
+
+ fn get_size(&mut self) -> usize {
+ let mut max = self.columns.as_ref().map_or(0, Vec::len);
+ let max_records = self.data.iter().map(Vec::len).max().unwrap_or(0);
+ max = std::cmp::max(max_records, max);
+
+ max
+ }
+
+ fn fix_rows(&mut self) {
+ let empty_cell = self.empty_cell_text.to_owned().unwrap_or_default();
+ let empty = CellInfo::new(empty_cell);
+
+ if let Some(header) = self.columns.as_mut() {
+ if self.count_columns > header.len() {
+ let count = self.count_columns - header.len();
+ append_vec(header, empty.clone(), count);
+ }
+ }
+
+ for row in &mut self.data {
+ if self.count_columns > row.len() {
+ let count = self.count_columns - row.len();
+ append_vec(row, empty.clone(), count);
+ }
+ }
+ }
+}
+
+impl From<Builder> for Vec<Vec<String>> {
+ fn from(mut builder: Builder) -> Self {
+ if !builder.is_consistent {
+ builder.fix_rows();
+ }
+
+ if let Some(columns) = builder.columns {
+ builder.data.insert(0, columns);
+ }
+
+ builder
+ .data
+ .into_iter()
+ .map(|row| row.into_iter().map(|c| c.into_inner()).collect())
+ .collect()
+ }
+}
+
+impl From<Builder> for Vec<Vec<CellInfo<String>>> {
+ fn from(mut builder: Builder) -> Self {
+ if !builder.is_consistent {
+ builder.fix_rows();
+ }
+
+ if let Some(columns) = builder.columns {
+ builder.data.insert(0, columns);
+ }
+
+ builder.data
+ }
+}
+
+impl<R, V> FromIterator<R> for Builder
+where
+ R: IntoIterator<Item = V>,
+ V: Into<String>,
+{
+ fn from_iter<T: IntoIterator<Item = R>>(iter: T) -> Self {
+ let mut builder = Self::default();
+ for row in iter {
+ let _ = builder.push_record(row);
+ }
+
+ builder
+ }
+}
+
+impl<D> Extend<D> for Builder
+where
+ D: Into<String>,
+{
+ fn extend<T: IntoIterator<Item = D>>(&mut self, iter: T) {
+ let _ = self.push_record(iter);
+ }
+}
+
+impl From<Vec<Vec<String>>> for Builder {
+ fn from(data: Vec<Vec<String>>) -> Self {
+ let count_columns = data.get(0).map_or(0, |row| row.len());
+
+ let data = data
+ .into_iter()
+ .map(|row| row.into_iter().map(CellInfo::new).collect())
+ .collect();
+
+ Self {
+ data,
+ count_columns,
+ columns: None,
+ is_consistent: false,
+ empty_cell_text: None,
+ }
+ }
+}
+
+impl From<Vec<Vec<CellInfo<String>>>> for Builder {
+ fn from(data: Vec<Vec<CellInfo<String>>>) -> Self {
+ let count_columns = data.get(0).map_or(0, |row| row.len());
+
+ Self {
+ data,
+ count_columns,
+ columns: None,
+ is_consistent: false,
+ empty_cell_text: None,
+ }
+ }
+}
+
+fn create_row<R, T>(row: R, size: usize) -> Vec<CellInfo<String>>
+where
+ R: IntoIterator<Item = T>,
+ T: Into<String>,
+{
+ let mut list = Vec::with_capacity(size);
+ for text in row {
+ let text = text.into();
+ let info = CellInfo::new(text);
+ list.push(info);
+ }
+
+ list
+}
+
+fn append_vec<T: Clone>(v: &mut Vec<T>, value: T, n: usize) {
+ v.extend((0..n).map(|_| value.clone()));
+}