Repository: zhiburt/tabled (rust)

Issue:
`table.is_empty()` on tables with only a header row
Hi, I run into a situation where I need to check if a table with a header row is empty. I notice that `table.is_empty()` returns false if the table has no data rows but merely a header row. However the function returns true if the table is indexed:

```rust
use tabled::{builder::Builder, settings::Style};

fn main() -> Result<()> {
    let mut builder = Builder::default();
    builder.set_header(["color", "vegetable", "contains"]);
    let builder = builder.index().column(1).name(None);
    let table = builder.build();
    assert!(table.is_empty());

    let mut builder = Builder::default();
    builder.set_header(["color", "vegetable", "contains"]);
    let table = builder.build();
    assert!(!table.is_empty());

    Ok(())
}
```
The difference seems to be caused by that `IndexBuilder` takes ["data length"](https://github.com/zhiburt/tabled/blob/master/tabled/src/builder/index_builder.rs#L229-L230) into consideration. Is this difference by-design or should non-indexed tables do the same too?

Pull request:
tabled/ Fix IndexBuilder on empty tables (#363)
There's a minor behaviour difference between how `Builder` and `IndexBuilder` handles tables that have no data rows but a header row. In that case, `Builder` will regard the header row itself as data, but `IndexBuilder` will not. This difference shows up when `table.is_empty()` is called on the resulting tables: such tables will have different shapes.

This patch fixes the process when an `IndexBuilder` is converted back to a `Builder`. With this patch, a default `Builder` will be returned only if the `IndexBuilder` has neither data rows nor a header row.

Unit tests are added accordingly.

Fix #363 

Now this code works:
```rust
use tabled::builder::Builder;

fn main() -> Result<()> {
    let mut builder = Builder::default();
    builder.set_header(["color", "vegetable", "contains"]);
    let builder = builder.index().name(None);
    let table = builder.build();
    assert!(!table.is_empty());
    assert_eq!(table.shape(), (1, 4));

    let mut builder = Builder::default();
    builder.set_header(["color", "vegetable", "contains"]);
    let table = builder.build();
    assert!(!table.is_empty());
    assert_eq!(table.shape(), (1, 3));

    Ok(())
}
```

Patch:
diff --git a/tabled/src/builder/index_builder.rs b/tabled/src/builder/index_builder.rs
index 081f580..93374ea 100644
--- a/tabled/src/builder/index_builder.rs
+++ b/tabled/src/builder/index_builder.rs
@@ -246,7 +246,8 @@ impl From<IndexBuilder> for Builder {
 }
 
 fn build_index(mut b: IndexBuilder) -> Builder {
-    if b.index.is_empty() {
+    // 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 {
         return Builder::default();
     }
 


Test patch:
diff --git a/tabled/tests/core/index_test.rs b/tabled/tests/core/index_test.rs
index f6e107a..fd3d016 100644
--- a/tabled/tests/core/index_test.rs
+++ b/tabled/tests/core/index_test.rs
@@ -157,7 +157,7 @@ test_table!(
 );
 
 test_table!(
-    builder_index_invalid_dosnt_panic,
+    builder_index_invalid_doesnt_panic,
     Builder::default().index().column(100).build(),
     ""
 );
@@ -171,6 +171,18 @@ test_table!(
     ""
 );
 
+test_table!(
+    builder_index_with_header_but_no_data,
+    {
+        let mut b = Builder::default();
+        b.set_header(["one", "two", "three"]);
+        b.index().build()
+    },
+    "+--+-----+-----+-------+"
+    "|  | one | two | three |"
+    "+--+-----+-----+-------+"
+);
+
 #[test]
 fn builder_index_transpose_transpose() {
     let data = Matrix::list::<4, 2>();
@@ -192,3 +204,15 @@ 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()
+    );
+}