Repository: zhiburt/tabled (language: rust)

Issue:
Refactor builder methods



Discussion / hints:

Fix patch:
diff --git a/README.md b/README.md
index 8a37292c..4f59d9e7 100644
--- a/README.md
+++ b/README.md
@@ -200,7 +200,7 @@ for line in song.lines() {
 }
 
 let columns = (0..builder.count_columns()).map(|i| i.to_string());
-builder.set_header(columns);
+builder.insert_record(0, columns);
 
 let mut table = builder.build();
 table.with(Style::ascii_rounded());
@@ -253,10 +253,9 @@ You can use `Builder::index` to make a particular column an index, which will st
 use tabled::{builder::Builder, settings::Style};
 
 let mut builder = Builder::default();
-builder
-    .set_header(["Index", "Language", "Status"])
-    .push_record(["1", "English", "In progress"])
-    .push_record(["2", "Deutsch", "Not ready"]);
+builder.push_record(["Index", "Language", "Status"]);
+builder.push_record(["1", "English", "In progress"]);
+builder.push_record(["2", "Deutsch", "Not ready"]);
 
 let builder = builder.index().column(1).name(None);
 
diff --git a/tabled/examples/builder.rs b/tabled/examples/builder.rs
index 6baf29c2..434df793 100644
--- a/tabled/examples/builder.rs
+++ b/tabled/examples/builder.rs
@@ -20,7 +20,8 @@ fn main() {
     let oceans = ["Atlantic", "Pacific", "Indian", "Southern", "Arctic"];
 
     let mut builder = Builder::default();
-    builder.set_header(["#", "Ocean"]);
+    builder.push_record(["#", "Ocean"]);
+
     for (i, ocean) in oceans.iter().enumerate() {
         builder.push_record([i.to_string(), ocean.to_string()]);
     }
diff --git a/tabled/examples/builder_index.rs b/tabled/examples/builder_index.rs
index 9a53eb56..d7840367 100644
--- a/tabled/examples/builder_index.rs
+++ b/tabled/examples/builder_index.rs
@@ -40,8 +40,8 @@ fn main() {
     let mut table = Table::builder(data)
         .index()
         .column(0)
-        .name(None)
         .transpose()
+        .name(None)
         .build();
 
     table.with(Style::modern());
diff --git a/tabled/src/builder/index_builder.rs b/tabled/src/builder/index_builder.rs
index 93374ea4..b4f317bf 100644
--- a/tabled/src/builder/index_builder.rs
+++ b/tabled/src/builder/index_builder.rs
@@ -1,4 +1,4 @@
-use crate::Table;
+use crate::{grid::records::vec_records::CellInfo, Table};
 
 use super::Builder;
 
@@ -19,7 +19,7 @@ use super::Builder;
 /// use tabled::builder::Builder;
 ///
 /// let mut builder = Builder::default();
-/// builder.set_header(["i", "col-1", "col-2"]);
+/// builder.push_record(["i", "col-1", "col-2"]);
 /// builder.push_record(["0", "value-1", "value-2"]);
 ///
 /// let table = builder.index().build().to_string();
@@ -47,9 +47,9 @@ use super::Builder;
 pub struct IndexBuilder {
     /// Index is an index data.
     /// It's always set.
-    index: Vec<String>,
+    index: Vec<CellInfo<String>>,
     /// Name of an index
-    name: Option<String>,
+    name: Option<CellInfo<String>>,
     /// A flag which checks if we need to actually use index.
     ///
     /// It might happen when it's only necessary to [`Self::transpose`] table.
@@ -57,7 +57,9 @@ pub struct IndexBuilder {
     /// A flag which checks if table was transposed.
     transposed: bool,
     /// Data originated in [`Builder`].
-    data: Vec<Vec<String>>,
+    data: Vec<Vec<CellInfo<String>>>,
+    /// A size of columns
+    count_columns: usize,
 }
 
 impl IndexBuilder {
@@ -69,7 +71,7 @@ impl IndexBuilder {
     /// use tabled::builder::Builder;
     ///
     /// let mut builder = Builder::default();
-    /// builder.set_header(["i", "col-1", "col-2"]);
+    /// builder.push_record(["i", "col-1", "col-2"]);
     /// builder.push_record(["0", "value-1", "value-2"]);
     /// builder.push_record(["2", "value-3", "value-4"]);
     ///
@@ -101,7 +103,7 @@ impl IndexBuilder {
     /// use tabled::builder::Builder;
     ///
     /// let mut builder = Builder::default();
-    /// builder.set_header(["i", "column1", "column2"]);
+    /// builder.push_record(["i", "column1", "column2"]);
     /// builder.push_record(["0", "value1", "value2"]);
     ///
     /// let table = builder.index()
@@ -121,7 +123,7 @@ impl IndexBuilder {
     /// )
     /// ```
     pub fn name(mut self, name: Option<String>) -> Self {
-        self.name = name;
+        self.name = name.map(CellInfo::new);
         self
     }
 
@@ -135,7 +137,7 @@ impl IndexBuilder {
     /// use tabled::builder::Builder;
     ///
     /// let mut builder = Builder::default();
-    /// builder.set_header(["i", "column1", "column2"]);
+    /// builder.push_record(["i", "column1", "column2"]);
     /// builder.push_record(["0", "value1", "value2"]);
     ///
     /// let table = builder.index().column(1).build();
@@ -152,13 +154,13 @@ impl IndexBuilder {
     /// )
     /// ```
     pub fn column(mut self, column: usize) -> Self {
-        if column >= matrix_count_columns(&self.data) {
+        if column >= self.count_columns {
             return self;
         }
 
         self.index = get_column(&mut self.data, column);
 
-        let name = remove_or_default(&mut self.index, 0);
+        let name = self.index.remove(0);
         self.name = Some(name);
 
         self
@@ -172,7 +174,7 @@ impl IndexBuilder {
     /// use tabled::builder::Builder;
     ///
     /// let mut builder = Builder::default();
-    /// builder.set_header(["i", "column-1", "column-2", "column-3"]);
+    /// builder.push_record(["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"]);
@@ -193,16 +195,20 @@ impl IndexBuilder {
     /// )
     /// ```
     pub fn transpose(mut self) -> Self {
-        let columns = &mut self.data[0];
-        std::mem::swap(&mut self.index, columns);
+        if self.data.is_empty() {
+            return self;
+        }
 
-        let columns = self.data.remove(0);
+        let mut columns = self.data.remove(0);
+        std::mem::swap(&mut self.index, &mut columns);
 
-        make_rows_columns(&mut self.data);
+        let count_columns = columns.len();
+        make_rows_columns(&mut self.data, self.index.len());
 
         self.data.insert(0, columns);
 
         self.transposed = !self.transposed;
+        self.count_columns = count_columns;
 
         self
     }
@@ -216,25 +222,23 @@ impl IndexBuilder {
 
 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));
+        let count_columns = builder.count_columns();
+        let data: Vec<Vec<_>> = builder.into();
+
+        let mut index = Vec::new();
+        if !data.is_empty() {
+            // we exclude first row which contains a header
+            let count_rows = data.len() - 1;
+            index = build_range_index(count_rows);
         }
 
-        // 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,
+            data,
+            count_columns,
             name: None,
             print_index: true,
             transposed: false,
-            data,
         }
     }
 }
@@ -247,14 +251,13 @@ impl From<IndexBuilder> for Builder {
 
 fn build_index(mut b: IndexBuilder) -> Builder {
     // we can skip the conversion if this builder has neither data rows nor header row
-    if b.index.is_empty() && matrix_count_columns(&b.data) == 0 {
+    if b.index.is_empty() && b.count_columns == 0 {
         return Builder::default();
     }
 
     // add index column
     if b.print_index {
-        b.index.insert(0, String::default());
-
+        b.index.insert(0, CellInfo::default());
         insert_column(&mut b.data, b.index, 0);
     }
 
@@ -262,38 +265,39 @@ fn build_index(mut b: IndexBuilder) -> Builder {
         if b.transposed && b.print_index {
             b.data[0][0] = name;
         } else {
-            b.data.insert(1, vec![name]);
+            let count_columns = b.data[0].len();
+            let mut name_row = vec![CellInfo::default(); count_columns];
+            name_row[0] = name;
+
+            b.data.insert(1, name_row);
         }
     }
 
-    Builder::from(b.data)
-}
-
-fn build_range_index(n: usize) -> Vec<String> {
-    (0..n).map(|i| i.to_string()).collect()
+    Builder::from_vec(b.data)
 }
 
-fn remove_or_default<T: Default>(v: &mut Vec<T>, i: usize) -> T {
-    if v.len() > i {
-        v.remove(i)
-    } else {
-        T::default()
-    }
+fn build_range_index(n: usize) -> Vec<CellInfo<String>> {
+    (0..n).map(|i| i.to_string()).map(CellInfo::new).collect()
 }
 
-fn get_column<T: Default>(v: &mut [Vec<T>], col: usize) -> Vec<T> {
+fn get_column<T>(v: &mut [Vec<T>], col: usize) -> Vec<T>
+where
+    T: Default,
+{
     let mut column = Vec::with_capacity(v.len());
     for row in v.iter_mut() {
-        let value = remove_or_default(row, col);
+        let value = row.remove(col);
         column.push(value);
     }
 
     column
 }
 
-fn make_rows_columns<T: Default>(v: &mut Vec<Vec<T>>) {
-    let count_columns = matrix_count_columns(v);
-
+// todo: Seems like can be hugely simplified.
+fn make_rows_columns<T>(v: &mut Vec<Vec<T>>, count_columns: usize)
+where
+    T: Default,
+{
     let mut columns = Vec::with_capacity(count_columns);
     for _ in 0..count_columns {
         let column = get_column(v, 0);
@@ -309,11 +313,7 @@ fn make_rows_columns<T: Default>(v: &mut Vec<Vec<T>>) {
 
 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);
+        let value = column.remove(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/tabled/src/builder/mod.rs b/tabled/src/builder/mod.rs
index 9002ba23..5e1214c1 100644
--- a/tabled/src/builder/mod.rs
+++ b/tabled/src/builder/mod.rs
@@ -86,10 +86,7 @@
 //!     Status::Complete { started_timestamp: 123, finihsed_timestamp: 234 },
 //! ];
 //!
-//! let mut builder = Table::builder(&data);
-//! builder.clean();
-//!
-//! let table = builder.build()
+//! let table = Table::new(data)
 //!     .with(Style::modern())
 //!     .to_string();
 //!
@@ -98,13 +95,13 @@
 //! assert_eq!(
 //!     table,
 //!     concat!(
-//!         "┌───────────────────┬────────────────────┬─────────┐\n",
-//!         "│ started_timestamp │ finihsed_timestamp │ Unknown │\n",
-//!         "├───────────────────┼────────────────────┼─────────┤\n",
-//!         "│                   │                    │ +       │\n",
-//!         "├───────────────────┼────────────────────┼─────────┤\n",
-//!         "│ 123               │ 234                │         │\n",
-//!         "└───────────────────┴────────────────────┴─────────┘",
+//!         "┌───────────────────┬────────────────────┬───────────┬───────┬─────────┐\n",
+//!         "│ started_timestamp │ finihsed_timestamp │ timestamp │ Ready │ Unknown │\n",
+//!         "├───────────────────┼────────────────────┼───────────┼───────┼─────────┤\n",
+//!         "│                   │                    │           │       │ +       │\n",
+//!         "├───────────────────┼────────────────────┼───────────┼───────┼─────────┤\n",
+//!         "│ 123               │ 234                │           │       │         │\n",
+//!         "└───────────────────┴────────────────────┴───────────┴───────┴─────────┘",
 //!    ),
 //! )
 //! ```
diff --git a/tabled/src/builder/table_builder.rs b/tabled/src/builder/table_builder.rs
index 40316494..64318b23 100644
--- a/tabled/src/builder/table_builder.rs
+++ b/tabled/src/builder/table_builder.rs
@@ -12,7 +12,7 @@ use super::IndexBuilder;
 /// use tabled::builder::Builder;
 ///
 /// let mut builder = Builder::default();
-/// builder.set_header(["index", "measure", "value"]);
+/// builder.push_record(["index", "measure", "value"]);
 /// builder.push_record(["0", "weight", "0.443"]);
 ///
 /// let table = builder.build();
@@ -40,14 +40,10 @@ use super::IndexBuilder;
 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>,
+    empty_text: CellInfo<String>,
 }
 
 impl Builder {
@@ -67,79 +63,38 @@ impl Builder {
     /// ```
     /// use tabled::builder::Builder;
     ///
-    /// let mut builder = Builder::with_capacity(2);
+    /// let mut builder = Builder::with_capacity(2, 3);
     /// 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);
+    pub fn with_capacity(count_records: usize, count_columns: usize) -> Self {
+        let mut builder = Self::new();
+        builder.data = Vec::with_capacity(count_records);
+        builder.count_columns = count_columns;
 
-        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
+        builder
     }
 
-    /// 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\
-    ///      +-------+----+-------+"
-    /// );
+    /// Creates a [`Builder`] instance.
     ///
+    /// # Safety
     ///
-    /// let mut builder = Table::builder(data);
-    /// builder.remove_header();
-    /// let table = builder.build().to_string();
+    /// It's marked unsafe to emphasize that you shall make sure that all rows bound to have the same length.
     ///
-    /// assert_eq!(
-    ///     table,
-    ///     "+-------+----+-------+\n\
-    ///      | Hello | 1  | false |\n\
-    ///      +-------+----+-------+\n\
-    ///      | World | 21 | true  |\n\
-    ///      +-------+----+-------+"
-    /// );
+    /// ```
+    /// use tabled::builder::Builder;
     ///
+    /// let data = vec![];
+    /// let builder = Builder::from_vec(data);
     /// ```
-    pub fn remove_header(&mut self) -> &mut Self {
-        self.columns = None;
-        self.count_columns = self.get_size();
+    pub fn from_vec(data: Vec<Vec<CellInfo<String>>>) -> Self {
+        let count_columns = if data.is_empty() { 0 } else { data[0].len() };
 
-        self
+        Self {
+            data,
+            count_columns,
+            empty_text: CellInfo::default(),
+        }
     }
 
     /// Sets a content of cells which are created in case rows has different length.
@@ -149,17 +104,15 @@ impl Builder {
     /// 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"]);
+    /// builder.set_empty("undefined");
+    /// builder.push_record((0..3).map(|i| i.to_string()));
+    /// builder.push_record(["i"]);
     /// ```
-    pub fn set_default_text<T>(&mut self, text: T) -> &mut Self
+    pub fn set_empty<T>(&mut self, text: T)
     where
         T: Into<String>,
     {
-        self.empty_cell_text = Some(text.into());
-        self
+        self.empty_text = CellInfo::new(text.into());
     }
 
     /// Build creates a [`Table`] instance.
@@ -168,7 +121,7 @@ impl Builder {
     /// use tabled::builder::Builder;
     ///
     /// let mut builder = Builder::default();
-    /// builder.set_header(["i", "column1", "column2"]);
+    /// builder.push_record(["i", "column1", "column2"]);
     /// builder.push_record(["0", "value1", "value2"]);
     /// ```
     pub fn build(self) -> Table {
@@ -212,17 +165,21 @@ impl Builder {
     /// 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
+    pub fn push_record<R>(&mut self, record: R)
     where
-        R: IntoIterator<Item = T>,
-        T: Into<String>,
+        R: IntoIterator,
+        R::Item: Into<String>,
     {
-        let list = create_row(row, self.count_columns);
+        let list = create_row(record, self.count_columns, &self.empty_text);
+        let list_length = list.len();
 
-        self.update_size(list.len());
-        self.data.push(list);
+        if !is_size_eq(self.count_columns, list_length) {
+            let size = list_length - self.count_columns;
+            resize_rows(&mut self.data, size, &self.empty_text)
+        }
 
-        self
+        self.count_columns = list_length;
+        self.data.push(list);
     }
 
     /// Insert a row into a specific position.
@@ -230,17 +187,21 @@ impl Builder {
     /// # Panics
     ///
     /// Panics if `index > count_rows`.
-    pub fn insert_record<R>(&mut self, index: usize, record: R) -> bool
+    pub fn insert_record<R>(&mut self, index: usize, record: R)
     where
         R: IntoIterator,
         R::Item: Into<String>,
     {
-        let list = create_row(record, self.count_columns);
+        let list = create_row(record, self.count_columns, &self.empty_text);
+        let list_length = list.len();
 
-        self.update_size(list.len());
-        self.data.insert(index, list);
+        if !is_size_eq(self.count_columns, list_length) {
+            let size = list_length - self.count_columns;
+            resize_rows(&mut self.data, size, &self.empty_text)
+        }
 
-        true
+        self.count_columns = list_length;
+        self.data.insert(index, list);
     }
 
     /// Clean removes empty columns and rows.
@@ -266,178 +227,158 @@ impl Builder {
     ///      +-------+"
     /// )
     /// ```
-    pub fn clean(&mut self) -> &mut Self {
-        self.clean_columns();
-        self.clean_rows();
-        self
+    pub fn clean(&mut self) {
+        self.count_columns -= remove_empty_columns(&mut self.data, self.count_columns);
+        remove_empty_rows(&mut self.data, self.count_columns);
     }
 
-    /// Set a column size.
+    /// Removes a row with a specific position.
     ///
-    /// 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
+    /// Index expected to be in range.
+    /// `Builder::count_records() < x >= 0`
+    ///
+    /// # Panics
+    ///
+    /// Panics if `row_index > count_rows`.
+    pub fn remove_record(&mut self, index: usize) {
+        let _ = self.data.remove(index);
     }
 
-    /// Returns an amount of columns which would be present in a built table.
-    pub fn count_columns(&self) -> usize {
-        self.count_columns
-    }
+    /// Removes a column with a specific position.
+    ///
+    /// Index expected to be in range.
+    /// `Builder::count_columns() < x >= 0`
+    ///
+    /// # Panics
+    ///
+    /// Panics if `index > count_columns`.
+    pub fn remove_column(&mut self, index: usize) {
+        for row in &mut self.data {
+            let _ = row.remove(index);
+        }
 
-    /// Returns an amount of rows which would be present in a built table.
-    pub fn count_rows(&self) -> usize {
-        self.data.len()
+        self.count_columns -= 1;
     }
 
-    /// Checks whether a builder contains a header set.
-    pub fn has_header(&self) -> bool {
-        self.columns.is_some()
-    }
+    /// Push a column.
+    pub fn push_column<I>(&mut self, column: I)
+    where
+        I: IntoIterator,
+        I::Item: Into<String>,
+    {
+        let mut iter = column.into_iter();
 
-    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;
-                }
-            }
+        for row in self.data.iter_mut() {
+            let text = iter
+                .next()
+                .map(Into::into)
+                .map(CellInfo::new)
+                .unwrap_or(self.empty_text.clone());
 
-            if is_empty {
-                for row in 0..self.data.len() {
-                    let _ = self.data[row].remove(col);
-                }
+            row.push(text);
+        }
 
-                if let Some(columns) = self.columns.as_mut() {
-                    if columns.len() > col {
-                        let _ = columns.remove(col);
-                    }
-                }
+        for text in iter {
+            let text = CellInfo::new(text.into());
 
-                i += 1;
+            let mut row = Vec::with_capacity(self.count_columns + 1);
+            for _ in 0..self.count_columns {
+                row.push(self.empty_text.clone());
             }
+
+            row.push(text);
         }
 
-        self.count_columns -= i;
+        self.count_columns += 1;
     }
 
-    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;
-                }
-            }
+    /// Insert a column with a specific position.
+    ///
+    /// In case a column is bigger then the total amount of rows it will be truncated.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `index > count_columns`.
+    pub fn insert_column<I>(&mut self, index: usize, column: I)
+    where
+        I: IntoIterator,
+        I::Item: Into<String>,
+    {
+        let mut iter = column.into_iter();
 
-            if is_empty {
-                let _ = self.data.remove(row);
-            }
+        for row in self.data.iter_mut() {
+            let text = iter
+                .next()
+                .map(Into::into)
+                .map(CellInfo::new)
+                .unwrap_or(self.empty_text.clone());
 
-            if row == 0 {
-                break;
-            }
+            row.insert(index, text);
         }
-    }
 
-    fn update_size(&mut self, size: usize) {
-        use std::cmp::Ordering;
+        for text in iter {
+            let text = CellInfo::new(text.into());
 
-        match size.cmp(&self.count_columns) {
-            Ordering::Less => {
-                if !self.data.is_empty() {
-                    self.is_consistent = false;
-                }
+            let mut row = Vec::with_capacity(self.count_columns + 1);
+            for _ in 0..index {
+                row.push(self.empty_text.clone());
             }
-            Ordering::Greater => {
-                self.count_columns = size;
 
-                if !self.data.is_empty() || self.columns.is_some() {
-                    self.is_consistent = false;
-                }
+            row.push(text);
+
+            for _ in index..self.count_columns {
+                row.push(self.empty_text.clone());
             }
-            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
+        self.count_columns += 1;
     }
 
-    fn fix_rows(&mut self) {
-        let empty_cell = self.empty_cell_text.to_owned().unwrap_or_default();
-        let empty = CellInfo::new(empty_cell);
+    /// Remove all records.
+    pub fn clear(&mut self) {
+        self.data.clear();
+        self.count_columns = 0;
+    }
 
-        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);
-            }
-        }
+    /// Returns an amount of columns which would be present in a built table.
+    pub fn count_columns(&self) -> usize {
+        self.count_columns
+    }
 
-        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);
-            }
-        }
+    /// Returns an amount of rows which would be present in a built table.
+    ///
+    /// Notice that it does not include header if present;
+    /// It returns only amount of records.
+    pub fn count_records(&self) -> usize {
+        self.data.len()
     }
 }
 
 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);
-        }
-
+    fn from(builder: Builder) -> Self {
         builder
             .data
             .into_iter()
-            .map(|row| row.into_iter().map(|c| c.into_inner()).collect())
+            .map(|row| row.into_iter().map(CellInfo::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);
-        }
-
+    fn from(builder: Builder) -> Self {
         builder.data
     }
 }
 
-impl<R, V> FromIterator<R> for Builder
+impl<R> FromIterator<R> for Builder
 where
-    R: IntoIterator<Item = V>,
-    V: Into<String>,
+    R: IntoIterator,
+    R::Item: Into<String>,
 {
     fn from_iter<T: IntoIterator<Item = R>>(iter: T) -> Self {
-        let mut builder = Self::default();
+        let mut builder = Self::new();
         for row in iter {
-            let _ = builder.push_record(row);
+            builder.push_record(row);
         }
 
         builder
@@ -449,58 +390,157 @@ where
     D: Into<String>,
 {
     fn extend<T: IntoIterator<Item = D>>(&mut self, iter: T) {
-        let _ = self.push_record(iter);
+        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
+        let mut data = data
             .into_iter()
             .map(|row| row.into_iter().map(CellInfo::new).collect())
             .collect();
 
+        let count_columns = equalize_row_length(&mut data);
+
         Self {
             data,
             count_columns,
-            columns: None,
-            is_consistent: false,
-            empty_cell_text: None,
+            empty_text: CellInfo::default(),
         }
     }
 }
 
 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());
+    fn from(mut data: Vec<Vec<CellInfo<String>>>) -> Self {
+        let count_columns = equalize_row_length(&mut data);
 
         Self {
             data,
             count_columns,
-            columns: None,
-            is_consistent: false,
-            empty_cell_text: None,
+            empty_text: CellInfo::default(),
         }
     }
 }
 
-fn create_row<R, T>(row: R, size: usize) -> Vec<CellInfo<String>>
+fn create_row<R>(row: R, size: usize, default: &CellInfo<String>) -> Vec<CellInfo<String>>
 where
-    R: IntoIterator<Item = T>,
-    T: Into<String>,
+    R: IntoIterator,
+    R::Item: 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);
+        let text = CellInfo::new(text);
+        list.push(text);
+    }
+
+    if list.len() < size {
+        for _ in 0..size - list.len() {
+            let text = default.clone();
+            list.push(text);
+        }
     }
 
     list
 }
 
-fn append_vec<T: Clone>(v: &mut Vec<T>, value: T, n: usize) {
-    v.extend((0..n).map(|_| value.clone()));
+fn remove_empty_columns(data: &mut [Vec<CellInfo<String>>], count_columns: usize) -> usize {
+    let mut deleted = 0;
+    for col in 0..count_columns {
+        let col = col - deleted;
+
+        let mut is_empty_column = true;
+        for row in data.iter() {
+            let text = &row[col];
+            if !text.as_ref().is_empty() {
+                is_empty_column = false;
+                break;
+            }
+        }
+
+        if is_empty_column {
+            for row in data.iter_mut() {
+                let _ = row.remove(col);
+            }
+
+            deleted += 1;
+        }
+    }
+
+    deleted
+}
+
+fn remove_empty_rows(data: &mut Vec<Vec<CellInfo<String>>>, count_columns: usize) {
+    let mut deleted = 0;
+
+    for row in 0..data.len() {
+        let row = row - deleted;
+
+        let mut is_empty_row = true;
+        for col in 0..count_columns {
+            let cell = &data[row][col];
+            if !cell.as_ref().is_empty() {
+                is_empty_row = false;
+                break;
+            }
+        }
+
+        if is_empty_row {
+            let _ = data.remove(row);
+            deleted += 1;
+        }
+    }
+}
+
+fn resize_rows(data: &mut Vec<Vec<CellInfo<String>>>, size: usize, empty_text: &CellInfo<String>) {
+    for row in data {
+        append_vec(row, empty_text.clone(), size);
+    }
+}
+
+fn append_vec<T>(v: &mut Vec<T>, value: T, n: usize)
+where
+    T: Clone,
+{
+    for _ in 0..n {
+        v.push(value.clone());
+    }
+}
+
+fn is_size_eq(expected: usize, new: usize) -> bool {
+    use std::cmp::Ordering;
+
+    match new.cmp(&expected) {
+        Ordering::Less => {
+            unreachable!("must be impossible due to the assumptions/checks we do");
+        }
+        Ordering::Greater => false,
+        Ordering::Equal => true,
+    }
+}
+
+fn equalize_row_length(data: &mut Vec<Vec<CellInfo<String>>>) -> usize {
+    if data.is_empty() {
+        return 0;
+    }
+
+    let first_row_length = data[0].len();
+    let init = (first_row_length, true);
+    let (count_columns, is_consistent) = data.iter().fold(init, |mut acc, cur| {
+        let length = cur.len();
+        acc.1 = acc.1 && acc.0 == length;
+        acc.0 = std::cmp::max(acc.0, length);
+        acc
+    });
+
+    if !is_consistent {
+        let empty_text = CellInfo::default();
+        for row in data {
+            let size = count_columns - row.len();
+            append_vec(row, empty_text.clone(), size);
+        }
+    }
+
+    count_columns
 }
diff --git a/tabled/src/lib.rs b/tabled/src/lib.rs
index 5170be2e..68cfb710 100644
--- a/tabled/src/lib.rs
+++ b/tabled/src/lib.rs
@@ -112,21 +112,17 @@
 //!
 //! let mut builder = Builder::default();
 //!
-//! let header = iter::once(String::from("i"))
-//!     .chain((0..y)
-//!     .map(|i| i.to_string()));
-//! builder.set_header(header);
+//! let header = iter::once(String::from("i")).chain((0..y).map(|i| i.to_string()));
+//! builder.push_record(header);
 //!
 //! for i in 0..x {
-//!     let row = iter::once(i)
-//!         .chain((0..y).map(|j| i * j))
-//!         .map(|i| i.to_string());
+//!     let row = iter::once(i).chain((0..y).map(|j| i * j)).map(|i| i.to_string());
 //!     builder.push_record(row);
 //! }
 //!
 //! let table = builder.build()
 //!     .with(Style::rounded())
-//!     .with(Modify::new(Rows::new(1..)).with(Alignment::left()))
+//!     .modify(Rows::new(1..), Alignment::left())
 //!     .to_string();
 //!
 //! assert_eq!(
diff --git a/tabled/src/settings/disable/mod.rs b/tabled/src/settings/disable/mod.rs
index 6b4806a8..28346181 100644
--- a/tabled/src/settings/disable/mod.rs
+++ b/tabled/src/settings/disable/mod.rs
@@ -69,7 +69,6 @@ impl<L> Disable<L, TargetColumn> {
     /// use tabled::{builder::Builder, settings::{Disable, location::ByColumnName, object::Columns}};
     ///
     /// let mut builder = Builder::default();
-    ///
     /// builder.push_record(["col1", "col2", "col3"]);
     /// builder.push_record(["Hello", "World", "1"]);
     ///
diff --git a/tabled/src/settings/formatting/charset.rs b/tabled/src/settings/formatting/charset.rs
index c58effcd..a2b047d3 100644
--- a/tabled/src/settings/formatting/charset.rs
+++ b/tabled/src/settings/formatting/charset.rs
@@ -49,12 +49,16 @@ impl Charset {
 /// # Example
 ///
 /// ```
-/// use tabled::{Table, settings::formatting::Charset};
+/// use std::iter::FromIterator;
+/// use tabled::{
+///     Table, builder::Builder,
+///     settings::formatting::Charset,
+/// };
 ///
 /// let text = "Some text which was created on windows \r\n yes they use this \\r\\n";
 ///
-/// let mut builder = Table::builder([text]);
-/// builder.set_header(["win. text"]);
+/// let mut builder = Builder::from(Table::from_iter([[text]]));
+/// builder.insert_record(0, ["win. text"]);
 ///
 /// let mut table = builder.build();
 /// table.with(Charset::clean());
diff --git a/tabled/src/tables/table.rs b/tabled/src/tables/table.rs
index 789a85f5..d8105879 100644
--- a/tabled/src/tables/table.rs
+++ b/tabled/src/tables/table.rs
@@ -156,20 +156,14 @@ impl Table {
         T: Tabled,
         I: IntoIterator<Item = T>,
     {
-        let mut records = Vec::new();
-        for row in iter {
-            let mut list = Vec::with_capacity(T::LENGTH);
-            for text in row.fields().into_iter() {
-                list.push(text.into_owned());
-            }
+        let mut builder = Builder::with_capacity(0, T::LENGTH);
+        builder.push_record(T::headers());
 
-            records.push(list);
+        for row in iter {
+            builder.push_record(row.fields().into_iter());
         }
 
-        let mut b = Builder::from(records);
-        let _ = b.set_header(T::headers()).hint_column_size(T::LENGTH);
-
-        b
+        builder
     }
 
     /// It's a generic function which applies options to the [`Table`].
@@ -323,10 +317,10 @@ impl fmt::Display for Table {
     }
 }
 
-impl<T, V> FromIterator<T> for Table
+impl<T> FromIterator<T> for Table
 where
-    T: IntoIterator<Item = V>,
-    V: Into<String>,
+    T: IntoIterator,
+    T::Item: Into<String>,
 {
     fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
         Builder::from_iter(iter.into_iter().map(|i| i.into_iter().map(|s| s.into()))).build()
@@ -335,7 +329,7 @@ where
 
 impl From<Builder> for Table {
     fn from(builder: Builder) -> Self {
-        let data: Vec<Vec<CellInfo<String>>> = builder.into();
+        let data = builder.into();
         let records = VecRecords::new(data);
 
         Self {
@@ -348,11 +342,8 @@ impl From<Builder> for Table {
 
 impl From<Table> for Builder {
     fn from(val: Table) -> Self {
-        let count_columns = val.count_columns();
-        let data: Vec<Vec<CellInfo<String>>> = val.records.into();
-        let mut builder = Builder::from(data);
-        let _ = builder.hint_column_size(count_columns);
-        builder
+        let data = val.records.into();
+        Builder::from_vec(data)
     }
 }
 
diff --git a/tabled/src/tables/table_pool.rs b/tabled/src/tables/table_pool.rs
index 07d2a543..cc13b992 100644
--- a/tabled/src/tables/table_pool.rs
+++ b/tabled/src/tables/table_pool.rs
@@ -428,7 +428,7 @@ mod print {
             intersections_horizontal = data.intersections_horizontal;
             next_intersections_vertical.extend(data.intersections_vertical);
 
-            let _ = builder.push_record([data.content]);
+            builder.push_record([data.content]);
         }
 
         let table = builder
@@ -521,13 +521,14 @@ mod print {
             buf.push(value);
         }
 
-        let mut b = Builder::with_capacity(1);
-        let _ = b.hint_column_size(buf.len()).push_record(buf);
-        let table = b
-            .build()
-            .with(Style::empty())
-            .with(Padding::zero())
-            .to_string();
+        let mut builder = Builder::with_capacity(1, buf.len());
+        builder.push_record(buf);
+
+        let mut table = builder.build();
+        let _ = table.with(Style::empty());
+        let _ = table.with(Padding::zero());
+
+        let table = table.to_string();
 
         CellData::new(table, new_intersections_horizontal, intersections_vertical)
     }


Test patch:
diff --git a/tabled/tests/core/builder_test.rs b/tabled/tests/core/builder_test.rs
index 7751df12..dca4d27c 100644
--- a/tabled/tests/core/builder_test.rs
+++ b/tabled/tests/core/builder_test.rs
@@ -25,17 +25,16 @@ test_table!(
 );
 
 test_table!(
-    set_header,
+    header_remove_0,
     {
         let mut b = Builder::default();
-        b.set_header(["1", "2", "3"]);
+        b.push_record(["1", "2", "3"]);
         b.push_record(["a", "b", "c"]);
         b.push_record(["d", "e", "f"]);
+        b.remove_record(0);
         b.build()
     },
     "+---+---+---+"
-    "| 1 | 2 | 3 |"
-    "+---+---+---+"
     "| a | b | c |"
     "+---+---+---+"
     "| d | e | f |"
@@ -43,37 +42,139 @@ test_table!(
 );
 
 test_table!(
-    header_remove_0,
+    header_remove_1,
     {
         let mut b = Builder::default();
-        b.set_header(["1", "2", "3"]);
         b.push_record(["a", "b", "c"]);
+        b.push_record(["1", "2", "3", "4", "5"]);
         b.push_record(["d", "e", "f"]);
-        b.remove_header();
+        b.remove_record(1);
+        b.build()
+    },
+    "+---+---+---+--+--+"
+    "| a | b | c |  |  |"
+    "+---+---+---+--+--+"
+    "| d | e | f |  |  |"
+    "+---+---+---+--+--+"
+);
+
+test_table!(
+    remove_row_0,
+    {
+        let mut b = Builder::default();
+        b.push_record(["1", "2", "3"]);
+        b.push_record(["d", "e", "f"]);
+        b.push_record(["a", "b", "c"]);
+        b.remove_record(1);
         b.build()
     },
     "+---+---+---+"
-    "| a | b | c |"
+    "| 1 | 2 | 3 |"
     "+---+---+---+"
-    "| d | e | f |"
+    "| a | b | c |"
     "+---+---+---+"
 );
 
 test_table!(
-    header_remove_1,
+    remove_column_0,
     {
         let mut b = Builder::default();
-        b.set_header(["1", "2", "3", "4", "5"]);
+        b.push_record(["1", "2", "3"]);
         b.push_record(["a", "b", "c"]);
         b.push_record(["d", "e", "f"]);
-        b.remove_header();
+        b.remove_column(2);
         b.build()
     },
-    "+---+---+---+"
-    "| a | b | c |"
-    "+---+---+---+"
-    "| d | e | f |"
-    "+---+---+---+"
+    "+---+---+"
+    "| 1 | 2 |"
+    "+---+---+"
+    "| a | b |"
+    "+---+---+"
+    "| d | e |"
+    "+---+---+"
+);
+
+test_table!(
+    push_column_0,
+    {
+        let mut b = Builder::default();
+        b.push_record(["1", "2", "3"]);
+        b.push_record(["a", "b", "c"]);
+        b.push_record(["d", "e", "f"]);
+        b.push_column(["4", "g", "h"]);
+        b.build()
+    },
+    "+---+---+---+---+"
+    "| 1 | 2 | 3 | 4 |"
+    "+---+---+---+---+"
+    "| a | b | c | g |"
+    "+---+---+---+---+"
+    "| d | e | f | h |"
+    "+---+---+---+---+"
+);
+
+test_table!(
+    push_column_1,
+    {
+        let mut b = Builder::default();
+        b.push_record(["a", "b", "c"]);
+        b.push_record(["d", "e", "f"]);
+        b.push_column(["g", "h"]);
+        b.build()
+    },
+    "+---+---+---+---+"
+    "| a | b | c | g |"
+    "+---+---+---+---+"
+    "| d | e | f | h |"
+    "+---+---+---+---+"
+);
+
+test_table!(
+    insert_column_0,
+    {
+        let mut b = Builder::default();
+        b.push_record(["a", "b", "c"]);
+        b.push_record(["d", "e", "f"]);
+        b.insert_column(2, ["k", "n"]);
+        b.build()
+    },
+    "+---+---+---+---+"
+    "| a | b | k | c |"
+    "+---+---+---+---+"
+    "| d | e | n | f |"
+    "+---+---+---+---+"
+);
+
+test_table!(
+    insert_column_1,
+    {
+        let mut b = Builder::default();
+        b.push_record(["1", "2", "3"]);
+        b.push_record(["a", "b", "c"]);
+        b.push_record(["d", "e", "f"]);
+        b.insert_column(3, ["4", "l", "d"]);
+        b.build()
+    },
+    "+---+---+---+---+"
+    "| 1 | 2 | 3 | 4 |"
+    "+---+---+---+---+"
+    "| a | b | c | l |"
+    "+---+---+---+---+"
+    "| d | e | f | d |"
+    "+---+---+---+---+"
+);
+
+test_table!(
+    reset_table_0,
+    {
+        let mut b = Builder::default();
+        b.push_record(["1", "2", "3"]);
+        b.push_record(["a", "b", "c"]);
+        b.push_record(["d", "e", "f"]);
+        b.clear();
+        b.build()
+    },
+    ""
 );
 
 test_table!(
@@ -92,7 +193,7 @@ test_table!(
     used_with_different_number_of_columns_0,
     {
         let mut b = Builder::default();
-        b.set_header(["1", "2"]);
+        b.push_record(["1", "2"]);
         b.push_record(["a", "b", "c"]);
         b.push_record(["d"]);
         b.build()
@@ -110,7 +211,7 @@ test_table!(
     used_with_different_number_of_columns_1,
     {
         let mut b = Builder::default();
-        b.set_header(["1", "2", "3"]);
+        b.push_record(["1", "2", "3"]);
         b.push_record(["a", "b"]);
         b.push_record(["d"]);
         b.build()
@@ -128,7 +229,7 @@ test_table!(
     used_with_different_number_of_columns_2,
     {
         let mut b = Builder::default();
-        b.set_header(["1"]);
+        b.push_record(["1"]);
         b.push_record(["a", "b"]);
         b.push_record(["d", "e", "f"]);
         b.build()
@@ -146,7 +247,10 @@ test_table!(
     with_default_cell_0,
     {
         let mut b = Builder::default();
-        b.set_header(["1", "2"]).set_default_text("NaN").push_record(["a", "b", "c"]).push_record(["d"]);
+        b.push_record(["1", "2"]);
+        b.set_empty("NaN");
+        b.push_record(["a", "b", "c"]);
+        b.push_record(["d"]);
         b.build()
     },
     "+---+-----+-----+"
@@ -162,7 +266,10 @@ test_table!(
     with_default_cell_1,
     {
         let mut b = Builder::default();
-        b.set_header(["1"]).set_default_text("NaN").push_record(["a", "b"]).push_record(["d", "e", "f"]);
+        b.push_record(["1"]);
+        b.set_empty("NaN");
+        b.push_record(["a", "b"]);
+        b.push_record(["d", "e", "f"]);
         b.build()
     },
     "+---+-----+-----+"
@@ -430,7 +537,7 @@ test_table!(
 
 test_table!(
     clean_with_columns_0,
-    clean(Builder::from_iter([["1", "2", "3"], ["a", "b", "c"], ["d", "e", "f"]]).set_header(["col1", "col2", "col3"]).clone()),
+    clean_with_head([["1", "2", "3"], ["a", "b", "c"], ["d", "e", "f"]], ["col1", "col2", "col3"]),
     "+------+------+------+"
     "| col1 | col2 | col3 |"
     "+------+------+------+"
@@ -444,7 +551,7 @@ test_table!(
 
 test_table!(
     clean_with_columns_1,
-    clean(Builder::from_iter([["", "2", "3"], ["", "b", "c"], ["", "e", "f"]]).set_header(["col1", "col2", "col3"]).clone()),
+    clean_with_head([["", "2", "3"], ["", "b", "c"], ["", "e", "f"]], ["", "col2", "col3"]),
     "+------+------+"
     "| col2 | col3 |"
     "+------+------+"
@@ -458,7 +565,7 @@ test_table!(
 
 test_table!(
     clean_with_columns_2,
-    clean(Builder::from_iter([["1", "", "3"], ["a", "", "c"], ["d", "", "f"]]).set_header(["col1", "col2", "col3"]).clone()),
+    clean_with_head([["1", "", "3"], ["a", "", "c"], ["d", "", "f"]], ["col1", "", "col3"]),
     "+------+------+"
     "| col1 | col3 |"
     "+------+------+"
@@ -472,7 +579,7 @@ test_table!(
 
 test_table!(
     clean_with_columns_3,
-    clean(Builder::from_iter([["1", "2", ""], ["a", "b", ""], ["d", "e", ""]]).set_header(["col1", "col2", "col3"]).clone()),
+    clean_with_head([["1", "2", ""], ["a", "b", ""], ["d", "e", ""]], ["col1", "col2", ""]),
     "+------+------+"
     "| col1 | col2 |"
     "+------+------+"
@@ -486,7 +593,7 @@ test_table!(
 
 test_table!(
     clean_with_columns_4,
-    clean(Builder::from_iter([["", "", "3"], ["", "", "c"], ["", "", "f"]]).set_header(["col1", "col2", "col3"]).clone()),
+    clean_with_head([["", "", "3"], ["", "", "c"], ["", "", "f"]], ["", "", "col3"]),
     "+------+"
     "| col3 |"
     "+------+"
@@ -500,7 +607,7 @@ test_table!(
 
 test_table!(
     clean_with_columns_5,
-    clean(Builder::from_iter([["1", "", ""], ["a", "", ""], ["d", "", ""]]).set_header(["col1", "col2", "col3"]).clone()),
+    clean_with_head([["1", "", ""], ["a", "", ""], ["d", "", ""]], ["col1", "", ""]),
     "+------+"
     "| col1 |"
     "+------+"
@@ -514,7 +621,7 @@ test_table!(
 
 test_table!(
     clean_with_columns_6,
-    clean(Builder::from_iter([["", "2", ""], ["", "b", ""], ["", "e", ""]]).set_header(["col1", "col2", "col3"]).clone()),
+    clean_with_head([["", "2", ""], ["", "b", ""], ["", "e", ""]], ["", "col2", ""]),
     "+------+"
     "| col2 |"
     "+------+"
@@ -528,17 +635,13 @@ test_table!(
 
 test_table!(
     clean_with_columns_7,
-    clean(
-        Builder::from_iter([["", "", ""], ["", "", ""], ["", "", ""]])
-            .set_header(["col1", "col2", "col3"])
-            .clone()
-    ),
+    clean_with_head([["", "", ""], ["", "", ""], ["", "", ""]], ["", "", ""]),
     ""
 );
 
 test_table!(
     clean_with_columns_8,
-    clean(Builder::from_iter([["", "", ""], ["a", "b", "c"], ["d", "e", "f"]]).set_header(["col1", "col2", "col3"]).clone()),
+    clean_with_head([["", "", ""], ["a", "b", "c"], ["d", "e", "f"]], ["col1", "col2", "col3"]),
     "+------+------+------+"
     "| col1 | col2 | col3 |"
     "+------+------+------+"
@@ -550,7 +653,7 @@ test_table!(
 
 test_table!(
     clean_with_columns_9,
-    clean(Builder::from_iter([["1", "2", "3"], ["", "", ""], ["d", "e", "f"]]).set_header(["col1", "col2", "col3"]).clone()),
+    clean_with_head([["1", "2", "3"], ["", "", ""], ["d", "e", "f"]], ["col1", "col2", "col3"]),
     "+------+------+------+"
     "| col1 | col2 | col3 |"
     "+------+------+------+"
@@ -562,7 +665,7 @@ test_table!(
 
 test_table!(
     clean_with_columns_10,
-    clean(Builder::from_iter([["1", "2", "3"], ["a", "b", "c"], ["", "", ""]]).set_header(["col1", "col2", "col3"]).clone()),
+    clean_with_head([["1", "2", "3"], ["a", "b", "c"], ["", "", ""]], ["col1", "col2", "col3"]),
     "+------+------+------+"
     "| col1 | col2 | col3 |"
     "+------+------+------+"
@@ -574,7 +677,7 @@ test_table!(
 
 test_table!(
     clean_with_columns_11,
-    clean(Builder::from_iter([["", "", ""], ["", "", ""], ["d", "e", "f"]]).set_header(["col1", "col2", "col3"]).clone()),
+    clean_with_head([["", "", ""], ["", "", ""], ["d", "e", "f"]], ["col1", "col2", "col3"]),
     "+------+------+------+"
     "| col1 | col2 | col3 |"
     "+------+------+------+"
@@ -584,7 +687,7 @@ test_table!(
 
 test_table!(
     clean_with_columns_12,
-    clean(Builder::from_iter([["1", "2", "3"], ["", "", ""], ["", "", ""]]).set_header(["col1", "col2", "col3"]).clone()),
+    clean_with_head([["1", "2", "3"], ["", "", ""], ["", "", ""]], ["col1", "col2", "col3"]),
     "+------+------+------+"
     "| col1 | col2 | col3 |"
     "+------+------+------+"
@@ -594,7 +697,7 @@ test_table!(
 
 test_table!(
     clean_with_columns_13,
-    clean(Builder::from_iter([["", "", ""], ["a", "b", "c"], ["", "", ""]]).set_header(["col1", "col2", "col3"]).clone()),
+    clean_with_head([["", "", ""], ["a", "b", "c"], ["", "", ""]], ["col1", "col2", "col3"]),
     "+------+------+------+"
     "| col1 | col2 | col3 |"
     "+------+------+------+"
@@ -604,7 +707,7 @@ test_table!(
 
 test_table!(
     clean_with_columns_14,
-    clean(Builder::from_iter([["1", "", "3"], ["", "", ""], ["d", "", "f"]]).set_header(["col1", "col2", "col3"]).clone()),
+    clean_with_head([["1", "", "3"], ["", "", ""], ["d", "", "f"]], ["col1", "", "col3"]),
     "+------+------+"
     "| col1 | col3 |"
     "+------+------+"
@@ -622,13 +725,11 @@ test_table!(
     index,
     Builder::from_iter([["n", "name"], ["0", "Dmitriy"], ["1", "Vladislav"]]).index().build(),
     "+---+---+-----------+"
-    "|   | 0 | 1         |"
-    "+---+---+-----------+"
-    "| 0 | n | name      |"
+    "|   | n | name      |"
     "+---+---+-----------+"
-    "| 1 | 0 | Dmitriy   |"
+    "| 0 | 0 | Dmitriy   |"
     "+---+---+-----------+"
-    "| 2 | 1 | Vladislav |"
+    "| 1 | 1 | Vladislav |"
     "+---+---+-----------+"
 );
 
@@ -639,15 +740,13 @@ test_table!(
         .name(Some("A index name".into()))
         .build(),
     "+--------------+---+-----------+"
-    "|              | 0 | 1         |"
+    "|              | n | name      |"
     "+--------------+---+-----------+"
     "| A index name |   |           |"
     "+--------------+---+-----------+"
-    "| 0            | n | name      |"
+    "| 0            | 0 | Dmitriy   |"
     "+--------------+---+-----------+"
-    "| 1            | 0 | Dmitriy   |"
-    "+--------------+---+-----------+"
-    "| 2            | 1 | Vladislav |"
+    "| 1            | 1 | Vladislav |"
     "+--------------+---+-----------+"
 );
 
@@ -658,8 +757,6 @@ test_table!(
         .hide()
         .build(),
     "+---+-----------+"
-    "| 0 | 1         |"
-    "+---+-----------+"
     "| n | name      |"
     "+---+-----------+"
     "| 0 | Dmitriy   |"
@@ -675,11 +772,9 @@ test_table!(
         .column(1)
         .build(),
     "+-----------+---+"
-    "|           | 0 |"
-    "+-----------+---+"
-    "| 1         |   |"
+    "|           | n |"
     "+-----------+---+"
-    "| name      | n |"
+    "| name      |   |"
     "+-----------+---+"
     "| Dmitriy   | 0 |"
     "+-----------+---+"
@@ -695,12 +790,10 @@ test_table!(
         .name(Some("Hello".into()))
         .build(),
     "+-----------+---+"
-    "|           | 0 |"
+    "|           | n |"
     "+-----------+---+"
     "| Hello     |   |"
     "+-----------+---+"
-    "| name      | n |"
-    "+-----------+---+"
     "| Dmitriy   | 0 |"
     "+-----------+---+"
     "| Vladislav | 1 |"
@@ -715,9 +808,7 @@ test_table!(
         .name(None)
         .build(),
     "+-----------+---+"
-    "|           | 0 |"
-    "+-----------+---+"
-    "| name      | n |"
+    "|           | n |"
     "+-----------+---+"
     "| Dmitriy   | 0 |"
     "+-----------+---+"
@@ -731,18 +822,30 @@ test_table!(
         .index()
         .transpose()
         .build(),
-    "+---+------+---------+-----------+"
-    "|   | 0    | 1       | 2         |"
-    "+---+------+---------+-----------+"
-    "| 0 | n    | 0       | 1         |"
-    "+---+------+---------+-----------+"
-    "| 1 | name | Dmitriy | Vladislav |"
-    "+---+------+---------+-----------+"
-    "| 2 | zz   | 123     | 123       |"
-    "+---+------+---------+-----------+"
+    "+------+---------+-----------+"
+    "|      | 0       | 1         |"
+    "+------+---------+-----------+"
+    "| n    | 0       | 1         |"
+    "+------+---------+-----------+"
+    "| name | Dmitriy | Vladislav |"
+    "+------+---------+-----------+"
+    "| zz   | 123     | 123       |"
+    "+------+---------+-----------+"
 );
 
 fn clean(mut b: Builder) -> String {
     b.clean();
     b.build().to_string()
 }
+
+fn clean_with_head<D>(data: D, rec: impl IntoIterator<Item = &'static str>) -> String
+where
+    D: IntoIterator,
+    D::Item: IntoIterator,
+    <D::Item as IntoIterator>::Item: Into<String>,
+{
+    let mut b = Builder::from_iter(data);
+    b.insert_record(0, rec);
+    b.clean();
+    b.build().to_string()
+}
diff --git a/tabled/tests/core/index_test.rs b/tabled/tests/core/index_test.rs
index fd3d016c..3ba1403a 100644
--- a/tabled/tests/core/index_test.rs
+++ b/tabled/tests/core/index_test.rs
@@ -102,13 +102,11 @@ test_table!(
     builder_index_with_no_columns,
     Builder::from_iter([["1", "2", "3"], ["a", "b", "c"], ["d", "e", "f"]]).index().build(),
     "+---+---+---+---+"
-    "|   | 0 | 1 | 2 |"
+    "|   | 1 | 2 | 3 |"
     "+---+---+---+---+"
-    "| 0 | 1 | 2 | 3 |"
+    "| 0 | a | b | c |"
     "+---+---+---+---+"
-    "| 1 | a | b | c |"
-    "+---+---+---+---+"
-    "| 2 | d | e | f |"
+    "| 1 | d | e | f |"
     "+---+---+---+---+"
 );
 
@@ -116,18 +114,16 @@ test_table!(
     builder_index_with_no_columns_and_name,
     Builder::from_iter([["1", "2", "3"], ["a", "b", "c"], ["d", "e", "f"]])
         .index()
-        .name(Some("Hello World".into()))
+        .name(Some(String::from("Hello World")))
         .build(),
     "+-------------+---+---+---+"
-    "|             | 0 | 1 | 2 |"
+    "|             | 1 | 2 | 3 |"
     "+-------------+---+---+---+"
     "| Hello World |   |   |   |"
     "+-------------+---+---+---+"
-    "| 0           | 1 | 2 | 3 |"
-    "+-------------+---+---+---+"
-    "| 1           | a | b | c |"
+    "| 0           | a | b | c |"
     "+-------------+---+---+---+"
-    "| 2           | d | e | f |"
+    "| 1           | d | e | f |"
     "+-------------+---+---+---+"
 );
 
@@ -137,15 +133,15 @@ test_table!(
         .index()
         .transpose()
         .build(),
-    "+---+---+---+---+"
-    "|   | 0 | 1 | 2 |"
-    "+---+---+---+---+"
-    "| 0 | 1 | a | d |"
-    "+---+---+---+---+"
-    "| 1 | 2 | b | e |"
-    "+---+---+---+---+"
-    "| 2 | 3 | c | f |"
-    "+---+---+---+---+"
+    "+---+---+---+"
+    "|   | 0 | 1 |"
+    "+---+---+---+"
+    "| 1 | a | d |"
+    "+---+---+---+"
+    "| 2 | b | e |"
+    "+---+---+---+"
+    "| 3 | c | f |"
+    "+---+---+---+"
 );
 
 test_table!(builder_index_empty, Builder::default().index().build(), "");
@@ -175,7 +171,7 @@ test_table!(
     builder_index_with_header_but_no_data,
     {
         let mut b = Builder::default();
-        b.set_header(["one", "two", "three"]);
+        b.push_record(["one", "two", "three"]);
         b.index().build()
     },
     "+--+-----+-----+-------+"
@@ -205,14 +201,84 @@ fn builder_index_no_name_transpose_transpose() {
     assert_eq!(orig_table, two_times_transposed_table,);
 }
 
-#[test]
-fn builder_index_convert_back_to_builder() {
-    let mut b1 = Builder::default();
-    b1.set_header(["one", "two", "three"]);
-    let b2 = Builder::from(b1.clone().index().hide());
-    assert_eq!(b1.clone().build().shape(), b2.clone().build().shape());
-    assert_eq!(
-        b1.clone().build().to_string(),
-        b2.clone().build().to_string()
-    );
-}
+test_table!(
+    builder_index_convert_back_to_builder,
+    {
+        let mut b = Builder::new();
+        b.push_record(["one", "two", "three"]);
+        Builder::from(b.clone().index().hide()).build()
+    },
+    "+-----+-----+-------+"
+    "| one | two | three |"
+    "+-----+-----+-------+"
+);
+
+test_table!(
+    index_column_3_times,
+    Table::builder(Matrix::list::<3, 2>()).index().column(0).column(0).column(0).build(),
+    "+----------+"
+    "|          |"
+    "+----------+"
+    "| column 1 |"
+    "+----------+"
+    "| 0-1      |"
+    "+----------+"
+    "| 1-1      |"
+    "+----------+"
+    "| 2-1      |"
+    "+----------+"
+);
+
+test_table!(
+    index_transpose_with_no_name0,
+    Builder::from_iter([["col1", "col2", "col3"], ["a", "b", "c"], ["d", "e", "f"]])
+        .index()
+        .transpose()
+        .name(Some(String::from("hello world")))
+        .transpose()
+        .build(),
+    "+-------------+------+------+------+"
+    "|             | col1 | col2 | col3 |"
+    "+-------------+------+------+------+"
+    "| hello world |      |      |      |"
+    "+-------------+------+------+------+"
+    "| 0           | a    | b    | c    |"
+    "+-------------+------+------+------+"
+    "| 1           | d    | e    | f    |"
+    "+-------------+------+------+------+"
+);
+
+test_table!(
+    index_transpose_with_no_name1,
+    Builder::from_iter([["col1", "col2", "col3"], ["a", "b", "c"], ["d", "e", "f"]])
+        .index()
+        .transpose()
+        .name(Some(String::from("hello world")))
+        .build(),
+    "+-------------+---+---+"
+    "| hello world | 0 | 1 |"
+    "+-------------+---+---+"
+    "| col1        | a | d |"
+    "+-------------+---+---+"
+    "| col2        | b | e |"
+    "+-------------+---+---+"
+    "| col3        | c | f |"
+    "+-------------+---+---+"
+);
+
+test_table!(
+    index_transpose_with_no_name2,
+    Builder::from_iter([["col1", "col2", "col3"], ["a", "b", "c"], ["d", "e", "f"]])
+        .index()
+        .transpose()
+        .build(),
+    "+------+---+---+"
+    "|      | 0 | 1 |"
+    "+------+---+---+"
+    "| col1 | a | d |"
+    "+------+---+---+"
+    "| col2 | b | e |"
+    "+------+---+---+"
+    "| col3 | c | f |"
+    "+------+---+---+"
+);