Repository: zhiburt/tabled
Pull request #321 (2023-04-06 23:21:29)

json_to_table/ Add collapse orientation


Patch:
diff --git a/json_to_table/examples/orientation.rs b/json_to_table/examples/orientation.rs
index 5e8ea5f..53f59a9 100644
--- a/json_to_table/examples/orientation.rs
+++ b/json_to_table/examples/orientation.rs
@@ -33,8 +33,8 @@ fn main() {
 
     let mut htable = json_to_table(&json);
     htable
-        .set_array_mode(Orientation::Horizontal)
-        .set_object_mode(Orientation::Horizontal);
+        .array_orientation(Orientation::Horizontal)
+        .object_orientation(Orientation::Horizontal);
 
     let ctable = json_to_table(&json);
 
diff --git a/json_to_table/src/table.rs b/json_to_table/src/table.rs
deleted file mode 100644
index 54d8924..0000000
--- a/json_to_table/src/table.rs
+++ /dev/null
@@ -1,867 +0,0 @@
-use core::fmt::{self, Display};
-use std::borrow::Borrow;
-
-use serde_json::Value;
-use tabled::{
-    grid::config::{ColoredConfig, SpannedConfig},
-    settings::style::{RawStyle, Style},
-    Table,
-};
-
-/// Converter of [`Value`] to a table,
-/// with a set of configurations.
-
-// todo: rename to ValueTable.
-#[derive(Debug, Clone)]
-pub struct JsonTable<T> {
-    value: T,
-    cfg: Config,
-}
-
-impl<T> JsonTable<T> {
-    /// Creates a new [`JsonTable`] object.
-    pub fn new(value: T) -> Self {
-        JsonTable {
-            value,
-            cfg: Config {
-                plain: true,
-                style: None,
-                cfg: None,
-                array_orientation: Orientation::Vertical,
-                object_orientation: Orientation::Vertical,
-            },
-        }
-    }
-
-    /// Set a style which will be used,
-    /// default is [`Style::ascii`].
-    pub fn set_style(&mut self, style: impl Into<RawStyle>) -> &mut Self {
-        self.cfg.style = Some(style.into());
-        self
-    }
-
-    /// Collapse tables out instead of tables within tables.
-    pub fn collapse(&mut self) -> &mut Self {
-        self.cfg.plain = false;
-        self
-    }
-
-    /// Set a table mode for a [`serde_json::Value::Object`].
-    pub fn set_object_mode(&mut self, mode: Orientation) -> &mut Self {
-        self.cfg.object_orientation = mode;
-        self
-    }
-
-    /// Set a table mode for a [`serde_json::Value::Array`].
-    pub fn set_array_mode(&mut self, mode: Orientation) -> &mut Self {
-        self.cfg.array_orientation = mode;
-        self
-    }
-
-    /// Set a config which will be used.
-    ///
-    /// You can obtain a config from a [`Table`].
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use serde_json::json;
-    /// use json_to_table::json_to_table;
-    /// use tabled::{
-    ///     settings::{Alignment, Padding, Style},
-    ///     Table
-    /// };
-    ///
-    /// let value = json!({
-    ///     "key1": 123,
-    ///     "234": ["123", "234", "456"],
-    ///     "key22": {
-    ///         "k1": 1,
-    ///         "k2": 2,
-    ///     }
-    /// });
-    ///
-    /// let cfg = Table::new([""])
-    ///     .with(Padding::zero())
-    ///     .with(Alignment::right())
-    ///     .with(Style::extended())
-    ///     .get_config()
-    ///     .clone();
-    ///
-    /// let table = json_to_table(&value)
-    ///     .set_config(cfg)
-    ///     .collapse()
-    ///     .to_string();
-    ///
-    /// println!("{}", table);
-    ///
-    ///    assert_eq!(
-    ///        table,
-    ///        concat!(
-    ///             "╔═════╦════╗\n",  
-    ///             "║  234║ 123║\n",  
-    ///             "║     ╠════╣\n",  
-    ///             "║     ║ 234║\n",  
-    ///             "║     ╠════╣\n",  
-    ///             "║     ║ 456║\n",  
-    ///             "╠═════╬════╣\n",  
-    ///             "║ key1║ 123║\n",  
-    ///             "╠═════╬══╦═╣\n",  
-    ///             "║key22║k1║1║\n",  
-    ///             "║     ╠══╬═╣\n",  
-    ///             "║     ║k2║2║\n",  
-    ///             "╚═════╩══╩═╝",
-    ///        ),
-    ///    );
-    /// ```
-    ///
-    /// [`Table`]: tabled::Table
-    pub fn set_config(&mut self, cfg: ColoredConfig) -> &mut Self {
-        self.cfg.cfg = Some(cfg);
-        self
-    }
-}
-
-impl<T> Display for JsonTable<T>
-where
-    T: Borrow<Value>,
-{
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let table = json_to_table::json_to_table(self.value.borrow(), &self.cfg);
-        table.fmt(f)
-    }
-}
-
-impl<T> From<JsonTable<T>> for Table
-where
-    T: Borrow<Value>,
-{
-    fn from(t: JsonTable<T>) -> Self {
-        json_to_table::json_to_table(t.value.borrow(), &t.cfg)
-    }
-}
-
-#[derive(Debug, Clone)]
-struct Config {
-    plain: bool,
-    style: Option<RawStyle>,
-    cfg: Option<ColoredConfig>,
-    object_orientation: Orientation,
-    array_orientation: Orientation,
-}
-
-/// The structure represents a table mode for a given entity,
-/// either it will be rendered vertically or horizontally.
-#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord)]
-pub enum Orientation {
-    /// Vertical mode (from top to bottom).
-    Vertical,
-    /// Horizontal mode (from left to right).
-    Horizontal,
-}
-
-mod json_to_table {
-    #![allow(clippy::too_many_arguments)]
-
-    use std::cmp;
-
-    use tabled::{
-        builder::Builder,
-        col,
-        grid::{
-            config::{ColoredConfig, Entity, Offset},
-            dimension::{Dimension, Estimate},
-            records::Records,
-            util::string::string_width_multiline,
-        },
-        settings::{Format, Height, Padding, Settings, TableOption, Width},
-    };
-
-    use super::*;
-
-    pub(super) fn json_to_table(value: &Value, cfg: &Config) -> Table {
-        if cfg.plain {
-            json_to_table_f(value, cfg, true)
-        } else {
-            json_to_table_r(value, cfg, 0, 0, true, true, false, false, &[], None)
-        }
-    }
-
-    fn json_to_table_f(v: &Value, config: &Config, outer: bool) -> Table {
-        match v {
-            Value::Array(arr) => {
-                let mut builder = Builder::new();
-
-                match config.array_orientation {
-                    Orientation::Vertical => {
-                        for value in arr {
-                            let val = json_to_table_f(value, config, false).to_string();
-                            builder.push_record([val]);
-                        }
-                    }
-                    Orientation::Horizontal => {
-                        let mut row = Vec::with_capacity(arr.len());
-                        for value in arr {
-                            let val = json_to_table_f(value, config, false).to_string();
-                            row.push(val);
-                        }
-
-                        builder.hint_column_size(row.len());
-                        builder.push_record(row);
-                    }
-                }
-
-                set_table_style(builder.build(), config)
-            }
-            Value::Object(map) => {
-                let mut builder = Builder::new();
-
-                match config.object_orientation {
-                    Orientation::Vertical => {
-                        for (key, value) in map {
-                            let val = json_to_table_f(value, config, false).to_string();
-                            builder.push_record([key.clone(), val]);
-                        }
-                    }
-                    Orientation::Horizontal => {
-                        let mut keys = Vec::with_capacity(map.len());
-                        let mut vals = Vec::with_capacity(map.len());
-                        for (key, value) in map {
-                            let val = json_to_table_f(value, config, false).to_string();
-                            vals.push(val);
-                            keys.push(key.clone());
-                        }
-
-                        builder.hint_column_size(map.len());
-                        builder.push_record(keys);
-                        builder.push_record(vals);
-                    }
-                }
-
-                set_table_style(builder.build(), config)
-            }
-            value => {
-                let value = match value {
-                    Value::String(text) => Some(text.clone()),
-                    Value::Bool(val) => Some(val.to_string()),
-                    Value::Number(num) => Some(num.to_string()),
-                    Value::Null => None,
-                    _ => unreachable!(),
-                };
-
-                let mut builder = Builder::new();
-
-                if let Some(value) = value {
-                    builder.hint_column_size(1);
-                    builder.push_record([value]);
-                }
-
-                let mut table = set_table_style(builder.build(), config);
-
-                if !outer {
-                    table.with(Style::empty());
-                }
-
-                table
-            }
-        }
-    }
-
-    fn json_to_table_r(
-        value: &Value,
-        config: &Config,
-        row: usize,
-        column: usize,
-        is_last: bool,
-        is_prev_row_last: bool,
-        is_in_list: bool,
-        change_key_split: bool,
-        used_splits: &[usize],
-        width: Option<usize>,
-    ) -> Table {
-        let wpad = config
-            .cfg
-            .as_ref()
-            .map(|cfg| {
-                let pad = cfg.get_padding(Entity::Global);
-                pad.left.indent.size + pad.right.indent.size
-            })
-            .unwrap_or(2);
-
-        match value {
-            Value::String(..) | Value::Bool(..) | Value::Number(..) | Value::Null => {
-                let table = match value {
-                    Value::String(s) => col![s],
-                    Value::Bool(b) => col![b],
-                    Value::Number(n) => col![n],
-                    Value::Null => col![""],
-                    _ => unreachable!(),
-                };
-
-                let mut table = set_table_style(table, config);
-
-                let mut top_intersection = GetTopIntersection(' ');
-                table.with(&mut top_intersection);
-                let top_intersection = top_intersection.0;
-
-                table.with(
-                    Settings::default()
-                        .with(Width::increase(width.unwrap_or(0)))
-                        .with(SetBottomChars(used_splits, top_intersection)),
-                );
-
-                table
-            }
-            Value::Object(obj) => {
-                if obj.is_empty() {
-                    // a corner case where the object must behave as empty string
-
-                    return json_to_table_r(
-                        &Value::String(String::new()),
-                        config,
-                        row,
-                        column,
-                        is_last,
-                        is_prev_row_last,
-                        is_in_list,
-                        change_key_split,
-                        used_splits,
-                        width,
-                    );
-                }
-
-                let map_length = obj.len();
-                let max_keys_width = obj
-                    .iter()
-                    .map(|(key, _)| {
-                        set_table_style(col![key], config)
-                            .with(NoRightBorders)
-                            .total_width()
-                    })
-                    .max()
-                    .unwrap_or_default();
-
-                let width = match width {
-                    Some(width) => width,
-                    None => {
-                        // build dummy table
-                        let map = obj.iter().enumerate().map(|(i, (key, value))| {
-                            let is_last = is_last && i + 1 == map_length;
-
-                            let mut key = set_table_style(col![key], config);
-                            key.with(NoRightBorders);
-
-                            let value = json_to_table_r(
-                                value,
-                                config,
-                                row,
-                                column + 2,
-                                is_last,
-                                i + 1 == map_length,
-                                false,
-                                false,
-                                &[],
-                                None,
-                            );
-
-                            (key, value)
-                        });
-
-                        // need to rebuild the values with a known width
-                        let width = map
-                            .into_iter()
-                            .map(|(_, value)| value.total_width())
-                            .max()
-                            .unwrap_or_default();
-
-                        width + max_keys_width
-                    }
-                };
-
-                let mut builder = Builder::new();
-                let mut iter = obj.iter().enumerate().peekable();
-                while let Some((i, value)) = iter.next() {
-                    let row = row + i;
-                    let (key, value) = value;
-
-                    let mut was_intersection_touched = false;
-                    let intersections = if i + 1 < map_length {
-                        let (_, (_, value)) = iter.peek().unwrap();
-                        find_top_intersection(value, wpad)
-                    } else {
-                        let mut splits = used_splits.to_owned();
-                        if !splits.is_empty() {
-                            let mut current_width = 0;
-                            while !splits.is_empty() {
-                                current_width += splits[0];
-                                if current_width >= max_keys_width {
-                                    splits[0] = current_width - max_keys_width;
-                                    break;
-                                }
-
-                                splits.remove(0);
-                                current_width += 1;
-
-                                // means we must change a split char
-                                if current_width == max_keys_width {
-                                    was_intersection_touched = true;
-                                    break;
-                                }
-                            }
-                        }
-
-                        splits
-                    };
-
-                    let is_last = is_last && i + 1 == map_length;
-                    let width = width - max_keys_width;
-
-                    let mut value = json_to_table_r(
-                        value,
-                        config,
-                        row,
-                        column + 2,
-                        is_last,
-                        i + 1 == map_length,
-                        false,
-                        was_intersection_touched,
-                        &intersections,
-                        Some(width),
-                    );
-
-                    {
-                        value.with(TopLeftChangeSplit);
-
-                        if row != 0 {
-                            value.with(NoTopBorders);
-                        }
-
-                        if !is_last {
-                            value.with(BottomRightChangeToRight);
-                        }
-
-                        if i + 1 == map_length {
-                            value.with(BottomLeftChangeToBottomIntersection);
-                        } else {
-                            value.with(BottomLeftChangeSplitToIntersection);
-                        }
-
-                        if was_intersection_touched {
-                            value.with(BottomLeftChangeSplitToIntersection);
-                        }
-                    }
-
-                    let key = col![key];
-                    let mut key = set_table_style(key, config);
-
-                    let mut top_intersection = GetTopIntersection(' ');
-                    key.with(&mut top_intersection);
-                    let top_intersection = top_intersection.0;
-
-                    {
-                        key.with(NoRightBorders);
-
-                        if row != 0 {
-                            key.with(NoTopBorders);
-                        }
-
-                        if row == 0 && column != 0 {
-                            key.with(TopLeftChangeSplit);
-                        }
-
-                        if column > 0 {
-                            if i + 1 == map_length {
-                                if is_in_list {
-                                    if is_last {
-                                        key.with(BottomLeftChangeToBottomIntersection);
-                                    } else if is_prev_row_last {
-                                        key.with(BottomLeftChangeSplitToIntersection);
-                                    } else {
-                                        key.with(BottomLeftChangeSplit);
-                                    }
-                                } else if is_prev_row_last {
-                                    key.with(BottomLeftChangeToBottomIntersection);
-                                } else {
-                                    key.with(BottomLeftChangeSplitToIntersection);
-                                }
-                            } else {
-                                key.with(BottomLeftChangeSplit);
-                            }
-                        } else if !is_last {
-                            key.with(BottomLeftChangeSplit);
-                        }
-
-                        if change_key_split {
-                            key.with(BottomLeftChangeSplitToIntersection);
-                        }
-                    }
-
-                    let value_height = value.total_height();
-                    let key_height = key.total_height();
-                    let height = cmp::max(key_height, value_height);
-
-                    value.with(Settings::new(
-                        Width::increase(width),
-                        Height::increase(height),
-                    ));
-
-                    {
-                        // set custom chars
-                        if i + 1 == map_length {
-                            // set for the key
-                            key.with(
-                                Settings::default()
-                                    .with(Width::increase(max_keys_width))
-                                    .with(Height::increase(height))
-                                    .with(SetBottomChars(used_splits, top_intersection)),
-                            );
-                        } else {
-                            key.with(Settings::new(
-                                Width::increase(max_keys_width),
-                                Height::increase(height),
-                            ));
-                        }
-                    }
-
-                    builder.push_record([key.to_string(), value.to_string()]);
-                }
-
-                let mut table = builder.build();
-                table.with(Style::empty()).with(Padding::zero());
-                table
-            }
-            Value::Array(list) => {
-                if list.is_empty() {
-                    // a corner case where the list must behave as empty string
-
-                    return json_to_table_r(
-                        &Value::String(String::new()),
-                        config,
-                        row,
-                        column,
-                        is_last,
-                        is_prev_row_last,
-                        is_in_list,
-                        change_key_split,
-                        used_splits,
-                        width,
-                    );
-                }
-
-                let width = match width {
-                    Some(width) => width,
-                    None => {
-                        // build a dummy tables
-                        let list = list.iter().enumerate().map(|(i, value)| {
-                            let is_last_element = i + 1 == list.len();
-                            let is_last = is_last && is_last_element;
-                            json_to_table_r(
-                                value,
-                                config,
-                                row,
-                                column,
-                                is_last,
-                                is_last_element,
-                                true,
-                                false,
-                                &[],
-                                None,
-                            )
-                        });
-
-                        // need to rebuild the values with a known width
-                        list.into_iter()
-                            .map(|value| value.total_width())
-                            .max()
-                            .unwrap_or_default()
-                    }
-                };
-                let map_length = list.len();
-                let mut builder = Builder::new();
-                for (i, value) in list.iter().enumerate() {
-                    let row = row + i;
-
-                    let intersections = if i + 1 < map_length {
-                        let value = &list[i + 1];
-                        find_top_intersection(value, wpad)
-                    } else {
-                        used_splits.to_owned()
-                    };
-
-                    let is_last = is_last && i + 1 == map_length;
-
-                    let mut is_last_in_list = i + 1 == list.len();
-                    if is_in_list {
-                        is_last_in_list = is_last_in_list && is_prev_row_last;
-                    }
-
-                    let mut value = json_to_table_r(
-                        value,
-                        config,
-                        row,
-                        column,
-                        is_last,
-                        is_last_in_list,
-                        true,
-                        false,
-                        &intersections,
-                        Some(width),
-                    );
-
-                    if column != 0 {
-                        value.with(TopLeftChangeSplit);
-                    }
-
-                    if row > 0 {
-                        value.with(NoTopBorders);
-                    }
-
-                    if !is_last {
-                        value.with(BottomRightChangeToRight);
-                    }
-
-                    if i + 1 < map_length {
-                        value.with(BottomLeftChangeSplit);
-                    }
-
-                    if i + 1 == map_length && !is_last {
-                        value.with(BottomLeftChangeSplitToIntersection);
-                    }
-
-                    if i + 1 == map_length && !is_last && is_prev_row_last {
-                        value.with(BottomLeftChangeToBottomIntersection);
-                    }
-
-                    if column == 0 && !is_last {
-                        value.with(BottomLeftChangeSplit);
-                    }
-
-                    if is_last && column != 0 {
-                        value.with(BottomLeftChangeToBottomIntersection);
-                    }
-
-                    value.with(Width::increase(width));
-
-                    builder.push_record([value.to_string()]);
-                }
-
-                let mut table = builder.build();
-                table.with(Style::empty()).with(Padding::zero());
-                table
-            }
-        }
-    }
-
-    fn find_top_intersection(table: &Value, padding: usize) -> Vec<usize> {
-        let mut intersections = Vec::new();
-        find_top_intersection_r(table, &mut intersections, padding);
-
-        intersections
-    }
-
-    fn find_top_intersection_r(table: &Value, chars: &mut Vec<usize>, padding: usize) {
-        match table {
-            Value::String(_) | Value::Bool(_) | Value::Number(_) | Value::Null => (),
-            Value::Object(m) => {
-                if m.is_empty() {
-                    return;
-                }
-
-                let mut max_keys_width = 0;
-                for (key, _) in m.iter() {
-                    let width = string_width_multiline(key) + padding;
-                    max_keys_width = cmp::max(max_keys_width, width);
-                }
-
-                chars.push(max_keys_width);
-
-                let (_, value) = m.iter().next().unwrap();
-                find_top_intersection_r(value, chars, padding);
-            }
-            Value::Array(list) => {
-                if let Some(value) = list.first() {
-                    find_top_intersection_r(value, chars, padding);
-                }
-            }
-        }
-    }
-
-    fn set_table_style(mut table: Table, config: &Config) -> Table {
-        if let Some(cfg) = config.cfg.as_ref() {
-            table.with(Format::config(|c: &mut ColoredConfig| *c = cfg.clone()));
-        }
-
-        if let Some(style) = config.style.as_ref() {
-            table.with(style);
-        }
-
-        table
-    }
-
-    struct NoTopBorders;
-
-    impl<R, D> TableOption<R, D, ColoredConfig> for NoTopBorders {
-        fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
-            let mut borders = *cfg.get_borders();
-            borders.top = None;
-            borders.top_intersection = None;
-            borders.top_left = None;
-            borders.top_right = None;
-
-            cfg.set_borders(borders);
-        }
-    }
-
-    struct NoBottomBorders;
-
-    impl<R, D> TableOption<R, D, ColoredConfig> for NoBottomBorders {
-        fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
-            let mut borders = *cfg.get_borders();
-            borders.bottom = None;
-            borders.bottom_intersection = None;
-            borders.bottom_left = None;
-            borders.bottom_right = None;
-
-            cfg.set_borders(borders);
-        }
-    }
-
-    struct NoRightBorders;
-
-    impl<R, D> TableOption<R, D, ColoredConfig> for NoRightBorders {
-        fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
-            let mut borders = *cfg.get_borders();
-            borders.top_right = None;
-            borders.bottom_right = None;
-            borders.right = None;
-            borders.right_intersection = None;
-
-            cfg.set_borders(borders);
-        }
-    }
-
-    struct NoLeftBorders;
-
-    impl<R, D> TableOption<R, D, ColoredConfig> for NoLeftBorders {
-        fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
-            let mut borders = *cfg.get_borders();
-            borders.top_left = None;
-            borders.bottom_left = None;
-            borders.left = None;
-            borders.left_intersection = None;
-
-            cfg.set_borders(borders);
-        }
-    }
-
-    struct TopLeftChangeSplit;
-
-    impl<R, D> TableOption<R, D, ColoredConfig> for TopLeftChangeSplit {
-        fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
-            let mut borders = *cfg.get_borders();
-            borders.top_left = borders.top_intersection;
-
-            cfg.set_borders(borders);
-        }
-    }
-
-    struct BottomLeftChangeSplit;
-
-    impl<R, D> TableOption<R, D, ColoredConfig> for BottomLeftChangeSplit {
-        fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
-            let mut borders = *cfg.get_borders();
-            borders.bottom_left = borders.left_intersection;
-
-            cfg.set_borders(borders);
-        }
-    }
-
-    struct BottomLeftChangeSplitToIntersection;
-
-    impl<R, D> TableOption<R, D, ColoredConfig> for BottomLeftChangeSplitToIntersection {
-        fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
-            let mut borders = *cfg.get_borders();
-            borders.bottom_left = borders.intersection;
-
-            cfg.set_borders(borders);
-        }
-    }
-
-    struct BottomRightChangeToRight;
-
-    impl<R, D> TableOption<R, D, ColoredConfig> for BottomRightChangeToRight {
-        fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
-            let mut borders = *cfg.get_borders();
-            borders.bottom_right = borders.right_intersection;
-
-            cfg.set_borders(borders);
-        }
-    }
-
-    struct BottomLeftChangeToBottomIntersection;
-
-    impl<R, D> TableOption<R, D, ColoredConfig> for BottomLeftChangeToBottomIntersection {
-        fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
-            let mut borders = *cfg.get_borders();
-            borders.bottom_left = borders.bottom_intersection;
-
-            cfg.set_borders(borders);
-        }
-    }
-
-    struct SetBottomChars<'a>(&'a [usize], char);
-
-    impl<R, D> TableOption<R, D, ColoredConfig> for SetBottomChars<'_>
-    where
-        R: Records,
-        for<'a> &'a R: Records,
-        for<'a> D: Dimension + Estimate<&'a R, SpannedConfig>,
-    {
-        fn change(&mut self, records: &mut R, cfg: &mut ColoredConfig, dims: &mut D) {
-            dims.estimate(&*records, cfg);
-
-            let table_width = (0..records.count_columns())
-                .map(|col| dims.get_width(col))
-                .sum::<usize>()
-                + cfg.count_vertical(records.count_columns());
-            let mut current_width = 0;
-
-            for pos in self.0 {
-                current_width += pos;
-                if current_width > table_width {
-                    break;
-                }
-
-                let split_char = self.1;
-                cfg.set_horizontal_char((1, 0), split_char, Offset::Begin(current_width));
-
-                current_width += 1;
-            }
-        }
-    }
-
-    struct GetTopIntersection(char);
-
-    impl<R, D> TableOption<R, D, ColoredConfig> for GetTopIntersection {
-        fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
-            self.0 = cfg.get_borders().top_intersection.unwrap_or(' ');
-        }
-    }
-
-    struct GetWidths(Vec<usize>);
-
-    impl<R, D> TableOption<R, D, ColoredConfig> for GetWidths
-    where
-        R: Records,
-        for<'a> &'a R: Records,
-        for<'a> D: Dimension + Estimate<&'a R, SpannedConfig>,
-    {
-        fn change(&mut self, records: &mut R, cfg: &mut ColoredConfig, dims: &mut D) {
-            dims.estimate(&*records, cfg);
-
-            self.0 = (0..records.count_columns())
-                .map(|col| dims.get_width(col))
-                .collect();
-        }
-    }
-}
diff --git a/json_to_table/src/table/collapsed_table.rs b/json_to_table/src/table/collapsed_table.rs
new file mode 100644
index 0000000..ea31cc3
--- /dev/null
+++ b/json_to_table/src/table/collapsed_table.rs
@@ -0,0 +1,1141 @@
+use std::{
+    cmp::{self, max},
+    collections::HashMap,
+    iter::repeat,
+};
+
+use serde_json::Map;
+use tabled::{
+    builder::Builder,
+    col,
+    grid::{
+        config::{AlignmentHorizontal, AlignmentVertical, ColoredConfig, Entity, Offset},
+        dimension::{Dimension, Estimate},
+        records::Records,
+        util::string::{count_lines, get_lines, string_dimension, string_width},
+    },
+    settings::{Padding, TableOption},
+};
+
+use super::*;
+
+#[derive(Debug, Default)]
+struct PrintContext {
+    pos: usize,
+    is_last_col: bool,
+    is_last_row: bool,
+    is_first_col: bool,
+    is_first_row: bool,
+    kv: bool,
+    kv_is_first: bool,
+    list: bool,
+    list_is_first: bool,
+    no_left: bool,
+    no_right: bool,
+    no_bottom: bool,
+    lean_top: bool,
+    top_intersection: bool,
+    top_left: bool,
+    intersections_horizontal: Vec<usize>,
+    intersections_vertical: Vec<usize>,
+    size: Dim,
+}
+
+struct CellData {
+    content: String,
+    intersections_horizontal: Vec<usize>,
+    intersections_vertical: Vec<usize>,
+}
+
+impl CellData {
+    fn new(content: String, i_horizontal: Vec<usize>, i_vertical: Vec<usize>) -> Self {
+        Self {
+            content,
+            intersections_horizontal: i_horizontal,
+            intersections_vertical: i_vertical,
+        }
+    }
+}
+
+pub(super) fn collapsed_table(value: &Value, cfg: &Config) -> String {
+    let dims = collect_table_dimensions(value, cfg);
+    let ctx = PrintContext {
+        is_last_col: true,
+        is_last_row: true,
+        is_first_col: true,
+        is_first_row: true,
+        size: *dims.all.get(&0).unwrap(),
+        ..Default::default()
+    };
+    _collapsed_table(value, cfg, &dims, ctx).content
+}
+
+fn _collapsed_table(val: &Value, cfg: &Config, dims: &Dimensions, ctx: PrintContext) -> CellData {
+    match val {
+        Value::String(..) | Value::Bool(..) | Value::Number(..) | Value::Null => {
+            let value = match val {
+                Value::String(val) => val.to_string(),
+                Value::Bool(val) => val.to_string(),
+                Value::Number(val) => val.to_string(),
+                Value::Null => String::new(),
+                _ => unreachable!(),
+            };
+
+            generate_value_cell(&value, cfg, ctx)
+        }
+        Value::Object(obj) => {
+            if obj.is_empty() {
+                // a corner case where the object must behave as empty string
+                return _collapsed_table(&Value::Null, cfg, dims, ctx);
+            }
+
+            match cfg.object_orientation {
+                Orientation::Vertical => generate_vertical_object(obj, cfg, dims, ctx),
+                Orientation::Horizontal => generate_horizontal_object(obj, cfg, dims, ctx),
+            }
+        }
+        Value::Array(list) => {
+            if list.is_empty() {
+                // a corner case where the list must behave as empty string
+                return _collapsed_table(&Value::Null, cfg, dims, ctx);
+            }
+
+            match cfg.array_orientation {
+                Orientation::Vertical => generate_vertical_array(list, cfg, dims, ctx),
+                Orientation::Horizontal => generate_horizontal_array(list, cfg, dims, ctx),
+            }
+        }
+    }
+}
+
+fn generate_vertical_array(
+    list: &Vec<Value>,
+    cfg: &Config,
+    dims: &Dimensions,
+    ctx: PrintContext,
+) -> CellData {
+    let array_dims = dims.arrays.get(&ctx.pos).unwrap();
+
+    let height = dims.all.get(&ctx.pos).unwrap().height;
+    let additional_height = ctx.size.height - height;
+    let (chunk_height, rest_height) = split_value(additional_height, list.len());
+
+    let mut intersections_horizontal = ctx.intersections_horizontal;
+    let mut intersections_vertical = ctx.intersections_vertical;
+    let mut next_vsplit = false;
+    let mut next_intersections_vertical = vec![];
+
+    let mut builder = Builder::new();
+    for (i, val) in list.iter().enumerate() {
+        let val_pos = *array_dims.index.get(&i).unwrap();
+
+        let mut height = dims.all.get(&val_pos).unwrap().height + chunk_height;
+        if i == 0 {
+            height += rest_height;
+        }
+        let size = Dim::new(ctx.size.width, height);
+
+        let (split, intersections_vertical) =
+            short_splits3(&mut intersections_vertical, size.height);
+        let old_split = next_vsplit;
+        next_vsplit = split;
+
+        let is_prev_list_not_first = ctx.list && !ctx.list_is_first;
+        let valctx = PrintContext {
+            pos: val_pos,
+            is_last_col: ctx.is_last_col,
+            is_last_row: ctx.is_last_row && i + 1 == list.len(),
+            is_first_col: ctx.is_first_col,
+            is_first_row: ctx.is_first_row && i == 0,
+            kv: ctx.kv,
+            kv_is_first: ctx.kv_is_first,
+            list: true,
+            list_is_first: i == 0 && !is_prev_list_not_first,
+            no_left: ctx.no_left,
+            no_right: ctx.no_right,
+            no_bottom: ctx.no_bottom && i + 1 == list.len(),
+            lean_top: ctx.lean_top && i == 0,
+            top_intersection: (ctx.top_intersection && i == 0) || old_split,
+            top_left: ctx.top_left || i > 0,
+            intersections_horizontal,
+            intersections_vertical,
+            size,
+        };
+
+        let data = _collapsed_table(val, cfg, dims, valctx);
+        intersections_horizontal = data.intersections_horizontal;
+        next_intersections_vertical.extend(data.intersections_vertical);
+
+        builder.push_record([data.content]);
+    }
+
+    let table = builder
+        .build()
+        .with(Style::empty())
+        .with(Padding::zero())
+        .to_string();
+
+    CellData::new(table, intersections_horizontal, next_intersections_vertical)
+}
+
+fn generate_horizontal_array(
+    list: &Vec<Value>,
+    cfg: &Config,
+    dims: &Dimensions,
+    ctx: PrintContext,
+) -> CellData {
+    let array_dims = dims.arrays.get(&ctx.pos).unwrap();
+
+    let list_width = dims.all.get(&ctx.pos).unwrap().width;
+    let additional_width = ctx.size.width - list_width;
+    let (chunk_width, rest_width) = split_value(additional_width, list.len());
+
+    let mut intersections_horizontal = ctx.intersections_horizontal;
+    let mut intersections_vertical = ctx.intersections_vertical;
+    let mut new_intersections_horizontal = vec![];
+    let mut split_next = false;
+
+    let mut buf = Vec::with_capacity(list.len());
+    for (i, val) in list.iter().enumerate() {
+        let val_pos = *array_dims.index.get(&i).unwrap();
+
+        let mut width = dims.all.get(&val_pos).unwrap().width + chunk_width;
+        if i == 0 {
+            width += rest_width;
+        }
+        let size = Dim::new(width, ctx.size.height);
+
+        let (split, intersections_horizontal) = short_splits3(&mut intersections_horizontal, width);
+        let old_split = split_next;
+        split_next = split;
+
+        let is_prev_list_not_first = ctx.list && !ctx.list_is_first;
+        let valctx = PrintContext {
+            pos: val_pos,
+            is_first_col: ctx.is_first_col && i == 0,
+            is_last_col: ctx.is_last_col && i + 1 == list.len(),
+            is_last_row: ctx.is_last_row,
+            is_first_row: ctx.is_first_row,
+            kv: false,
+            kv_is_first: false,
+            list: false,
+            list_is_first: !is_prev_list_not_first,
+            no_left: false,
+            no_right: !(ctx.is_last_col && i + 1 == list.len()),
+            no_bottom: false,
+            lean_top: !(ctx.is_first_col && i == 0),
+            top_intersection: (ctx.top_intersection && i == 0) || old_split,
+            top_left: ctx.top_left && i == 0,
+            intersections_horizontal,
+            intersections_vertical,
+            size,
+        };
+
+        let val = _collapsed_table(val, cfg, dims, valctx);
+
+        intersections_vertical = val.intersections_vertical;
+
+        new_intersections_horizontal.extend(val.intersections_horizontal.iter());
+        let value = val.content;
+
+        buf.push(value);
+    }
+
+    let mut b = Builder::with_capacity(1);
+    b.hint_column_size(buf.len());
+    b.push_record(buf);
+    let table = b
+        .build()
+        .with(Style::empty())
+        .with(Padding::zero())
+        .to_string();
+
+    CellData::new(table, new_intersections_horizontal, intersections_vertical)
+}
+
+fn generate_vertical_object(
+    obj: &Map<String, Value>,
+    cfg: &Config,
+    dims: &Dimensions,
+    ctx: PrintContext,
+) -> CellData {
+    let map_dims = dims.maps.get(&ctx.pos).unwrap();
+    let max_key_width = map_dims.key_max.width;
+
+    let has_vertical = cfg.cfg.get_borders().has_left();
+    let has_horizontal = cfg.cfg.get_borders().has_top();
+
+    let value_width = ctx.size.width - max_key_width - has_vertical as usize;
+
+    let mut intersections_horizontal = ctx.intersections_horizontal;
+    let mut intersections_vertical = ctx.intersections_vertical;
+    let mut next_vertical_intersections = vec![];
+
+    let (is_key_intersect, key_splits) =
+        short_splits3(&mut intersections_horizontal, max_key_width);
+
+    let mut builder = Builder::new();
+    for (i, (key, val)) in obj.iter().enumerate() {
+        let val_pos = *map_dims.index.get(&i).unwrap();
+        let key_pos = ctx.pos + i + 1;
+
+        let key_height = dims.all.get(&key_pos).unwrap().height;
+        let val_height = dims.all.get(&val_pos).unwrap().height;
+        let entry_height = cmp::max(key_height, val_height);
+
+        let is_last_row = ctx.is_last_row && i + 1 == obj.len();
+        let is_first_row = ctx.is_first_row && i == 0;
+
+        let valctx = PrintContext {
+            pos: val_pos,
+            is_first_row,
+            is_last_row,
+            is_first_col: false,
+            is_last_col: ctx.is_last_col,
+            kv: true,
+            kv_is_first: i == 0,
+            list: false,
+            list_is_first: false,
+            no_left: false,
+            no_right: !ctx.is_last_col,
+            no_bottom: false,
+            lean_top: i == 0,
+            top_intersection: i > 0 || (i == 0 && is_key_intersect),
+            top_left: false,
+            intersections_horizontal,
+            intersections_vertical: vec![],
+            size: Dim::new(value_width, entry_height),
+        };
+
+        let val = _collapsed_table(val, cfg, dims, valctx);
+        intersections_horizontal = val.intersections_horizontal;
+        next_vertical_intersections.extend(val.intersections_vertical);
+
+        let (_, key_vsplits) = short_splits3(&mut intersections_vertical, entry_height);
+
+        let key = config_string(key, &cfg.cfg, max_key_width, entry_height);
+
+        let mut key = col![key];
+        key.with(&cfg.cfg);
+        key.with(NoRightBorders);
+
+        if !is_last_row {
+            key.with(NoBottomBorders);
+        }
+
+        if !ctx.is_first_col && is_last_row {
+            key.with(BottomLeftChangeToBottomIntersection);
+        }
+
+        if !is_first_row {
+            key.with(TopLeftChangeToLeft);
+        }
+
+        if ctx.kv && !ctx.kv_is_first && i == 0 {
+            key.with(TopLeftChangeIntersection);
+        }
+
+        if ctx.kv && ctx.kv_is_first && i == 0 {
+            key.with(TopLeftChangeTopIntersection);
+        }
+
+        if ctx.list && !ctx.list_is_first {
+            key.with(TopLeftChangeToLeft);
+        }
+
+        if !ctx.is_first_col && is_first_row {
+            key.with(TopLeftChangeTopIntersection);
+        }
+
+        if i == 0 && ctx.lean_top {
+            key.with(TopLeftChangeTopIntersection);
+        }
+
+        if i == 0 && ctx.top_intersection {
+            key.with(TopLeftChangeIntersection);
+        }
+
+        if i == 0 && has_vertical && !key_splits.is_empty() {
+            let c = cfg.cfg.get_borders().bottom_intersection.unwrap_or(' ');
+            key.with(SetTopChars(&key_splits, c));
+        }
+
+        if has_horizontal && !key_vsplits.is_empty() {
+            let c = cfg.cfg.get_borders().right_intersection.unwrap_or(' ');
+            key.with(SetLeftChars(&key_vsplits, c));
+        }
+
+        builder.push_record([key.to_string(), val.content]);
+    }
+
+    intersections_horizontal.insert(0, max_key_width);
+
+    let table = builder
+        .build()
+        .with(Style::empty())
+        .with(Padding::zero())
+        .to_string();
+
+    CellData::new(table, intersections_horizontal, next_vertical_intersections)
+}
+
+fn generate_horizontal_object(
+    obj: &Map<String, Value>,
+    cfg: &Config,
+    dims: &Dimensions,
+    ctx: PrintContext,
+) -> CellData {
+    let map_dims = dims.maps.get(&ctx.pos).unwrap();
+
+    let key_height = map_dims.key_max.height;
+    let has_horizontal = cfg.cfg.get_borders().has_top();
+    let val_height = ctx.size.height - key_height - has_horizontal as usize;
+
+    let map_width = dims.all.get(&ctx.pos).unwrap().width;
+    let additional_width = ctx.size.width - map_width;
+    let (chunk_width, rest_width) = split_value(additional_width, obj.len());
+
+    let mut intersections_horizontal = ctx.intersections_horizontal;
+    let mut intersections_vertical = ctx.intersections_vertical;
+    let mut split_next = false;
+
+    let (vsplit, mut first_key_intersections_horizontal) =
+        short_splits3(&mut intersections_vertical, key_height);
+
+    let mut row1 = Vec::with_capacity(obj.len());
+    for (i, val) in obj.keys().enumerate() {
+        let key_pos = ctx.pos + i + 1;
+        let val_pos = *map_dims.index.get(&i).unwrap();
+
+        let val_width = dims.all.get(&val_pos).unwrap().width;
+        let key_width = dims.all.get(&key_pos).unwrap().width;
+
+        let mut width = max(val_width, key_width) + chunk_width;
+        if i == 0 {
+            width += rest_width;
+        }
+
+        let (split, intersections_horizontal) = short_splits3(&mut intersections_horizontal, width);
+        let old_split = split_next;
+        split_next = split;
+
+        let size = Dim::new(width, key_height);
+        let is_prev_list_not_first = ctx.list && !ctx.list_is_first;
+        let valctx = PrintContext {
+            pos: key_pos,
+            is_first_col: ctx.is_first_col && i == 0,
+            is_last_col: ctx.is_last_col && i + 1 == obj.len(),
+            is_last_row: false,
+            is_first_row: ctx.is_first_row,
+            kv: false,
+            kv_is_first: false,
+            list: false,
+            list_is_first: !is_prev_list_not_first,
+            no_left: false,
+            no_right: !(ctx.is_last_col && i + 1 == obj.len()),
+            no_bottom: true,
+            lean_top: !(ctx.is_first_col && i == 0),
+            top_intersection: (ctx.top_intersection && i == 0) || old_split,
+            top_left: ctx.top_left && i == 0,
+            intersections_horizontal,
+            intersections_vertical: first_key_intersections_horizontal,
+            size,
+        };
+
+        first_key_intersections_horizontal = vec![];
+
+        let val = generate_value_cell(val, cfg, valctx);
+        let value = val.content;
+
+        row1.push(value);
+    }
+
+    let mut next_intersections_horizontal = vec![];
+
+    let mut row2 = Vec::with_capacity(obj.len());
+    for (i, val) in obj.values().enumerate() {
+        let key_pos = ctx.pos + i + 1;
+        let val_pos = *map_dims.index.get(&i).unwrap();
+
+        let val_width = dims.all.get(&val_pos).unwrap().width;
+        let key_width = dims.all.get(&key_pos).unwrap().width;
+
+        let mut width = max(val_width, key_width) + chunk_width;
+        if i == 0 {
+            width += rest_width;
+        }
+
+        let size = Dim::new(width, val_height);
+        let is_prev_list_not_first = ctx.list && !ctx.list_is_first;
+        let valctx = PrintContext {
+            pos: val_pos,
+            is_first_col: ctx.is_first_col && i == 0,
+            is_last_col: ctx.is_last_col && i + 1 == obj.len(),
+            is_last_row: ctx.is_last_row,
+            is_first_row: false,
+            kv: true,
+            kv_is_first: false,
+            list: true,
+            list_is_first: !is_prev_list_not_first,
+            no_left: false,
+            no_right: !(ctx.is_last_col && i + 1 == obj.len()),
+            no_bottom: false,
+            lean_top: false,
+            top_intersection: i > 0 || (i == 0 && vsplit),
+            top_left: i == 0,
+            intersections_horizontal: vec![],
+            intersections_vertical,
+            size,
+        };
+
+        let val = _collapsed_table(val, cfg, dims, valctx);
+
+        intersections_vertical = val.intersections_vertical;
+        next_intersections_horizontal.extend(val.intersections_horizontal);
+
+        row2.push(val.content);
+    }
+
+    intersections_vertical.insert(0, key_height);
+
+    let mut b = Builder::with_capacity(2);
+    b.hint_column_size(obj.len());
+    b.push_record(row1);
+    b.push_record(row2);
+    let table = b
+        .build()
+        .with(Style::empty())
+        .with(Padding::zero())
+        .to_string();
+
+    CellData::new(table, next_intersections_horizontal, intersections_vertical)
+}
+
+fn generate_value_cell(value: &str, cfg: &Config, ctx: PrintContext) -> CellData {
+    let value = config_string(value, &cfg.cfg, ctx.size.width, ctx.size.height);
+
+    let mut table = col![value];
+    table.with(&cfg.cfg);
+
+    if !ctx.is_last_row || ctx.no_bottom {
+        table.with(NoBottomBorders);
+    }
+
+    if ctx.no_right {
+        table.with(NoRightBorders);
+    }
+
+    if ctx.kv && ctx.kv_is_first {
+        table.with(TopLeftChangeTopIntersection);
+    }
+
+    if ctx.kv && !ctx.kv_is_first {
+        table.with(TopLeftChangeIntersection);
+    }
+
+    if ctx.kv && ctx.list && !ctx.list_is_first {
+        table.with(TopLeftChangeToLeft);
+    }
+
+    if ctx.is_last_col && !ctx.is_first_row {
+        table.with(TopRightChangeToRight);
+    }
+
+    if !ctx.is_first_col && ctx.is_last_row {
+        table.with(BottomLeftChangeToBottomIntersection);
+    }
+
+    if ctx.is_first_col && !ctx.is_first_row {
+        table.with(TopLeftChangeToLeft);
+    }
+
+    if ctx.lean_top {
+        table.with(TopLeftChangeTopIntersection);
+    }
+
+    if ctx.top_left {
+        table.with(TopLeftChangeToLeft);
+    }
+
+    if ctx.top_intersection {
+        table.with(TopLeftChangeIntersection);
+    }
+
+    let has_vertical = cfg.cfg.get_borders().has_left();
+    if !ctx.intersections_horizontal.is_empty() && has_vertical {
+        let mut splits = ctx.intersections_horizontal;
+        let mut splits = short_splits(&mut splits, ctx.size.width);
+        squash_splits(&mut splits);
+
+        let c = cfg.cfg.get_borders().bottom_intersection.unwrap_or(' ');
+        table.with(SetTopChars(&splits, c));
+    }
+
+    let has_horizontal = cfg.cfg.get_borders().has_top();
+    if !ctx.intersections_vertical.is_empty() && has_horizontal {
+        let mut splits = ctx.intersections_vertical;
+        let mut splits = short_splits(&mut splits, ctx.size.width);
+        squash_splits(&mut splits);
+
+        let c = cfg.cfg.get_borders().right_intersection.unwrap_or(' ');
+        table.with(SetLeftChars(&splits, c));
+    }
+
+    let table = table.to_string();
+
+    CellData::new(table, vec![ctx.size.width], vec![ctx.size.height])
+}
+
+struct NoTopBorders;
+
+impl<R, D> TableOption<R, D, ColoredConfig> for NoTopBorders {
+    fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+        let mut borders = *cfg.get_borders();
+        borders.top = None;
+        borders.top_intersection = None;
+        borders.top_left = None;
+        borders.top_right = None;
+
+        cfg.set_borders(borders);
+    }
+}
+
+struct NoBottomBorders;
+
+impl<R, D> TableOption<R, D, ColoredConfig> for NoBottomBorders {
+    fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+        let mut borders = *cfg.get_borders();
+        borders.bottom = None;
+        borders.bottom_intersection = None;
+        borders.bottom_left = None;
+        borders.bottom_right = None;
+
+        cfg.set_borders(borders);
+    }
+}
+
+struct NoRightBorders;
+
+impl<R, D> TableOption<R, D, ColoredConfig> for NoRightBorders {
+    fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+        let mut borders = *cfg.get_borders();
+        borders.top_right = None;
+        borders.bottom_right = None;
+        borders.right = None;
+        borders.right_intersection = None;
+
+        cfg.set_borders(borders);
+    }
+}
+
+struct NoLeftBorders;
+
+impl<R, D> TableOption<R, D, ColoredConfig> for NoLeftBorders {
+    fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+        let mut borders = *cfg.get_borders();
+        borders.top_left = None;
+        borders.bottom_left = None;
+        borders.left = None;
+        borders.left_intersection = None;
+
+        cfg.set_borders(borders);
+    }
+}
+
+struct TopLeftChangeTopIntersection;
+
+impl<R, D> TableOption<R, D, ColoredConfig> for TopLeftChangeTopIntersection {
+    fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+        let mut borders = *cfg.get_borders();
+        borders.top_left = borders.top_intersection;
+
+        cfg.set_borders(borders);
+    }
+}
+
+struct TopLeftChangeIntersection;
+
+impl<R, D> TableOption<R, D, ColoredConfig> for TopLeftChangeIntersection {
+    fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+        let mut borders = *cfg.get_borders();
+        borders.top_left = borders.intersection;
+
+        cfg.set_borders(borders);
+    }
+}
+
+struct TopLeftChangeToLeft;
+
+impl<R, D> TableOption<R, D, ColoredConfig> for TopLeftChangeToLeft {
+    fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+        let mut borders = *cfg.get_borders();
+        borders.top_left = borders.left_intersection;
+
+        cfg.set_borders(borders);
+    }
+}
+
+struct TopRightChangeToRight;
+
+impl<R, D> TableOption<R, D, ColoredConfig> for TopRightChangeToRight {
+    fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+        let mut borders = *cfg.get_borders();
+        borders.top_right = borders.right_intersection;
+
+        cfg.set_borders(borders);
+    }
+}
+
+struct BottomLeftChangeSplit;
+
+impl<R, D> TableOption<R, D, ColoredConfig> for BottomLeftChangeSplit {
+    fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+        let mut borders = *cfg.get_borders();
+        borders.bottom_left = borders.left_intersection;
+
+        cfg.set_borders(borders);
+    }
+}
+
+struct BottomLeftChangeSplitToIntersection;
+
+impl<R, D> TableOption<R, D, ColoredConfig> for BottomLeftChangeSplitToIntersection {
+    fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+        let mut borders = *cfg.get_borders();
+        borders.bottom_left = borders.intersection;
+
+        cfg.set_borders(borders);
+    }
+}
+
+struct BottomRightChangeToRight;
+
+impl<R, D> TableOption<R, D, ColoredConfig> for BottomRightChangeToRight {
+    fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+        let mut borders = *cfg.get_borders();
+        borders.bottom_right = borders.right_intersection;
+
+        cfg.set_borders(borders);
+    }
+}
+
+struct BottomLeftChangeToBottomIntersection;
+
+impl<R, D> TableOption<R, D, ColoredConfig> for BottomLeftChangeToBottomIntersection {
+    fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+        let mut borders = *cfg.get_borders();
+        borders.bottom_left = borders.bottom_intersection;
+
+        cfg.set_borders(borders);
+    }
+}
+
+struct SetBottomChars<'a>(&'a [usize], char);
+
+impl<R, D> TableOption<R, D, ColoredConfig> for SetBottomChars<'_>
+where
+    R: Records,
+    for<'a> &'a R: Records,
+    for<'a> D: Dimension + Estimate<&'a R, SpannedConfig>,
+{
+    fn change(&mut self, records: &mut R, cfg: &mut ColoredConfig, dims: &mut D) {
+        dims.estimate(&*records, cfg);
+
+        let table_width = (0..records.count_columns())
+            .map(|col| dims.get_width(col))
+            .sum::<usize>()
+            + cfg.count_vertical(records.count_columns());
+        let mut current_width = 0;
+
+        for pos in self.0 {
+            current_width += pos;
+            if current_width > table_width {
+                break;
+            }
+
+            let split_char = self.1;
+            cfg.set_horizontal_char((1, 0), split_char, Offset::Begin(current_width));
+
+            current_width += 1;
+        }
+    }
+}
+
+struct SetTopChars<'a>(&'a [usize], char);
+
+impl<R, D> TableOption<R, D, ColoredConfig> for SetTopChars<'_> {
+    fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+        for &split in self.0 {
+            let offset = split;
+            cfg.set_horizontal_char((0, 0), self.1, Offset::Begin(offset));
+        }
+    }
+}
+
+struct SetLeftChars<'a>(&'a [usize], char);
+
+impl<R, D> TableOption<R, D, ColoredConfig> for SetLeftChars<'_> {
+    fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+        for &offset in self.0 {
+            cfg.set_vertical_char((0, 0), self.1, Offset::Begin(offset));
+        }
+    }
+}
+
+struct GetTopIntersection(char);
+
+impl<R, D> TableOption<R, D, ColoredConfig> for GetTopIntersection {
+    fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+        self.0 = cfg.get_borders().top_intersection.unwrap_or(' ');
+    }
+}
+
+struct GetBottomIntersection(char);
+
+impl<R, D> TableOption<R, D, ColoredConfig> for GetBottomIntersection {
+    fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+        self.0 = cfg.get_borders().bottom_intersection.unwrap_or(' ');
+    }
+}
+
+#[derive(Debug, Default)]
+struct Dimensions {
+    all: HashMap<usize, Dim>,
+    maps: HashMap<usize, MapDimensions>,
+    arrays: HashMap<usize, ArrayDimensions>,
+}
+
+#[derive(Debug, Default, Clone, Copy)]
+struct Dim {
+    width: usize,
+    height: usize,
+}
+
+impl Dim {
+    fn new(width: usize, height: usize) -> Self {
+        Self { width, height }
+    }
+}
+
+#[derive(Debug, Default)]
+struct MapDimensions {
+    key_max: Dim,
+    value_max: Dim,
+    index: HashMap<usize, usize>,
+}
+
+#[derive(Debug, Default)]
+struct ArrayDimensions {
+    max: Dim,
+    index: HashMap<usize, usize>,
+}
+
+fn collect_table_dimensions(val: &Value, cfg: &Config) -> Dimensions {
+    let mut buf = Dimensions::default();
+    let (dim, _) = __collect_table_dims(&mut buf, val, cfg, 0);
+    buf.all.insert(0, dim);
+    buf
+}
+
+fn __collect_table_dims(
+    buf: &mut Dimensions,
+    val: &Value,
+    cfg: &Config,
+    pos: usize,
+) -> (Dim, usize) {
+    match val {
+        Value::String(text) => (str_dimension(text, cfg), 0),
+        Value::Bool(b) => (bool_dimension(b, cfg), 0),
+        Value::Number(num) => (num_dimension(num, cfg), 0),
+        Value::Null => (empty_dimension(cfg), 0),
+        Value::Object(obj) => {
+            if obj.is_empty() {
+                return (empty_dimension(cfg), 0);
+            }
+
+            let mut index = MapDimensions {
+                index: HashMap::with_capacity(obj.len()),
+                key_max: Dim::default(),
+                value_max: Dim::default(),
+            };
+
+            let mut total_height = 0;
+            let mut total_width = 0;
+            let mut count_elements = obj.len() * 2;
+            let mut val_pos = pos + 1 + obj.len();
+            for (i, (key, val)) in obj.iter().enumerate() {
+                let key_pos = pos + i + 1;
+
+                let key = str_dimension(key, cfg);
+                let (val, elements) = __collect_table_dims(buf, val, cfg, val_pos);
+                count_elements += elements;
+
+                total_height += max(key.height, val.height);
+                total_width += max(key.width, val.width);
+
+                index.key_max.width = max(index.key_max.width, key.width);
+                index.key_max.height = max(index.key_max.height, key.height);
+                index.value_max.width = max(index.value_max.width, val.width);
+                index.value_max.height = max(index.value_max.height, val.height);
+
+                buf.all.insert(key_pos, key);
+                buf.all.insert(val_pos, val);
+
+                index.index.insert(i, val_pos);
+
+                val_pos += elements + 1;
+            }
+
+            let key_max = index.key_max;
+            let val_max = index.value_max;
+
+            buf.maps.insert(pos, index);
+
+            let has_vertical = cfg.cfg.get_borders().has_left();
+            let has_horizontal = cfg.cfg.get_borders().has_top();
+
+            match cfg.object_orientation {
+                Orientation::Vertical => {
+                    let total_width = key_max.width + val_max.width + has_vertical as usize;
+                    total_height += has_horizontal as usize * (obj.len() - 1);
+
+                    (Dim::new(total_width, total_height), count_elements)
+                }
+                Orientation::Horizontal => {
+                    let total_height = key_max.height + val_max.height + has_horizontal as usize;
+                    total_width += has_vertical as usize * (obj.len() - 1);
+
+                    (Dim::new(total_width, total_height), count_elements)
+                }
+            }
+        }
+        Value::Array(list) => {
+            if list.is_empty() {
+                return (empty_dimension(cfg), 0);
+            }
+
+            let mut index = ArrayDimensions {
+                max: Dim::default(),
+                index: HashMap::with_capacity(list.len()),
+            };
+
+            let mut total_height = 0;
+            let mut total_width = 0;
+
+            let mut count_elements = list.len();
+            let mut val_pos = pos + 1;
+            for (i, value) in list.iter().enumerate() {
+                let (dim, elements) = __collect_table_dims(buf, value, cfg, val_pos);
+                count_elements += elements;
+
+                total_height += dim.height;
+                total_width += dim.width;
+
+                index.max.width = max(index.max.width, dim.width);
+                index.max.height = max(index.max.height, dim.height);
+
+                buf.all.insert(val_pos, dim);
+
+                index.index.insert(i, val_pos);
+
+                val_pos += 1 + elements;
+            }
+
+            let max_width = index.max.width;
+            let max_height = index.max.height;
+
+            buf.arrays.insert(pos, index);
+
+            match cfg.array_orientation {
+                Orientation::Vertical => {
+                    let has_horizontal = cfg.cfg.get_borders().has_top();
+                    total_height += has_horizontal as usize * (list.len() - 1);
+
+                    (Dim::new(max_width, total_height), count_elements)
+                }
+                Orientation::Horizontal => {
+                    let has_vertical = cfg.cfg.get_borders().has_left();
+                    total_width += has_vertical as usize * (list.len() - 1);
+
+                    (Dim::new(total_width, max_height), count_elements)
+                }
+            }
+        }
+    }
+}
+
+fn bool_dimension(b: &bool, cfg: &Config) -> Dim {
+    let width = if *b { 4 } else { 5 };
+    Dim::new(
+        width + get_padding_horizontal(cfg),
+        1 + get_padding_vertical(cfg),
+    )
+}
+
+fn num_dimension(num: &serde_json::Number, cfg: &Config) -> Dim {
+    Dim::new(
+        num.to_string().len() + get_padding_horizontal(cfg),
+        1 + get_padding_vertical(cfg),
+    )
+}
+
+fn empty_dimension(cfg: &Config) -> Dim {
+    Dim::new(get_padding_horizontal(cfg), 1 + get_padding_vertical(cfg))
+}
+
+fn str_dimension(text: &str, cfg: &Config) -> Dim {
+    let (count_lines, width) = string_dimension(text);
+    let w = width + get_padding_horizontal(cfg);
+    let h = count_lines + get_padding_vertical(cfg);
+    Dim::new(w, h)
+}
+
+fn get_padding_horizontal(cfg: &Config) -> usize {
+    let pad = cfg.cfg.get_padding(Entity::Global);
+    pad.left.indent.size + pad.right.indent.size
+}
+
+fn get_padding_vertical(cfg: &Config) -> usize {
+    let pad = cfg.cfg.get_padding(Entity::Global);
+    pad.top.indent.size + pad.bottom.indent.size
+}
+
+fn split_value(value: usize, by: usize) -> (usize, usize) {
+    let val = value / by;
+    let rest = value - val * by;
+    (val, rest)
+}
+
+fn config_string(value: &str, cfg: &ColoredConfig, width: usize, height: usize) -> String {
+    let pad = cfg.get_padding(Entity::Global);
+    let width = width - pad.left.indent.size - pad.right.indent.size;
+    let height = height - pad.bottom.indent.size - pad.top.indent.size;
+    let ah = *cfg.get_alignment_horizontal(Entity::Global);
+    let av = *cfg.get_alignment_vertical(Entity::Global);
+    set_string_dimension(value, width, height, ah, av)
+}
+
+fn set_string_dimension(
+    text: &str,
+    width: usize,
+    height: usize,
+    ah: AlignmentHorizontal,
+    av: AlignmentVertical,
+) -> String {
+    let mut out = Vec::with_capacity(height);
+
+    let count_lines = count_lines(text);
+
+    let (top, bottom) = indent_vertical(av, height, count_lines);
+
+    out.extend(repeat(String::new()).take(top));
+
+    for line in get_lines(text) {
+        let w = string_width(&line);
+        let (left, right) = indent_horizontal(ah, width, w);
+
+        let mut buf = String::new();
+        buf.extend(repeat(' ').take(left));
+        buf.push_str(&line);
+        buf.extend(repeat(' ').take(right));
+
+        out.push(buf);
+    }
+
+    out.extend(repeat(String::new()).take(bottom));
+
+    out.join("\n")
+}
+
+fn indent_vertical(al: AlignmentVertical, available: usize, real: usize) -> (usize, usize) {
+    let top = indent_top(al, available, real);
+    let bottom = available - real - top;
+    (top, bottom)
+}
+
+fn indent_horizontal(al: AlignmentHorizontal, available: usize, real: usize) -> (usize, usize) {
+    let top = indent_left(al, available, real);
+    let right = available - real - top;
+    (top, right)
+}
+
+fn indent_top(al: AlignmentVertical, available: usize, real: usize) -> usize {
+    match al {
+        AlignmentVertical::Top => 0,
+        AlignmentVertical::Bottom => available - real,
+        AlignmentVertical::Center => (available - real) / 2,
+    }
+}
+
+fn indent_left(al: AlignmentHorizontal, available: usize, real: usize) -> usize {
+    match al {
+        AlignmentHorizontal::Left => 0,
+        AlignmentHorizontal::Right => available - real,
+        AlignmentHorizontal::Center => (available - real) / 2,
+    }
+}
+
+fn short_splits(splits: &mut Vec<usize>, width: usize) -> Vec<usize> {
+    if splits.is_empty() {
+        return Vec::new();
+    }
+
+    let mut out = Vec::new();
+    let mut pos = 0;
+    for &split in splits.iter() {
+        if pos + split >= width {
+            break;
+        }
+
+        pos += split;
+        out.push(pos);
+    }
+
+    splits.drain(..out.len());
+
+    if !splits.is_empty() && pos <= width {
+        let rest = width - pos;
+        splits[0] -= rest;
+    }
+
+    out
+}
+
+fn short_splits3(splits: &mut Vec<usize>, width: usize) -> (bool, Vec<usize>) {
+    if splits.is_empty() {
+        return (false, Vec::new());
+    }
+
+    let mut out = Vec::new();
+    let mut pos = 0;
+    for &split in splits.iter() {
+        if pos + split >= width {
+            break;
+        }
+
+        pos += split + 1;
+        out.push(split);
+    }
+
+    splits.drain(..out.len());
+
+    if splits.is_empty() {
+        return (false, out);
+    }
+
+    if pos <= width {
+        splits[0] -= width - pos;
+        if splits[0] > 0 {
+            splits[0] -= 1;
+        } else {
+            splits.remove(0);
+            return (true, out);
+        }
+    }
+
+    (false, out)
+}
+
+fn squash_splits(splits: &mut [usize]) {
+    splits.iter_mut().enumerate().for_each(|(i, s)| *s += i);
+}
diff --git a/json_to_table/src/table/mod.rs b/json_to_table/src/table/mod.rs
new file mode 100644
index 0000000..b2c0ac1
--- /dev/null
+++ b/json_to_table/src/table/mod.rs
@@ -0,0 +1,174 @@
+use core::fmt::{self, Display};
+use std::borrow::Borrow;
+
+use serde_json::Value;
+use tabled::{
+    grid::{
+        config::{AlignmentHorizontal, ColoredConfig, Entity, Indent, Sides, SpannedConfig},
+        dimension::CompleteDimension,
+        records::EmptyRecords,
+    },
+    settings::{style::Style, TableOption},
+    Table,
+};
+
+mod collapsed_table;
+mod plain_table;
+
+/// Converter of [`Value`] to a table,
+/// with a set of configurations.
+// todo: rename to ValueTable.
+#[derive(Debug, Clone)]
+pub struct JsonTable<T> {
+    value: T,
+    cfg: Config,
+}
+
+impl<T> JsonTable<T> {
+    /// Creates a new [`JsonTable`] object.
+    pub fn new(value: T) -> Self {
+        JsonTable {
+            value,
+            cfg: Config {
+                plain: true,
+                cfg: ColoredConfig::new(configure_grid(), Default::default()),
+                array_orientation: Orientation::Vertical,
+                object_orientation: Orientation::Vertical,
+            },
+        }
+    }
+
+    /// Collapse tables out instead of tables within tables.
+    pub fn collapse(&mut self) -> &mut Self {
+        self.cfg.plain = false;
+        self
+    }
+
+    /// Set a table mode for a [`serde_json::Value::Object`].
+    pub fn object_orientation(&mut self, mode: Orientation) -> &mut Self {
+        self.cfg.object_orientation = mode;
+        self
+    }
+
+    /// Set a table mode for a [`serde_json::Value::Array`].
+    pub fn array_orientation(&mut self, mode: Orientation) -> &mut Self {
+        self.cfg.array_orientation = mode;
+        self
+    }
+
+    /// Set a config which will be used.
+    ///
+    /// You can obtain a config from a [`Table`].
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use serde_json::json;
+    /// use json_to_table::json_to_table;
+    /// use tabled::{
+    ///     settings::{Alignment, Padding, Style},
+    ///     Table
+    /// };
+    ///
+    /// let value = json!({
+    ///     "key1": 123,
+    ///     "234": ["123", "234", "456"],
+    ///     "key22": {
+    ///         "k1": 1,
+    ///         "k2": 2,
+    ///     }
+    /// });
+    ///
+    /// let table = json_to_table(&value)
+    ///     .with(Padding::zero())
+    ///     .with(Alignment::right())
+    ///     .with(Style::extended())
+    ///     .collapse()
+    ///     .to_string();
+    ///
+    /// println!("{}", table);
+    ///
+    ///    assert_eq!(
+    ///        table,
+    ///        concat!(
+    ///             "╔═════╦════╗\n",  
+    ///             "║  234║ 123║\n",  
+    ///             "║     ╠════╣\n",  
+    ///             "║     ║ 234║\n",  
+    ///             "║     ╠════╣\n",  
+    ///             "║     ║ 456║\n",  
+    ///             "╠═════╬════╣\n",  
+    ///             "║ key1║ 123║\n",  
+    ///             "╠═════╬══╦═╣\n",  
+    ///             "║key22║k1║1║\n",  
+    ///             "║     ╠══╬═╣\n",  
+    ///             "║     ║k2║2║\n",  
+    ///             "╚═════╩══╩═╝",
+    ///        ),
+    ///    );
+    /// ```
+    ///
+    /// [`Table`]: tabled::Table
+    pub fn with<O>(&mut self, mut option: O) -> &mut Self
+    where
+        O: TableOption<EmptyRecords, CompleteDimension<'static>, ColoredConfig>,
+    {
+        let mut records = EmptyRecords::default();
+        let mut dims = CompleteDimension::default();
+        option.change(&mut records, &mut self.cfg.cfg, &mut dims);
+
+        self
+    }
+}
+
+impl<T> Display for JsonTable<T>
+where
+    T: Borrow<Value>,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let table = json_to_table(self.value.borrow(), &self.cfg);
+        table.fmt(f)
+    }
+}
+
+#[derive(Debug, Clone)]
+struct Config {
+    plain: bool,
+    cfg: ColoredConfig,
+    object_orientation: Orientation,
+    array_orientation: Orientation,
+}
+
+/// The structure represents a table mode for a given entity,
+/// either it will be rendered vertically or horizontally.
+#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord)]
+pub enum Orientation {
+    /// Vertical mode (from top to bottom).
+    Vertical,
+    /// Horizontal mode (from left to right).
+    Horizontal,
+}
+
+fn configure_grid() -> SpannedConfig {
+    let mut cfg = SpannedConfig::default();
+    cfg.set_padding(
+        Entity::Global,
+        Sides::new(
+            Indent::spaced(1),
+            Indent::spaced(1),
+            Indent::default(),
+            Indent::default(),
+        ),
+    );
+    cfg.set_alignment_horizontal(Entity::Global, AlignmentHorizontal::Left);
+    cfg.set_borders(*Style::ascii().get_borders());
+
+    cfg
+}
+
+fn json_to_table(value: &Value, cfg: &Config) -> String {
+    match cfg.plain {
+        true => plain_table::plain_table(value, cfg),
+        false => collapsed_table::collapsed_table(value, cfg),
+    }
+}
diff --git a/json_to_table/src/table/plain_table.rs b/json_to_table/src/table/plain_table.rs
new file mode 100644
index 0000000..19cd2d8
--- /dev/null
+++ b/json_to_table/src/table/plain_table.rs
@@ -0,0 +1,78 @@
+use std::iter::FromIterator;
+
+use tabled::builder::Builder;
+
+use super::*;
+
+pub(super) fn plain_table(v: &Value, cfg: &Config) -> String {
+    _plain_table(v, cfg, true)
+}
+
+fn _plain_table(v: &Value, cfg: &Config, outer: bool) -> String {
+    match v {
+        Value::Array(arr) => match cfg.array_orientation {
+            Orientation::Vertical => {
+                let mut buf = Builder::with_capacity(1);
+                buf.hint_column_size(1);
+                for value in arr {
+                    let val = _plain_table(value, cfg, false);
+                    buf.push_record([val]);
+                }
+
+                buf.build().with(&cfg.cfg).to_string()
+            }
+            Orientation::Horizontal => {
+                let mut buf = Vec::with_capacity(arr.len());
+                for value in arr {
+                    let val = _plain_table(value, cfg, false);
+                    buf.push(val);
+                }
+
+                Builder::from(vec![buf]).build().with(&cfg.cfg).to_string()
+            }
+        },
+        Value::Object(map) => match cfg.object_orientation {
+            Orientation::Vertical => {
+                let mut buf = Builder::with_capacity(map.len());
+                for (key, value) in map {
+                    let val = _plain_table(value, cfg, false);
+                    buf.push_record([key.clone(), val]);
+                }
+
+                buf.build().with(&cfg.cfg).to_string()
+            }
+            Orientation::Horizontal => {
+                let mut keys = Vec::with_capacity(map.len());
+                let mut vals = Vec::with_capacity(map.len());
+                for (key, value) in map {
+                    let val = _plain_table(value, cfg, false);
+                    vals.push(val);
+                    keys.push(key.clone());
+                }
+
+                Builder::from(vec![keys, vals])
+                    .build()
+                    .with(&cfg.cfg)
+                    .to_string()
+            }
+        },
+        Value::Null => String::new(),
+        value => {
+            let val = match value {
+                Value::String(text) => text.to_owned(),
+                Value::Bool(val) => val.to_string(),
+                Value::Number(num) => num.to_string(),
+                _ => unreachable!(),
+            };
+
+            let mut table = Table::from_iter([[val]]);
+            table.with(&cfg.cfg);
+
+            if !outer {
+                table.with(Style::empty());
+            }
+
+            table.to_string()
+        }
+    }
+}
diff --git a/papergrid/src/config/borders.rs b/papergrid/src/config/borders.rs
index 1e96d88..d242e1f 100644
--- a/papergrid/src/config/borders.rs
+++ b/papergrid/src/config/borders.rs
@@ -1,5 +1,5 @@
 /// Borders represents a Table frame with horizontal and vertical split lines.
-#[derive(Debug, Clone, Copy, Default)]
+#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Borders<T> {
     /// A top horizontal on the frame.
     pub top: Option<T>,
diff --git a/papergrid/src/config/compact/mod.rs b/papergrid/src/config/compact/mod.rs
index 7064321..099fa44 100644
--- a/papergrid/src/config/compact/mod.rs
+++ b/papergrid/src/config/compact/mod.rs
@@ -9,7 +9,7 @@ use crate::config::{AlignmentHorizontal, Borders, Indent, Line, Sides};
 /// This structure represents a settings of a grid.
 ///
 /// grid: crate::Grid.
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
 pub struct CompactConfig {
     borders: Borders<char>,
     horizontal_line1: Option<Line<char>>,
@@ -100,7 +100,7 @@ impl CompactConfig {
         &self.padding
     }
 
-    /// Set a horizontal alignment to a given cells.
+    /// Set a horizontal alignment.
     pub const fn set_alignment_horizontal(mut self, alignment: AlignmentHorizontal) -> Self {
         self.halignment = alignment;
         self
diff --git a/papergrid/src/config/indent.rs b/papergrid/src/config/indent.rs
index 2111006..4d98772 100644
--- a/papergrid/src/config/indent.rs
+++ b/papergrid/src/config/indent.rs
@@ -1,5 +1,5 @@
 /// Indent represent a filled space.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Indent {
     /// A fill character.
     pub fill: char,
diff --git a/papergrid/src/config/line.rs b/papergrid/src/config/line.rs
index 3a8f9c5..c3089e1 100644
--- a/papergrid/src/config/line.rs
+++ b/papergrid/src/config/line.rs
@@ -1,5 +1,5 @@
 /// A line data structure.
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord)]
 pub struct Line<T> {
     /// A horizontal/vertical character.
     pub main: T,
diff --git a/papergrid/src/config/sides.rs b/papergrid/src/config/sides.rs
index 9faebfb..7aa0fb4 100644
--- a/papergrid/src/config/sides.rs
+++ b/papergrid/src/config/sides.rs
@@ -1,5 +1,5 @@
 /// A structure which represents 4 box sides.
-#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
+#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Sides<T> {
     /// Top side.
     pub top: T,
diff --git a/papergrid/src/config/spanned/borders_config.rs b/papergrid/src/config/spanned/borders_config.rs
index f6c7f73..91c291c 100644
--- a/papergrid/src/config/spanned/borders_config.rs
+++ b/papergrid/src/config/spanned/borders_config.rs
@@ -2,7 +2,7 @@ use std::collections::{HashMap, HashSet};
 
 use crate::config::{Border, Borders, Position};
 
-#[derive(Debug, Clone, Default)]
+#[derive(Debug, Default, Clone, PartialEq, Eq)]
 pub(crate) struct BordersConfig<T> {
     global: Option<T>,
     borders: Borders<T>,
@@ -321,14 +321,14 @@ impl<T: std::fmt::Debug> BordersConfig<T> {
     }
 }
 
-#[derive(Debug, Clone, Default)]
+#[derive(Debug, Clone, Default, PartialEq, Eq)]
 pub(crate) struct BordersMap<T> {
     vertical: HashMap<Position, T>,
     horizontal: HashMap<Position, T>,
     intersection: HashMap<Position, T>,
 }
 
-#[derive(Debug, Clone, Default)]
+#[derive(Debug, Clone, Default, PartialEq, Eq)]
 pub(crate) struct BordersLayout {
     left: bool,
     right: bool,
@@ -341,7 +341,7 @@ pub(crate) struct BordersLayout {
 }
 
 /// A structure for a custom horizontal line.
-#[derive(Debug, Clone, Copy, Default)]
+#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord)]
 pub struct HorizontalLine<T> {
     /// Line character.
     pub main: Option<T>,
@@ -364,7 +364,7 @@ impl<T> HorizontalLine<T> {
 }
 
 /// A structure for a vertical line.
-#[derive(Debug, Clone, Copy, Default)]
+#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord)]
 pub struct VerticalLine<T> {
     /// Line character.
     pub main: Option<T>,
diff --git a/papergrid/src/config/spanned/entity_map.rs b/papergrid/src/config/spanned/entity_map.rs
index 8f37fcf..472ea5f 100644
--- a/papergrid/src/config/spanned/entity_map.rs
+++ b/papergrid/src/config/spanned/entity_map.rs
@@ -3,7 +3,7 @@ use fnv::FnvHashMap;
 use crate::config::{Entity, Position};
 
 /// A structure to keep information for [`Entity`] as a key.
-#[derive(Debug, Clone, Default)]
+#[derive(Debug, Default, Clone, PartialEq, Eq)]
 pub struct EntityMap<T> {
     // we have a global type to allocate in on stack.
     // because most of the time no changes are made to the [`EntityMap`].
diff --git a/papergrid/src/config/spanned/mod.rs b/papergrid/src/config/spanned/mod.rs
index d6609b2..ad338b2 100644
--- a/papergrid/src/config/spanned/mod.rs
+++ b/papergrid/src/config/spanned/mod.rs
@@ -21,7 +21,7 @@ pub use self::{entity_map::EntityMap, formatting::Formatting, offset::Offset};
 /// This structure represents a settings of a grid.
 ///
 /// grid: crate::Grid.
-#[derive(Debug, Clone)]
+#[derive(Debug, PartialEq, Eq, Clone)]
 pub struct SpannedConfig {
     margin: Sides<ColoredMarginIndent>,
     padding: EntityMap<Sides<ColoredIndent>>,
@@ -67,6 +67,10 @@ impl SpannedConfig {
     }
 
     /// Set a [`Margin`] value.
+    ///
+
+    // todo: change back to set_margin()
+
     pub fn get_margin_mut(&mut self) -> &mut Sides<ColoredMarginIndent> {
         &mut self.margin
     }
@@ -765,6 +769,8 @@ fn is_cell_covered_by_both_spans(cfg: &SpannedConfig, pos: Position) -> bool {
     })
 }
 
+// todo:: Get back to original PAdding + PaddingColor
+
 /// A colorefull indent.
 #[derive(Default, Debug, Clone, PartialEq, Eq)]
 pub struct ColoredIndent {
diff --git a/papergrid/src/records/vec_records/cell_info.rs b/papergrid/src/records/vec_records/cell_info.rs
index 826edcf..547d5e9 100644
--- a/papergrid/src/records/vec_records/cell_info.rs
+++ b/papergrid/src/records/vec_records/cell_info.rs
@@ -6,7 +6,7 @@ use crate::{
 };
 
 /// The struct is a [Cell] implementation which keeps width information pre allocated.
-#[derive(Debug, Default)]
+#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
 pub struct CellInfo<S> {
     text: S,
     width: usize,
@@ -109,7 +109,7 @@ where
     }
 }
 
-#[derive(Debug, Clone, Default)]
+#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Clone)]
 struct StrWithWidth<'a> {
     text: Cow<'a, str>,
     width: usize,
diff --git a/papergrid/src/records/vec_records/mod.rs b/papergrid/src/records/vec_records/mod.rs
index 6e90c0d..b4dcb1f 100644
--- a/papergrid/src/records/vec_records/mod.rs
+++ b/papergrid/src/records/vec_records/mod.rs
@@ -15,7 +15,7 @@ pub use cell::Cell;
 pub use cell_info::CellInfo;
 
 /// A [Records] implementation based on allocated buffers.
-#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
 pub struct VecRecords<T> {
     data: Vec<Vec<T>>,
     shape: (usize, usize),
diff --git a/tabled/src/grid/colored_config.rs b/tabled/src/grid/colored_config.rs
index ef79204..f59a5a4 100644
--- a/tabled/src/grid/colored_config.rs
+++ b/tabled/src/grid/colored_config.rs
@@ -7,7 +7,7 @@ use papergrid::{
 };
 
 /// A [`Table`] configuration.
-#[derive(Debug, Clone)]
+#[derive(Debug, Default, PartialEq, Eq, Clone)]
 pub struct ColoredConfig {
     config: SpannedConfig,
     colors: HashMap<Position, AnsiColor<'static>>,
diff --git a/tabled/src/grid/compact_multiline_config.rs b/tabled/src/grid/compact_multiline_config.rs
new file mode 100644
index 0000000..8aa316b
--- /dev/null
+++ b/tabled/src/grid/compact_multiline_config.rs
@@ -0,0 +1,142 @@
+use core::ops::{Deref, DerefMut};
+
+use papergrid::config::compact::CompactConfig;
+use papergrid::config::AlignmentVertical;
+
+/// A [`Table`] configuration.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+pub struct CompactMultilineConfig {
+    config: CompactConfig,
+    alignment_vertical: AlignmentVertical,
+}
+
+impl CompactMultilineConfig {
+    /// Create a new colored config.
+    pub fn new(config: CompactConfig) -> Self {
+        Self::from(config)
+    }
+
+    /// Set a horizontal alignment.
+    pub const fn set_alignment_vertical(mut self, alignment: AlignmentVertical) -> Self {
+        self.alignment_vertical = alignment;
+        self
+    }
+
+    /// Get a alignment horizontal.
+    pub const fn get_alignment_vertical(&self) -> AlignmentVertical {
+        self.alignment_vertical
+    }
+}
+
+impl From<CompactConfig> for CompactMultilineConfig {
+    fn from(config: CompactConfig) -> Self {
+        Self {
+            config,
+            alignment_vertical: AlignmentVertical::Top,
+        }
+    }
+}
+
+impl Deref for CompactMultilineConfig {
+    type Target = CompactConfig;
+
+    fn deref(&self) -> &Self::Target {
+        &self.config
+    }
+}
+
+impl DerefMut for CompactMultilineConfig {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.config
+    }
+}
+
+impl AsRef<CompactConfig> for CompactMultilineConfig {
+    fn as_ref(&self) -> &CompactConfig {
+        &self.config
+    }
+}
+
+#[cfg(feature = "std")]
+impl From<CompactMultilineConfig> for crate::grid::config::SpannedConfig {
+    fn from(compact: CompactMultilineConfig) -> Self {
+        use crate::grid::color::{AnsiColor, StaticColor};
+        use crate::grid::config::{Borders, Entity::Global, HorizontalLine, Indent, Offset, Sides};
+        use papergrid::config::spanned::{ColoredIndent, ColoredMarginIndent};
+
+        fn to_margin(
+            pad: &Sides<Indent>,
+            colors: Sides<StaticColor>,
+        ) -> Sides<ColoredMarginIndent> {
+            let colors = to_ansi_color(colors);
+            Sides::new(
+                ColoredMarginIndent::new(pad.left, Offset::Begin(0), Some(colors.left)),
+                ColoredMarginIndent::new(pad.right, Offset::Begin(0), Some(colors.right)),
+                ColoredMarginIndent::new(pad.top, Offset::Begin(0), Some(colors.top)),
+                ColoredMarginIndent::new(pad.bottom, Offset::Begin(0), Some(colors.bottom)),
+            )
+        }
+
+        fn to_padding(pad: &Sides<Indent>, colors: Sides<StaticColor>) -> Sides<ColoredIndent> {
+            let colors = to_ansi_color(colors);
+            Sides::new(
+                ColoredIndent::new(pad.left, Some(colors.left)),
+                ColoredIndent::new(pad.right, Some(colors.right)),
+                ColoredIndent::new(pad.top, Some(colors.top)),
+                ColoredIndent::new(pad.bottom, Some(colors.bottom)),
+            )
+        }
+
+        fn to_ansi_color(b: Sides<StaticColor>) -> Sides<AnsiColor<'static>> {
+            Sides::new(b.left.into(), b.right.into(), b.top.into(), b.bottom.into())
+        }
+
+        fn borders_static_color_to_ansi_color(
+            b: Borders<StaticColor>,
+        ) -> Borders<AnsiColor<'static>> {
+            Borders {
+                left: b.left.map(|c| c.into()),
+                right: b.right.map(|c| c.into()),
+                top: b.top.map(|c| c.into()),
+                bottom: b.bottom.map(|c| c.into()),
+                bottom_intersection: b.bottom_intersection.map(|c| c.into()),
+                bottom_left: b.bottom_left.map(|c| c.into()),
+                bottom_right: b.bottom_right.map(|c| c.into()),
+                horizontal: b.horizontal.map(|c| c.into()),
+                intersection: b.intersection.map(|c| c.into()),
+                left_intersection: b.left_intersection.map(|c| c.into()),
+                right_intersection: b.right_intersection.map(|c| c.into()),
+                top_intersection: b.top_intersection.map(|c| c.into()),
+                top_left: b.top_left.map(|c| c.into()),
+                top_right: b.top_right.map(|c| c.into()),
+                vertical: b.vertical.map(|c| c.into()),
+            }
+        }
+
+        let mut cfg = crate::grid::config::SpannedConfig::default();
+
+        let pad = to_padding(compact.get_padding(), compact.get_padding_color());
+        cfg.set_padding(Global, pad);
+        *cfg.get_margin_mut() = to_margin(compact.get_margin(), compact.get_margin_color());
+        cfg.set_alignment_horizontal(Global, compact.get_alignment_horizontal());
+        cfg.set_alignment_vertical(Global, compact.get_alignment_vertical());
+        cfg.set_borders(*compact.get_borders());
+        cfg.set_borders_color(borders_static_color_to_ansi_color(
+            *compact.get_borders_color(),
+        ));
+
+        if let Some(line) = compact.get_first_horizontal_line() {
+            cfg.insert_horizontal_line(
+                1,
+                HorizontalLine {
+                    intersection: line.intersection,
+                    left: line.connect1,
+                    right: line.connect2,
+                    main: Some(line.main),
+                },
+            );
+        }
+
+        cfg
+    }
+}
diff --git a/tabled/src/grid/dimension/complete_dimension.rs b/tabled/src/grid/dimension/complete_dimension.rs
index 6313d6d..3147cb2 100644
--- a/tabled/src/grid/dimension/complete_dimension.rs
+++ b/tabled/src/grid/dimension/complete_dimension.rs
@@ -9,7 +9,7 @@ use crate::grid::{
 /// CompleteDimension is a [`Dimension`] implementation for a [`Table`]
 ///
 /// [`Table`]: crate::Table
-#[derive(Debug, Default, Clone)]
+#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Clone)]
 pub struct CompleteDimension<'a> {
     width: Option<Cow<'a, [usize]>>,
     height: Option<Cow<'a, [usize]>>,
diff --git a/tabled/src/grid/mod.rs b/tabled/src/grid/mod.rs
index 0c2eefa..dca9a41 100644
--- a/tabled/src/grid/mod.rs
+++ b/tabled/src/grid/mod.rs
@@ -7,6 +7,8 @@
 #[cfg(feature = "std")]
 mod colored_config;
 
+mod compact_multiline_config;
+
 pub mod dimension;
 pub mod records;
 
@@ -32,6 +34,8 @@ pub mod config {
     #[cfg(feature = "std")]
     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
     pub use super::colored_config::ColoredConfig;
+
+    pub use super::compact_multiline_config::CompactMultilineConfig;
 }
 
 pub use papergrid::grid::compact::CompactGrid;
diff --git a/tabled/src/settings/alignment/mod.rs b/tabled/src/settings/alignment/mod.rs
index 72f4e81..f708920 100644
--- a/tabled/src/settings/alignment/mod.rs
+++ b/tabled/src/settings/alignment/mod.rs
@@ -51,9 +51,11 @@
 //! [`Table`]: crate::Table
 //! [`AlignmentStrategy`]: crate::settings::formatting::AlignmentStrategy
 
+use core::ops::DerefMut;
+
 use crate::{
     grid::config::CompactConfig,
-    grid::config::{AlignmentHorizontal, AlignmentVertical, Entity},
+    grid::config::{AlignmentHorizontal, AlignmentVertical, CompactMultilineConfig, Entity},
     settings::TableOption,
 };
 
@@ -177,3 +179,12 @@ impl<R, D> TableOption<R, D, CompactConfig> for Alignment {
         }
     }
 }
+
+impl<R, D> TableOption<R, D, CompactMultilineConfig> for Alignment {
+    fn change(&mut self, _: &mut R, cfg: &mut CompactMultilineConfig, _: &mut D) {
+        match self.inner {
+            Horizontal(a) => *cfg.deref_mut() = cfg.set_alignment_horizontal(a),
+            Vertical(a) => *cfg = cfg.set_alignment_vertical(a),
+        }
+    }
+}
diff --git a/tabled/src/settings/margin/mod.rs b/tabled/src/settings/margin/mod.rs
index c22cb6a..7e6820b 100644
--- a/tabled/src/settings/margin/mod.rs
+++ b/tabled/src/settings/margin/mod.rs
@@ -26,10 +26,12 @@
 //!
 //! [`Table`]: crate::Table
 
+use core::ops::DerefMut;
+
 use crate::{
     grid::{
         color::StaticColor,
-        config::CompactConfig,
+        config::{CompactConfig, CompactMultilineConfig},
         config::{Indent, Sides},
     },
     settings::TableOption,
@@ -129,3 +131,12 @@ where
         }
     }
 }
+
+impl<R, D, C> TableOption<R, D, CompactMultilineConfig> for Margin<C>
+where
+    C: Into<StaticColor> + Clone,
+{
+    fn change(&mut self, records: &mut R, cfg: &mut CompactMultilineConfig, dimension: &mut D) {
+        self.change(records, cfg.deref_mut(), dimension)
+    }
+}
diff --git a/tabled/src/settings/padding/mod.rs b/tabled/src/settings/padding/mod.rs
index 8c33547..4a9a217 100644
--- a/tabled/src/settings/padding/mod.rs
+++ b/tabled/src/settings/padding/mod.rs
@@ -35,10 +35,12 @@
 //!
 //! [`Table`]: crate::Table
 
+use core::ops::DerefMut;
+
 use crate::{
     grid::{
         color::StaticColor,
-        config::CompactConfig,
+        config::{CompactConfig, CompactMultilineConfig},
         config::{Entity, Indent, Sides},
     },
     settings::TableOption,
@@ -147,6 +149,15 @@ where
     }
 }
 
+impl<R, D, C> TableOption<R, D, CompactMultilineConfig> for Padding<C>
+where
+    C: Into<StaticColor> + Clone,
+{
+    fn change(&mut self, records: &mut R, cfg: &mut CompactMultilineConfig, dimension: &mut D) {
+        self.change(records, cfg.deref_mut(), dimension)
+    }
+}
+
 #[cfg(feature = "std")]
 fn create_padding<C: Into<AnsiColor<'static>> + Clone>(
     i: &Sides<Indent>,
diff --git a/tabled/src/settings/style/builder.rs b/tabled/src/settings/style/builder.rs
index 61e18ae..e454a05 100644
--- a/tabled/src/settings/style/builder.rs
+++ b/tabled/src/settings/style/builder.rs
@@ -1,9 +1,9 @@
 //! This module contains a compile time style builder [`Style`].
 
-use core::marker::PhantomData;
+use core::{marker::PhantomData, ops::DerefMut};
 
 use crate::{
-    grid::config::{Borders, CompactConfig},
+    grid::config::{Borders, CompactConfig, CompactMultilineConfig},
     settings::TableOption,
 };
 
@@ -1094,6 +1094,16 @@ where
     }
 }
 
+impl<T, B, L, R, H, V, HLines, VLines, I, D> TableOption<I, D, CompactMultilineConfig>
+    for Style<T, B, L, R, H, V, HLines, VLines>
+where
+    HLines: IntoIterator<Item = HorizontalLine> + Clone,
+{
+    fn change(&mut self, records: &mut I, cfg: &mut CompactMultilineConfig, dimension: &mut D) {
+        self.change(records, cfg.deref_mut(), dimension)
+    }
+}
+
 /// An iterator which limits [`Line`] influence on iterations over lines for in [`Style`].
 #[derive(Debug, Clone)]
 pub struct HorizontalLineIter<I> {
diff --git a/tabled/src/settings/style/horizontal_line.rs b/tabled/src/settings/style/horizontal_line.rs
index b329c07..af56dd9 100644
--- a/tabled/src/settings/style/horizontal_line.rs
+++ b/tabled/src/settings/style/horizontal_line.rs
@@ -1,4 +1,9 @@
-use crate::{grid::config::CompactConfig, settings::TableOption};
+use core::ops::DerefMut;
+
+use crate::{
+    grid::config::{CompactConfig, CompactMultilineConfig},
+    settings::TableOption,
+};
 
 #[cfg(feature = "std")]
 use crate::grid::config::{ColoredConfig, HorizontalLine as GridLine};
@@ -109,3 +114,9 @@ impl<R, D> TableOption<R, D, CompactConfig> for HorizontalLine {
         }
     }
 }
+
+impl<R, D> TableOption<R, D, CompactMultilineConfig> for HorizontalLine {
+    fn change(&mut self, records: &mut R, cfg: &mut CompactMultilineConfig, dimension: &mut D) {
+        self.change(records, cfg.deref_mut(), dimension)
+    }
+}
diff --git a/tabled/src/tables/compact.rs b/tabled/src/tables/compact.rs
index d41a17e..b3e1cf0 100644
--- a/tabled/src/tables/compact.rs
+++ b/tabled/src/tables/compact.rs
@@ -188,6 +188,12 @@ impl<I, D> CompactTable<I, D> {
     pub fn get_config(&self) -> &CompactConfig {
         &self.cfg
     }
+
+    /// Returns a table config.
+    pub fn get_config_mut(&mut self) -> &mut CompactConfig {
+        &mut self.cfg
+    }
+
     /// Format table into [fmt::Write]er.
     pub fn fmt<W>(self, writer: W) -> fmt::Result
     where
diff --git a/tabled/src/tables/mod.rs b/tabled/src/tables/mod.rs
index 93ac453..7f4f03f 100644
--- a/tabled/src/tables/mod.rs
+++ b/tabled/src/tables/mod.rs
@@ -1,17 +1,21 @@
 //! Module contains a list of table representatives.
 //!
-//! ## [`table`]
+//! ## [`Table`]
 //!
 //! A default table implementation.
 //!
-//! ## [`iter`]
+//! ## [`IterTable`]
 //!
 //! Just like [`table`] but it's API is a bit different to serve better in context
 //! where there are a memory limits.
 //!
-//! ## [`extended`]
+//! ## [`ExtendedTable`]
 //!
-//! Has a table which is useful for large amount of data.
+//! It's a table which is useful for large amount of data.
+//!
+//! ## [`PoolTable`]
+//!
+//! A table with a greather controll of a layout.
 
 mod compact;
 mod util;
@@ -22,6 +26,8 @@ mod extended;
 mod iter;
 #[cfg(feature = "std")]
 mod table;
+#[cfg(feature = "std")]
+mod table_pool;
 
 #[cfg(feature = "std")]
 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
@@ -35,4 +41,8 @@ pub use iter::IterTable;
 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
 pub use extended::ExtendedTable;
 
+#[cfg(feature = "std")]
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+pub use table_pool::{PoolTable, TableValue};
+
 pub use compact::CompactTable;
diff --git a/tabled/src/tables/table.rs b/tabled/src/tables/table.rs
index 3b7fe93..2fef352 100644
--- a/tabled/src/tables/table.rs
+++ b/tabled/src/tables/table.rs
@@ -56,7 +56,7 @@ use papergrid::{
 /// [`Padding`]: crate::settings::Padding
 /// [`Style`]: crate::settings::Style
 /// [`Style::ascii`]: crate::settings::Style::ascii
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
 pub struct Table {
     records: VecRecords<CellInfo<String>>,
     config: ColoredConfig,
@@ -244,6 +244,21 @@ impl Table {
     pub fn get_config(&self) -> &ColoredConfig {
         &self.config
     }
+
+    /// Returns a table config.
+    pub fn get_config_mut(&mut self) -> &mut ColoredConfig {
+        &mut self.config
+    }
+}
+
+impl Default for Table {
+    fn default() -> Self {
+        Self {
+            records: VecRecords::default(),
+            config: ColoredConfig::new(configure_grid(), HashMap::default()),
+            dimension: CompleteDimension::default(),
+        }
+    }
 }
 
 impl fmt::Display for Table {
@@ -298,12 +313,36 @@ impl<R, D> TableOption<R, D, ColoredConfig> for CompactConfig {
     }
 }
 
+impl<R, D> TableOption<R, D, ColoredConfig> for &CompactConfig {
+    fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+        *cfg.deref_mut() = (**self).into();
+    }
+}
+
 impl<R, D> TableOption<R, D, ColoredConfig> for ColoredConfig {
     fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
         *cfg = self.clone();
     }
 }
 
+impl<R, D> TableOption<R, D, ColoredConfig> for &ColoredConfig {
+    fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+        *cfg = self.clone();
+    }
+}
+
+impl<R, D> TableOption<R, D, ColoredConfig> for SpannedConfig {
+    fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+        *cfg.deref_mut() = self.clone();
+    }
+}
+
+impl<R, D> TableOption<R, D, ColoredConfig> for &SpannedConfig {
+    fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+        *cfg.deref_mut() = self.clone();
+    }
+}
+
 fn convert_fmt_alignment(alignment: fmt::Alignment) -> AlignmentHorizontal {
     match alignment {
         fmt::Alignment::Left => AlignmentHorizontal::Left,
diff --git a/tabled/src/tables/table_pool.rs b/tabled/src/tables/table_pool.rs
new file mode 100644
index 0000000..d3d7777
--- /dev/null
+++ b/tabled/src/tables/table_pool.rs
@@ -0,0 +1,1091 @@
+use papergrid::{
+    config::{compact::CompactConfig, AlignmentHorizontal, Indent, Sides},
+    records::IntoRecords,
+};
+
+use crate::{
+    grid::{config::CompactMultilineConfig, dimension::CompleteDimension, records::EmptyRecords},
+    settings::{Style, TableOption},
+};
+
+/// [`PoolTable`] is a table which allows a greater set of possibilities for cell alignment.
+/// It's data is not aligned in any way by default.
+///
+/// It works similar to the main [`Table`] by default.
+///
+///
+/// ```
+/// use tabled::tables::PoolTable;
+///
+/// let data = vec![
+///     vec!["Hello", "World", "!"],
+///     vec!["Salve", "mondo", "!"],
+///     vec!["Hola", "mundo", "!"],
+/// ];
+///
+/// let table = PoolTable::new(data).to_string();
+///
+/// assert_eq!(
+///     table,
+///     "+-------+-------+---+\n\
+///      | Hello | World | ! |\n\
+///      +-------+-------+---+\n\
+///      | Salve | mondo | ! |\n\
+///      +-------+-------+---+\n\
+///      | Hola  | mundo | ! |\n\
+///      +-------+-------+---+"
+/// )
+/// ```
+///
+/// But it allows you to have a different number of columns inside the rows.
+///
+/// ```
+/// use tabled::tables::PoolTable;
+///
+/// let data = vec![
+///     vec!["Hello", "World", "!"],
+///     vec!["Salve, mondo!"],
+///     vec!["Hola", "mundo", "", "", "!"],
+/// ];
+///
+/// let table = PoolTable::new(data).to_string();
+///
+/// assert_eq!(
+///     table,
+///     "+----------+--------+----+\n\
+///      | Hello    | World  | !  |\n\
+///      +----------+--------+----+\n\
+///      | Salve, mondo!          |\n\
+///      +------+-------+--+--+---+\n\
+///      | Hola | mundo |  |  | ! |\n\
+///      +------+-------+--+--+---+"
+/// )
+/// ```
+///
+/// Notice that you also can build a custom table layout by using [`TableValue`].
+///
+/// ```
+/// use tabled::tables::{PoolTable, TableValue};
+///
+/// let message = "Hello\nWorld";
+///
+/// let data = TableValue::Column(vec![
+///     TableValue::Row(vec![
+///         TableValue::Column(vec![
+///             TableValue::Cell(String::from(message)),
+///         ]),
+///         TableValue::Column(vec![
+///             TableValue::Cell(String::from(message)),
+///             TableValue::Row(vec![
+///                 TableValue::Cell(String::from(message)),
+///                 TableValue::Cell(String::from(message)),
+///                 TableValue::Cell(String::from(message)),
+///             ])
+///         ]),
+///     ]),
+///     TableValue::Cell(String::from(message)),
+/// ]);
+///
+/// let table = PoolTable::from(data).to_string();
+///
+/// assert_eq!(
+///     table,
+///     "+-------+-----------------------+\n\
+///      | Hello | Hello                 |\n\
+///      | World | World                 |\n\
+///      |       +-------+-------+-------+\n\
+///      |       | Hello | Hello | Hello |\n\
+///      |       | World | World | World |\n\
+///      +-------+-------+-------+-------+\n\
+///      | Hello                         |\n\
+///      | World                         |\n\
+///      +-------------------------------+"
+/// )
+/// ```
+///
+/// [`Table`]: crate::Table
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub struct PoolTable {
+    config: CompactMultilineConfig,
+    value: TableValue,
+}
+
+impl PoolTable {
+    /// Creates a [`PoolTable`] out from a record iterator.
+    pub fn new<I: IntoRecords>(iter: I) -> Self {
+        let value = TableValue::Column(
+            iter.iter_rows()
+                .into_iter()
+                .map(|row| {
+                    TableValue::Row(
+                        row.into_iter()
+                            .map(|cell| cell.as_ref().to_string())
+                            .map(TableValue::Cell)
+                            .collect(),
+                    )
+                })
+                .collect(),
+        );
+
+        Self {
+            config: configure_grid(),
+            value,
+        }
+    }
+
+    /// A is a generic function which applies options to the [`PoolTable`] configuration.
+    ///
+    /// Notice that it has a limited support of options.
+    ///
+    /// ```
+    /// use tabled::tables::PoolTable;
+    /// use tabled::settings::{Style, Padding};
+    ///
+    /// let data = vec![
+    ///     vec!["Hello", "World", "!"],
+    ///     vec!["Salve", "mondo", "!"],
+    ///     vec!["Hola", "mundo", "!"],
+    /// ];
+    ///
+    /// let table = PoolTable::new(data)
+    ///     .with(Style::extended())
+    ///     .with(Padding::zero())
+    ///     .to_string();
+    ///
+    /// assert_eq!(
+    ///     table,
+    ///     "╔═════╦═════╦═╗\n\
+    ///      ║Hello║World║!║\n\
+    ///      ╠═════╬═════╬═╣\n\
+    ///      ║Salve║mondo║!║\n\
+    ///      ╠═════╬═════╬═╣\n\
+    ///      ║Hola ║mundo║!║\n\
+    ///      ╚═════╩═════╩═╝"
+    /// )
+    /// ```
+    pub fn with<O>(&mut self, mut option: O) -> &mut Self
+    where
+        O: TableOption<EmptyRecords, CompleteDimension<'static>, CompactMultilineConfig>,
+    {
+        let mut records = EmptyRecords::default();
+        let mut dims = CompleteDimension::default();
+        option.change(&mut records, &mut self.config, &mut dims);
+
+        self
+    }
+}
+
+impl From<TableValue> for PoolTable {
+    fn from(value: TableValue) -> Self {
+        Self {
+            config: configure_grid(),
+            value,
+        }
+    }
+}
+
+impl std::fmt::Display for PoolTable {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        print::build_table(&self.value, &self.config).fmt(f)
+    }
+}
+
+/// [`TableValue`] a structure which is responsible for a [`PoolTable`] layout.
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub enum TableValue {
+    /// A horizontal row.
+    Row(Vec<TableValue>),
+    /// A vertical column.
+    Column(Vec<TableValue>),
+    /// A single cell.
+    Cell(String),
+}
+
+fn configure_grid() -> CompactMultilineConfig {
+    let default_padding = Sides::new(
+        Indent::spaced(1),
+        Indent::spaced(1),
+        Indent::default(),
+        Indent::default(),
+    );
+
+    CompactMultilineConfig::from(
+        CompactConfig::default()
+            .set_padding(default_padding)
+            .set_alignment_horizontal(AlignmentHorizontal::Left)
+            .set_borders(*Style::ascii().get_borders()),
+    )
+}
+
+mod print {
+    use std::{cmp::max, collections::HashMap, iter::repeat};
+
+    use papergrid::config::{spanned::SpannedConfig, Borders};
+
+    use crate::{
+        builder::Builder,
+        grid::{
+            config::{
+                AlignmentHorizontal, AlignmentVertical, ColoredConfig, CompactMultilineConfig,
+                Offset,
+            },
+            dimension::{Dimension, Estimate},
+            records::Records,
+            util::string::{count_lines, get_lines, string_dimension, string_width},
+        },
+        settings::{Padding, Style, TableOption},
+        Table,
+    };
+
+    use super::TableValue;
+
+    #[derive(Debug, Default)]
+    struct PrintContext {
+        pos: usize,
+        is_last_col: bool,
+        is_last_row: bool,
+        is_first_col: bool,
+        is_first_row: bool,
+        kv: bool,
+        kv_is_first: bool,
+        list: bool,
+        list_is_first: bool,
+        no_left: bool,
+        no_right: bool,
+        no_bottom: bool,
+        lean_top: bool,
+        top_intersection: bool,
+        top_left: bool,
+        intersections_horizontal: Vec<usize>,
+        intersections_vertical: Vec<usize>,
+        size: Dim,
+    }
+
+    struct CellData {
+        content: String,
+        intersections_horizontal: Vec<usize>,
+        intersections_vertical: Vec<usize>,
+    }
+
+    impl CellData {
+        fn new(content: String, i_horizontal: Vec<usize>, i_vertical: Vec<usize>) -> Self {
+            Self {
+                content,
+                intersections_horizontal: i_horizontal,
+                intersections_vertical: i_vertical,
+            }
+        }
+    }
+
+    pub(super) fn build_table(val: &TableValue, cfg: &CompactMultilineConfig) -> String {
+        let dims = collect_table_dimensions(val, cfg);
+        let ctx = PrintContext {
+            is_last_col: true,
+            is_last_row: true,
+            is_first_col: true,
+            is_first_row: true,
+            size: *dims.all.get(&0).unwrap(),
+            ..Default::default()
+        };
+
+        let data = _build_table(val, cfg, &dims, ctx);
+
+        data.content
+    }
+
+    fn _build_table(
+        val: &TableValue,
+        cfg: &CompactMultilineConfig,
+        dims: &Dimensions,
+        ctx: PrintContext,
+    ) -> CellData {
+        match val {
+            TableValue::Cell(text) => generate_value_cell(text, cfg, ctx),
+            TableValue::Row(list) => {
+                if list.is_empty() {
+                    return generate_value_cell("", cfg, ctx);
+                }
+
+                generate_table_row(list, cfg, dims, ctx)
+            }
+            TableValue::Column(list) => {
+                if list.is_empty() {
+                    return generate_value_cell("", cfg, ctx);
+                }
+
+                generate_table_column(list, cfg, dims, ctx)
+            }
+        }
+    }
+
+    fn generate_table_column(
+        list: &Vec<TableValue>,
+        cfg: &CompactMultilineConfig,
+        dims: &Dimensions,
+        ctx: PrintContext,
+    ) -> CellData {
+        let array_dims = dims.arrays.get(&ctx.pos).unwrap();
+
+        let height = dims.all.get(&ctx.pos).unwrap().height;
+        let additional_height = ctx.size.height - height;
+        let (chunk_height, rest_height) = split_value(additional_height, list.len());
+
+        let mut intersections_horizontal = ctx.intersections_horizontal;
+        let mut intersections_vertical = ctx.intersections_vertical;
+        let mut next_vsplit = false;
+        let mut next_intersections_vertical = vec![];
+
+        let mut builder = Builder::new();
+        for (i, val) in list.iter().enumerate() {
+            let val_pos = *array_dims.index.get(&i).unwrap();
+
+            let mut height = dims.all.get(&val_pos).unwrap().height + chunk_height;
+            if i == 0 {
+                height += rest_height;
+            }
+            let size = Dim::new(ctx.size.width, height);
+
+            let (split, intersections_vertical) =
+                short_splits3(&mut intersections_vertical, size.height);
+            let old_split = next_vsplit;
+            next_vsplit = split;
+
+            let is_prev_list_not_first = ctx.list && !ctx.list_is_first;
+            let valctx = PrintContext {
+                pos: val_pos,
+                is_last_col: ctx.is_last_col,
+                is_last_row: ctx.is_last_row && i + 1 == list.len(),
+                is_first_col: ctx.is_first_col,
+                is_first_row: ctx.is_first_row && i == 0,
+                kv: ctx.kv,
+                kv_is_first: ctx.kv_is_first,
+                list: true,
+                list_is_first: i == 0 && !is_prev_list_not_first,
+                no_left: ctx.no_left,
+                no_right: ctx.no_right,
+                no_bottom: ctx.no_bottom && i + 1 == list.len(),
+                lean_top: ctx.lean_top && i == 0,
+                top_intersection: (ctx.top_intersection && i == 0) || old_split,
+                top_left: ctx.top_left || i > 0,
+                intersections_horizontal,
+                intersections_vertical,
+                size,
+            };
+
+            let data = _build_table(val, cfg, dims, valctx);
+            intersections_horizontal = data.intersections_horizontal;
+            next_intersections_vertical.extend(data.intersections_vertical);
+
+            builder.push_record([data.content]);
+        }
+
+        let table = builder
+            .build()
+            .with(Style::empty())
+            .with(Padding::zero())
+            .to_string();
+
+        CellData::new(table, intersections_horizontal, next_intersections_vertical)
+    }
+
+    fn generate_table_row(
+        list: &Vec<TableValue>,
+        cfg: &CompactMultilineConfig,
+        dims: &Dimensions,
+        ctx: PrintContext,
+    ) -> CellData {
+        let array_dims = dims.arrays.get(&ctx.pos).unwrap();
+
+        let list_width = dims.all.get(&ctx.pos).unwrap().width;
+        let additional_width = ctx.size.width - list_width;
+        let (chunk_width, rest_width) = split_value(additional_width, list.len());
+
+        let mut intersections_horizontal = ctx.intersections_horizontal;
+        let mut intersections_vertical = ctx.intersections_vertical;
+        let mut new_intersections_horizontal = vec![];
+        let mut split_next = false;
+
+        let mut buf = Vec::with_capacity(list.len());
+        for (i, val) in list.iter().enumerate() {
+            let val_pos = *array_dims.index.get(&i).unwrap();
+
+            let mut width = dims.all.get(&val_pos).unwrap().width + chunk_width;
+            if i == 0 {
+                width += rest_width;
+            }
+            let size = Dim::new(width, ctx.size.height);
+
+            let (split, intersections_horizontal) =
+                short_splits3(&mut intersections_horizontal, width);
+            let old_split = split_next;
+            split_next = split;
+
+            let is_prev_list_not_first = ctx.list && !ctx.list_is_first;
+            let valctx = PrintContext {
+                pos: val_pos,
+                is_first_col: ctx.is_first_col && i == 0,
+                is_last_col: ctx.is_last_col && i + 1 == list.len(),
+                is_last_row: ctx.is_last_row,
+                is_first_row: ctx.is_first_row,
+                kv: false,
+                kv_is_first: false,
+                list: false,
+                list_is_first: !is_prev_list_not_first,
+                no_left: false,
+                no_right: !(ctx.is_last_col && i + 1 == list.len()),
+                no_bottom: false,
+                lean_top: !(ctx.is_first_col && i == 0),
+                top_intersection: (ctx.top_intersection && i == 0) || old_split,
+                top_left: ctx.top_left && i == 0,
+                intersections_horizontal,
+                intersections_vertical,
+                size,
+            };
+
+            let val = _build_table(val, cfg, dims, valctx);
+
+            intersections_vertical = val.intersections_vertical;
+
+            new_intersections_horizontal.extend(val.intersections_horizontal.iter());
+            let value = val.content;
+
+            buf.push(value);
+        }
+
+        let mut b = Builder::with_capacity(1);
+        b.hint_column_size(buf.len());
+        b.push_record(buf);
+        let table = b
+            .build()
+            .with(Style::empty())
+            .with(Padding::zero())
+            .to_string();
+
+        CellData::new(table, new_intersections_horizontal, intersections_vertical)
+    }
+
+    fn generate_value_cell(
+        value: &str,
+        cfg: &CompactMultilineConfig,
+        ctx: PrintContext,
+    ) -> CellData {
+        let width = ctx.size.width;
+        let height = ctx.size.height;
+
+        let config: SpannedConfig = (*cfg).into();
+
+        let value = config_string(value, cfg, width, height);
+        let mut table = Table::new([value]);
+
+        let _ = table.with(config);
+        let _ = table.with(ConfigCell(ctx));
+
+        let table = table.to_string();
+
+        CellData::new(table, vec![width], vec![height])
+    }
+
+    struct ConfigCell(PrintContext);
+
+    impl<R, D> TableOption<R, D, ColoredConfig> for ConfigCell {
+        fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+            let ctx = &mut self.0;
+
+            {
+                let mut borders = *cfg.get_borders();
+
+                let has_vertical = cfg.get_borders().has_left();
+                if !ctx.intersections_horizontal.is_empty() && has_vertical {
+                    let mut splits =
+                        short_splits(&mut ctx.intersections_horizontal, ctx.size.width);
+                    squash_splits(&mut splits);
+
+                    let c = cfg.get_borders().bottom_intersection.unwrap_or(' ');
+                    cfg_set_top_chars(cfg, &splits, c)
+                }
+
+                let has_horizontal = cfg.get_borders().has_top();
+                if !ctx.intersections_vertical.is_empty() && has_horizontal {
+                    let mut splits = short_splits(&mut ctx.intersections_vertical, ctx.size.width);
+                    squash_splits(&mut splits);
+
+                    let c = cfg.get_borders().right_intersection.unwrap_or(' ');
+                    cfg_set_left_chars(cfg, &splits, c)
+                }
+
+                // set top_left
+                {
+                    if ctx.kv && ctx.kv_is_first {
+                        borders.top_left = borders.top_intersection;
+                    }
+
+                    if ctx.kv && !ctx.kv_is_first {
+                        borders.top_left = borders.intersection;
+                    }
+
+                    if ctx.kv && ctx.list && !ctx.list_is_first {
+                        borders.top_left = borders.left_intersection;
+                    }
+
+                    if ctx.is_first_col && !ctx.is_first_row {
+                        borders.top_left = borders.left_intersection;
+                    }
+
+                    if ctx.lean_top {
+                        borders.top_left = borders.top_intersection;
+                    }
+
+                    if ctx.top_left {
+                        borders.top_left = borders.left_intersection;
+                    }
+
+                    if ctx.top_intersection {
+                        borders.top_left = borders.intersection;
+                    }
+                }
+
+                if ctx.is_last_col && !ctx.is_first_row {
+                    borders.top_right = borders.right_intersection;
+                }
+
+                if !ctx.is_first_col && ctx.is_last_row {
+                    borders.bottom_left = borders.bottom_intersection;
+                }
+
+                if !ctx.is_last_row || ctx.no_bottom {
+                    cfg_no_bottom_borders(&mut borders);
+                }
+
+                if ctx.no_right {
+                    cfg_no_right_borders(&mut borders);
+                }
+
+                cfg.set_borders(borders);
+            }
+        }
+    }
+
+    fn cfg_no_bottom_borders(borders: &mut Borders<char>) {
+        borders.bottom = None;
+        borders.bottom_intersection = None;
+        borders.bottom_left = None;
+        borders.bottom_right = None;
+    }
+
+    fn cfg_no_right_borders(borders: &mut Borders<char>) {
+        borders.right = None;
+        borders.right_intersection = None;
+        borders.top_right = None;
+        borders.bottom_right = None;
+    }
+
+    fn cfg_set_top_chars(cfg: &mut ColoredConfig, list: &[usize], c: char) {
+        for &split in list {
+            let offset = split;
+            cfg.set_horizontal_char((0, 0), c, Offset::Begin(offset));
+        }
+    }
+
+    fn cfg_set_left_chars(cfg: &mut ColoredConfig, list: &[usize], c: char) {
+        for &offset in list {
+            cfg.set_vertical_char((0, 0), c, Offset::Begin(offset));
+        }
+    }
+
+    struct NoTopBorders;
+
+    impl<R, D> TableOption<R, D, ColoredConfig> for NoTopBorders {
+        fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+            let mut borders = *cfg.get_borders();
+            borders.top = None;
+            borders.top_intersection = None;
+            borders.top_left = None;
+            borders.top_right = None;
+
+            cfg.set_borders(borders);
+        }
+    }
+
+    struct NoBottomBorders;
+
+    impl<R, D> TableOption<R, D, ColoredConfig> for NoBottomBorders {
+        fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+            let mut borders = *cfg.get_borders();
+            borders.bottom = None;
+            borders.bottom_intersection = None;
+            borders.bottom_left = None;
+            borders.bottom_right = None;
+
+            cfg.set_borders(borders);
+        }
+    }
+
+    struct NoRightBorders;
+
+    impl<R, D> TableOption<R, D, ColoredConfig> for NoRightBorders {
+        fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+            let mut borders = *cfg.get_borders();
+            borders.top_right = None;
+            borders.bottom_right = None;
+            borders.right = None;
+            borders.right_intersection = None;
+
+            cfg.set_borders(borders);
+        }
+    }
+
+    struct NoLeftBorders;
+
+    impl<R, D> TableOption<R, D, ColoredConfig> for NoLeftBorders {
+        fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+            let mut borders = *cfg.get_borders();
+            borders.top_left = None;
+            borders.bottom_left = None;
+            borders.left = None;
+            borders.left_intersection = None;
+
+            cfg.set_borders(borders);
+        }
+    }
+
+    struct TopLeftChangeTopIntersection;
+
+    impl<R, D> TableOption<R, D, ColoredConfig> for TopLeftChangeTopIntersection {
+        fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+            let mut borders = *cfg.get_borders();
+            borders.top_left = borders.top_intersection;
+
+            cfg.set_borders(borders);
+        }
+    }
+
+    struct TopLeftChangeIntersection;
+
+    impl<R, D> TableOption<R, D, ColoredConfig> for TopLeftChangeIntersection {
+        fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+            let mut borders = *cfg.get_borders();
+            borders.top_left = borders.intersection;
+
+            cfg.set_borders(borders);
+        }
+    }
+
+    struct TopLeftChangeToLeft;
+
+    impl<R, D> TableOption<R, D, ColoredConfig> for TopLeftChangeToLeft {
+        fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+            let mut borders = *cfg.get_borders();
+            borders.top_left = borders.left_intersection;
+
+            cfg.set_borders(borders);
+        }
+    }
+
+    struct TopRightChangeToRight;
+
+    impl<R, D> TableOption<R, D, ColoredConfig> for TopRightChangeToRight {
+        fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+            let mut borders = *cfg.get_borders();
+            borders.top_right = borders.right_intersection;
+
+            cfg.set_borders(borders);
+        }
+    }
+
+    struct BottomLeftChangeSplit;
+
+    impl<R, D> TableOption<R, D, ColoredConfig> for BottomLeftChangeSplit {
+        fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+            let mut borders = *cfg.get_borders();
+            borders.bottom_left = borders.left_intersection;
+
+            cfg.set_borders(borders);
+        }
+    }
+
+    struct BottomLeftChangeSplitToIntersection;
+
+    impl<R, D> TableOption<R, D, ColoredConfig> for BottomLeftChangeSplitToIntersection {
+        fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+            let mut borders = *cfg.get_borders();
+            borders.bottom_left = borders.intersection;
+
+            cfg.set_borders(borders);
+        }
+    }
+
+    struct BottomRightChangeToRight;
+
+    impl<R, D> TableOption<R, D, ColoredConfig> for BottomRightChangeToRight {
+        fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+            let mut borders = *cfg.get_borders();
+            borders.bottom_right = borders.right_intersection;
+
+            cfg.set_borders(borders);
+        }
+    }
+
+    struct BottomLeftChangeToBottomIntersection;
+
+    impl<R, D> TableOption<R, D, ColoredConfig> for BottomLeftChangeToBottomIntersection {
+        fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+            let mut borders = *cfg.get_borders();
+            borders.bottom_left = borders.bottom_intersection;
+
+            cfg.set_borders(borders);
+        }
+    }
+
+    struct SetBottomChars<'a>(&'a [usize], char);
+
+    impl<R, D> TableOption<R, D, ColoredConfig> for SetBottomChars<'_>
+    where
+        R: Records,
+        for<'a> &'a R: Records,
+        for<'a> D: Dimension + Estimate<&'a R, ColoredConfig>,
+    {
+        fn change(&mut self, records: &mut R, cfg: &mut ColoredConfig, dims: &mut D) {
+            dims.estimate(&*records, cfg);
+
+            let table_width = (0..records.count_columns())
+                .map(|col| dims.get_width(col))
+                .sum::<usize>()
+                + cfg.count_vertical(records.count_columns());
+            let mut current_width = 0;
+
+            for pos in self.0 {
+                current_width += pos;
+                if current_width > table_width {
+                    break;
+                }
+
+                let split_char = self.1;
+                cfg.set_horizontal_char((1, 0), split_char, Offset::Begin(current_width));
+
+                current_width += 1;
+            }
+        }
+    }
+
+    struct SetTopChars<'a>(&'a [usize], char);
+
+    impl<R, D> TableOption<R, D, ColoredConfig> for SetTopChars<'_> {
+        fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+            for &split in self.0 {
+                let offset = split;
+                cfg.set_horizontal_char((0, 0), self.1, Offset::Begin(offset));
+            }
+        }
+    }
+
+    struct SetLeftChars<'a>(&'a [usize], char);
+
+    impl<R, D> TableOption<R, D, ColoredConfig> for SetLeftChars<'_> {
+        fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+            for &offset in self.0 {
+                cfg.set_vertical_char((0, 0), self.1, Offset::Begin(offset));
+            }
+        }
+    }
+
+    struct GetTopIntersection(char);
+
+    impl<R, D> TableOption<R, D, ColoredConfig> for GetTopIntersection {
+        fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+            self.0 = cfg.get_borders().top_intersection.unwrap_or(' ');
+        }
+    }
+
+    struct GetBottomIntersection(char);
+
+    impl<R, D> TableOption<R, D, ColoredConfig> for GetBottomIntersection {
+        fn change(&mut self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+            self.0 = cfg.get_borders().bottom_intersection.unwrap_or(' ');
+        }
+    }
+
+    #[derive(Debug, Default)]
+    struct Dimensions {
+        all: HashMap<usize, Dim>,
+        arrays: HashMap<usize, ArrayDimensions>,
+    }
+
+    #[derive(Debug, Default, Clone, Copy)]
+    struct Dim {
+        width: usize,
+        height: usize,
+    }
+
+    impl Dim {
+        fn new(width: usize, height: usize) -> Self {
+            Self { width, height }
+        }
+    }
+
+    #[derive(Debug, Default)]
+    struct ArrayDimensions {
+        max: Dim,
+        index: HashMap<usize, usize>,
+    }
+
+    fn collect_table_dimensions(val: &TableValue, cfg: &CompactMultilineConfig) -> Dimensions {
+        let mut buf = Dimensions::default();
+        let (dim, _) = __collect_table_dims(&mut buf, val, cfg, 0);
+        let _ = buf.all.insert(0, dim);
+        buf
+    }
+
+    fn __collect_table_dims(
+        buf: &mut Dimensions,
+        val: &TableValue,
+        cfg: &CompactMultilineConfig,
+        pos: usize,
+    ) -> (Dim, usize) {
+        match val {
+            TableValue::Cell(text) => (str_dimension(text, cfg), 0),
+            TableValue::Row(list) => {
+                if list.is_empty() {
+                    return (empty_dimension(cfg), 0);
+                }
+
+                let mut index = ArrayDimensions {
+                    max: Dim::default(),
+                    index: HashMap::with_capacity(list.len()),
+                };
+
+                let mut total_width = 0;
+
+                let mut count_elements = list.len();
+                let mut val_pos = pos + 1;
+                for (i, value) in list.iter().enumerate() {
+                    let (dim, elements) = __collect_table_dims(buf, value, cfg, val_pos);
+                    count_elements += elements;
+
+                    total_width += dim.width;
+
+                    index.max.width = max(index.max.width, dim.width);
+                    index.max.height = max(index.max.height, dim.height);
+
+                    let _ = buf.all.insert(val_pos, dim);
+
+                    let _ = index.index.insert(i, val_pos);
+
+                    val_pos += 1 + elements;
+                }
+
+                let max_height = index.max.height;
+
+                let _ = buf.arrays.insert(pos, index);
+
+                let has_vertical = cfg.get_borders().has_left();
+                total_width += has_vertical as usize * (list.len() - 1);
+
+                (Dim::new(total_width, max_height), count_elements)
+            }
+            TableValue::Column(list) => {
+                if list.is_empty() {
+                    return (empty_dimension(cfg), 0);
+                }
+
+                let mut index = ArrayDimensions {
+                    max: Dim::default(),
+                    index: HashMap::with_capacity(list.len()),
+                };
+
+                let mut total_height = 0;
+
+                let mut count_elements = list.len();
+                let mut val_pos = pos + 1;
+                for (i, value) in list.iter().enumerate() {
+                    let (dim, elements) = __collect_table_dims(buf, value, cfg, val_pos);
+                    count_elements += elements;
+
+                    total_height += dim.height;
+
+                    index.max.width = max(index.max.width, dim.width);
+                    index.max.height = max(index.max.height, dim.height);
+
+                    let _ = buf.all.insert(val_pos, dim);
+
+                    let _ = index.index.insert(i, val_pos);
+
+                    val_pos += 1 + elements;
+                }
+
+                let max_width = index.max.width;
+
+                let _ = buf.arrays.insert(pos, index);
+
+                let has_horizontal = cfg.get_borders().has_top();
+                total_height += has_horizontal as usize * (list.len() - 1);
+
+                (Dim::new(max_width, total_height), count_elements)
+            }
+        }
+    }
+
+    fn empty_dimension(cfg: &CompactMultilineConfig) -> Dim {
+        Dim::new(get_padding_horizontal(cfg), 1 + get_padding_vertical(cfg))
+    }
+
+    fn str_dimension(text: &str, cfg: &CompactMultilineConfig) -> Dim {
+        let (count_lines, width) = string_dimension(text);
+        let w = width + get_padding_horizontal(cfg);
+        let h = count_lines + get_padding_vertical(cfg);
+        Dim::new(w, h)
+    }
+
+    fn get_padding_horizontal(cfg: &CompactMultilineConfig) -> usize {
+        let pad = cfg.get_padding();
+        pad.left.size + pad.right.size
+    }
+
+    fn get_padding_vertical(cfg: &CompactMultilineConfig) -> usize {
+        let pad = cfg.get_padding();
+        pad.top.size + pad.bottom.size
+    }
+
+    fn split_value(value: usize, by: usize) -> (usize, usize) {
+        let val = value / by;
+        let rest = value - val * by;
+        (val, rest)
+    }
+
+    fn config_string(
+        value: &str,
+        cfg: &CompactMultilineConfig,
+        width: usize,
+        height: usize,
+    ) -> String {
+        let width = width - get_padding_horizontal(cfg);
+        let height = height - get_padding_vertical(cfg);
+        let ah = cfg.get_alignment_horizontal();
+        let av = cfg.get_alignment_vertical();
+        set_string_dimension(value, width, height, ah, av)
+    }
+
+    fn set_string_dimension(
+        text: &str,
+        width: usize,
+        height: usize,
+        ah: AlignmentHorizontal,
+        av: AlignmentVertical,
+    ) -> String {
+        let mut out = Vec::with_capacity(height);
+
+        let count_lines = count_lines(text);
+
+        let (top, bottom) = indent_vertical(av, height, count_lines);
+
+        out.extend(repeat(String::new()).take(top));
+
+        for line in get_lines(text) {
+            let w = string_width(&line);
+            let (left, right) = indent_horizontal(ah, width, w);
+
+            let mut buf = String::new();
+            buf.extend(repeat(' ').take(left));
+            buf.push_str(&line);
+            buf.extend(repeat(' ').take(right));
+
+            out.push(buf);
+        }
+
+        out.extend(repeat(String::new()).take(bottom));
+
+        out.join("\n")
+    }
+
+    fn indent_vertical(al: AlignmentVertical, available: usize, real: usize) -> (usize, usize) {
+        let top = indent_top(al, available, real);
+        let bottom = available - real - top;
+        (top, bottom)
+    }
+
+    fn indent_horizontal(al: AlignmentHorizontal, available: usize, real: usize) -> (usize, usize) {
+        let top = indent_left(al, available, real);
+        let right = available - real - top;
+        (top, right)
+    }
+
+    fn indent_top(al: AlignmentVertical, available: usize, real: usize) -> usize {
+        match al {
+            AlignmentVertical::Top => 0,
+            AlignmentVertical::Bottom => available - real,
+            AlignmentVertical::Center => (available - real) / 2,
+        }
+    }
+
+    fn indent_left(al: AlignmentHorizontal, available: usize, real: usize) -> usize {
+        match al {
+            AlignmentHorizontal::Left => 0,
+            AlignmentHorizontal::Right => available - real,
+            AlignmentHorizontal::Center => (available - real) / 2,
+        }
+    }
+
+    fn short_splits(splits: &mut Vec<usize>, width: usize) -> Vec<usize> {
+        if splits.is_empty() {
+            return Vec::new();
+        }
+
+        let mut out = Vec::new();
+        let mut pos = 0;
+        for &split in splits.iter() {
+            if pos + split >= width {
+                break;
+            }
+
+            pos += split;
+            out.push(pos);
+        }
+
+        let _ = splits.drain(..out.len());
+
+        if !splits.is_empty() && pos <= width {
+            let rest = width - pos;
+            splits[0] -= rest;
+        }
+
+        out
+    }
+
+    fn short_splits3(splits: &mut Vec<usize>, width: usize) -> (bool, Vec<usize>) {
+        if splits.is_empty() {
+            return (false, Vec::new());
+        }
+
+        let mut out = Vec::new();
+        let mut pos = 0;
+        for &split in splits.iter() {
+            if pos + split >= width {
+                break;
+            }
+
+            pos += split + 1;
+            out.push(split);
+        }
+
+        let _ = splits.drain(..out.len());
+
+        if splits.is_empty() {
+            return (false, out);
+        }
+
+        if pos <= width {
+            splits[0] -= width - pos;
+            if splits[0] > 0 {
+                splits[0] -= 1;
+            } else {
+                let _ = splits.remove(0);
+                return (true, out);
+            }
+        }
+
+        (false, out)
+    }
+
+    fn squash_splits(splits: &mut [usize]) {
+        splits.iter_mut().enumerate().for_each(|(i, s)| *s += i);
+    }
+}


Test patch:
diff --git a/json_to_table/tests/test_config.rs b/json_to_table/tests/test_config.rs
index 303d5b0..464b245 100644
--- a/json_to_table/tests/test_config.rs
+++ b/json_to_table/tests/test_config.rs
@@ -1,9 +1,6 @@
 use json_to_table::json_to_table;
 use serde_json::json;
-use tabled::{
-    settings::{Alignment, Padding, Style},
-    Table,
-};
+use tabled::settings::{Alignment, Padding, Style};
 
 #[cfg(feature = "color")]
 use tabled::{grid::color::AnsiColor, grid::config::SpannedConfig};
@@ -21,15 +18,10 @@ fn config_from_table_test() {
         }
     );
 
-    let cfg = Table::new([""])
+    let table = json_to_table(&value)
         .with(Alignment::center())
         .with(Alignment::center_vertical())
-        .get_config()
-        .clone();
-
-    let table = json_to_table(&value)
-        .set_style(Style::modern())
-        .set_config(cfg)
+        .with(Style::modern())
         .collapse()
         .to_string();
 
@@ -66,16 +58,11 @@ fn config_from_table_padding_zero_test() {
         }
     );
 
-    let cfg = Table::new([""])
+    let table = json_to_table(&value)
         .with(Padding::zero())
         .with(Alignment::center())
         .with(Alignment::center_vertical())
-        .get_config()
-        .clone();
-
-    let table = json_to_table(&value)
-        .set_style(Style::modern())
-        .set_config(cfg)
+        .with(Style::modern())
         .collapse()
         .to_string();
 
@@ -112,16 +99,11 @@ fn config_from_table_general_test() {
         }
     );
 
-    let cfg = Table::new([""])
+    let table = json_to_table(&value)
         .with(Padding::zero())
         .with(Alignment::center())
         .with(Alignment::center_vertical())
-        .get_config()
-        .clone();
-
-    let table = json_to_table(&value)
-        .set_style(Style::modern())
-        .set_config(cfg)
+        .with(Style::modern())
         .to_string();
 
     assert_eq!(
@@ -151,6 +133,8 @@ fn config_from_table_general_test() {
 #[cfg(feature = "color")]
 #[test]
 fn color_test() {
+    use tabled::grid::config::ColoredConfig;
+
     let value = json!(
         {
             "key1": 123,
@@ -164,10 +148,11 @@ fn color_test() {
 
     let mut cfg = SpannedConfig::default();
     cfg.set_border_color_global(AnsiColor::new("\u{1b}[34m".into(), "\u{1b}[39m".into()));
+    let cfg = ColoredConfig::new(cfg, Default::default());
 
     let table = json_to_table(&value)
-        .set_style(Style::modern())
-        .set_config(cfg.into())
+        .with(cfg)
+        .with(Style::modern())
         .collapse()
         .to_string();
 
@@ -182,11 +167,11 @@ fn color_test() {
             "\u{1b}[34m│\u{1b}[39m     \u{1b}[34m│\u{1b}[39m456 \u{1b}[34m│\u{1b}[39m\n",
             "\u{1b}[34m├─────\u{1b}[39m\u{1b}[34m┼────┤\u{1b}[39m\n",
             "\u{1b}[34m│\u{1b}[39mkey1 \u{1b}[34m│\u{1b}[39m123 \u{1b}[34m│\u{1b}[39m\n",
-            "\u{1b}[34m├─────\u{1b}[39m\u{1b}[34m┼──┬─┤\u{1b}[39m\n",
+            "\u{1b}[34m├─────\u{1b}[39m\u{1b}[34m┼──\u{1b}[39m\u{1b}[34m┬─┤\u{1b}[39m\n",
             "\u{1b}[34m│\u{1b}[39mkey22\u{1b}[34m│\u{1b}[39mk1\u{1b}[34m│\u{1b}[39m1\u{1b}[34m│\u{1b}[39m\n",
             "\u{1b}[34m│\u{1b}[39m     \u{1b}[34m├──\u{1b}[39m\u{1b}[34m┼─┤\u{1b}[39m\n",
             "\u{1b}[34m│\u{1b}[39m     \u{1b}[34m│\u{1b}[39mk2\u{1b}[34m│\u{1b}[39m2\u{1b}[34m│\u{1b}[39m\n",
-            "\u{1b}[34m└─────\u{1b}[39m\u{1b}[34m┴──\u{1b}[39m\u{1b}[34m┴─┘\u{1b}[39m"
+            "\u{1b}[34m└─────\u{1b}[39m\u{1b}[34m┴──\u{1b}[39m\u{1b}[34m┴─┘\u{1b}[39m",
         )
     );
 }
diff --git a/json_to_table/tests/test_orientation_modes.rs b/json_to_table/tests/test_orientation_modes.rs
index d7600d8..b667190 100644
--- a/json_to_table/tests/test_orientation_modes.rs
+++ b/json_to_table/tests/test_orientation_modes.rs
@@ -34,8 +34,8 @@ fn orientation_test_1() {
     );
 
     let table = json_to_table(&value)
-        .set_style(Style::extended())
-        .set_object_mode(Orientation::Horizontal)
+        .with(Style::extended())
+        .object_orientation(Orientation::Horizontal)
         .to_string();
 
     assert_eq!(
@@ -86,9 +86,9 @@ fn orientation_test_2() {
     );
 
     let table = json_to_table(&value)
-        .set_style(Style::modern())
-        .set_object_mode(Orientation::Horizontal)
-        .set_array_mode(Orientation::Horizontal)
+        .with(Style::modern())
+        .object_orientation(Orientation::Horizontal)
+        .array_orientation(Orientation::Horizontal)
         .to_string();
 
     assert_eq!(
@@ -157,7 +157,7 @@ fn orientation_visitor_test() {
         }}
     );
 
-    let table = json_to_table(&value).set_style(Style::modern()).to_string();
+    let table = json_to_table(&value).with(Style::modern()).to_string();
 
     assert_eq!(
         table,
@@ -277,6 +277,822 @@ fn orientation_visitor_test() {
     );
 }
 
+#[test]
+fn collapse_array_orientation_test_1() {
+    let value = json!(
+        {"widget": {
+            "debug": "on",
+            "text": {
+                "data": ["Click Here", "asda", "123132"],
+                "size": 36,
+                "style": "bold",
+                "name": "text1",
+                "hOffset": 250,
+                "vOffset": 100,
+                "alignment": "center",
+                "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
+            }
+        }}
+    );
+
+    let table = json_to_table(&value)
+        .with(Style::extended())
+        .array_orientation(Orientation::Horizontal)
+        .collapse()
+        .to_string();
+
+    assert_eq!(
+        table,
+        concat!(
+            "╔════════╦═══════╦═══════════════════════════════════════════════════════╗\n",
+            "║ widget ║ debug ║ on                                                    ║\n",
+            "║        ╠═══════╬═══════════╦═══════════════════════════════════════════╣\n",
+            "║        ║ text  ║ alignment ║ center                                    ║\n",
+            "║        ║       ╠═══════════╬═════════════════╦═══════════╦═════════════╣\n",
+            "║        ║       ║ data      ║ Click Here      ║ asda      ║ 123132      ║\n",
+            "║        ║       ╠═══════════╬═════════════════╩═══════════╩═════════════╣\n",
+            "║        ║       ║ hOffset   ║ 250                                       ║\n",
+            "║        ║       ╠═══════════╬═══════════════════════════════════════════╣\n",
+            "║        ║       ║ name      ║ text1                                     ║\n",
+            "║        ║       ╠═══════════╬═══════════════════════════════════════════╣\n",
+            "║        ║       ║ onMouseUp ║ sun1.opacity = (sun1.opacity / 100) * 90; ║\n",
+            "║        ║       ╠═══════════╬═══════════════════════════════════════════╣\n",
+            "║        ║       ║ size      ║ 36                                        ║\n",
+            "║        ║       ╠═══════════╬═══════════════════════════════════════════╣\n",
+            "║        ║       ║ style     ║ bold                                      ║\n",
+            "║        ║       ╠═══════════╬═══════════════════════════════════════════╣\n",
+            "║        ║       ║ vOffset   ║ 100                                       ║\n",
+            "╚════════╩═══════╩═══════════╩═══════════════════════════════════════════╝",
+        )
+    );
+}
+
+#[test]
+fn collapse_array_orientation_test_2() {
+    let value = json!(
+        {"widget": {
+            "debug": "on",
+            "text": {
+                "data": ["Click Here", "asda", "123132"],
+                "data1": [["Click", "1", "3", "4"], "aa", {"123132": 11}],
+                "size": 36,
+                "style": "bold",
+                "name": "text1",
+                "hOffset": 250,
+                "vOffset": 100,
+                "alignment": "center",
+                "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
+            }
+        }}
+    );
+
+    let table = json_to_table(&value)
+        .with(Style::extended())
+        .array_orientation(Orientation::Horizontal)
+        .collapse()
+        .to_string();
+
+    assert_eq!(
+        table,
+        concat!(
+            "╔════════╦═══════╦═══════════════════════════════════════════════════════╗\n",
+            "║ widget ║ debug ║ on                                                    ║\n",
+            "║        ╠═══════╬═══════════╦═══════════════════════════════════════════╣\n",
+            "║        ║ text  ║ alignment ║ center                                    ║\n",
+            "║        ║       ╠═══════════╬═════════════════╦═══════════╦═════════════╣\n",
+            "║        ║       ║ data      ║ Click Here      ║ asda      ║ 123132      ║\n",
+            "║        ║       ╠═══════════╬══════════╦═══╦══╩╦═══╦═════╦╩═══════╦═════╣\n",
+            "║        ║       ║ data1     ║ Click    ║ 1 ║ 3 ║ 4 ║ aa  ║ 123132 ║ 11  ║\n",
+            "║        ║       ╠═══════════╬══════════╩═══╩═══╩═══╩═════╩════════╩═════╣\n",
+            "║        ║       ║ hOffset   ║ 250                                       ║\n",
+            "║        ║       ╠═══════════╬═══════════════════════════════════════════╣\n",
+            "║        ║       ║ name      ║ text1                                     ║\n",
+            "║        ║       ╠═══════════╬═══════════════════════════════════════════╣\n",
+            "║        ║       ║ onMouseUp ║ sun1.opacity = (sun1.opacity / 100) * 90; ║\n",
+            "║        ║       ╠═══════════╬═══════════════════════════════════════════╣\n",
+            "║        ║       ║ size      ║ 36                                        ║\n",
+            "║        ║       ╠═══════════╬═══════════════════════════════════════════╣\n",
+            "║        ║       ║ style     ║ bold                                      ║\n",
+            "║        ║       ╠═══════════╬═══════════════════════════════════════════╣\n",
+            "║        ║       ║ vOffset   ║ 100                                       ║\n",
+            "╚════════╩═══════╩═══════════╩═══════════════════════════════════════════╝",
+        )
+    );
+}
+
+#[test]
+fn collapse_array_orientation_test_3() {
+    let value = json!(
+        {"widget": {
+            "debug": "on",
+            "text": {
+                "data": ["Click Here", "asda", "123132"],
+                "data1": [["Click", "1", "3", "4"], "aa", "123132", 11],
+                "size": 36,
+                "style": "bold",
+                "name": "text1",
+                "hOffset": 250,
+                "vOffset": 100,
+                "alignment": "center",
+                "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
+            }
+        }}
+    );
+
+    let table = json_to_table(&value)
+        .with(Style::extended())
+        .array_orientation(Orientation::Horizontal)
+        .collapse()
+        .to_string();
+
+    assert_eq!(
+        table,
+        concat!(
+            "╔════════╦═══════╦═══════════════════════════════════════════════════════╗\n",
+            "║ widget ║ debug ║ on                                                    ║\n",
+            "║        ╠═══════╬═══════════╦═══════════════════════════════════════════╣\n",
+            "║        ║ text  ║ alignment ║ center                                    ║\n",
+            "║        ║       ╠═══════════╬═════════════════╦═══════════╦═════════════╣\n",
+            "║        ║       ║ data      ║ Click Here      ║ asda      ║ 123132      ║\n",
+            "║        ║       ╠═══════════╬═════════╦═══╦═══╬═══╦═════╦═╩═══════╦═════╣\n",
+            "║        ║       ║ data1     ║ Click   ║ 1 ║ 3 ║ 4 ║ aa  ║ 123132  ║ 11  ║\n",
+            "║        ║       ╠═══════════╬═════════╩═══╩═══╩═══╩═════╩═════════╩═════╣\n",
+            "║        ║       ║ hOffset   ║ 250                                       ║\n",
+            "║        ║       ╠═══════════╬═══════════════════════════════════════════╣\n",
+            "║        ║       ║ name      ║ text1                                     ║\n",
+            "║        ║       ╠═══════════╬═══════════════════════════════════════════╣\n",
+            "║        ║       ║ onMouseUp ║ sun1.opacity = (sun1.opacity / 100) * 90; ║\n",
+            "║        ║       ╠═══════════╬═══════════════════════════════════════════╣\n",
+            "║        ║       ║ size      ║ 36                                        ║\n",
+            "║        ║       ╠═══════════╬═══════════════════════════════════════════╣\n",
+            "║        ║       ║ style     ║ bold                                      ║\n",
+            "║        ║       ╠═══════════╬═══════════════════════════════════════════╣\n",
+            "║        ║       ║ vOffset   ║ 100                                       ║\n",
+            "╚════════╩═══════╩═══════════╩═══════════════════════════════════════════╝",
+        )
+    );
+}
+
+#[test]
+fn collapse_array_orientation_test_4() {
+    let value = json!({
+        "data": ["Click Here", "asda", "123132"],
+        "data0":  "",
+        "data1": [["Click", "1", "3", "4"], ["aa", "123132"], [11, 1, 1, 1, 1, 1]],
+        "data2": [["C", "1", "3", "4"], ["a", "12"], [11, 1, 1]],
+    });
+
+    let table = json_to_table(&value)
+        .with(Style::extended())
+        .array_orientation(Orientation::Horizontal)
+        .collapse()
+        .to_string();
+
+    assert_eq!(
+        table,
+        concat!(
+            "╔═══════╦══════════════════════╦════════════════╦══════════════════╗\n",
+            "║ data  ║ Click Here           ║ asda           ║ 123132           ║\n",
+            "╠═══════╬══════════════════════╩════════════════╩══════════════════╣\n",
+            "║ data0 ║                                                          ║\n",
+            "╠═══════╬═══════╦═══╦═══╦═══╦════╦════════╦════╦═══╦═══╦═══╦═══╦═══╣\n",
+            "║ data1 ║ Click ║ 1 ║ 3 ║ 4 ║ aa ║ 123132 ║ 11 ║ 1 ║ 1 ║ 1 ║ 1 ║ 1 ║\n",
+            "╠═══════╬═══════╬═══╩╦══╩═╦═╩══╦═╩═════╦══╩════╬═══╩═══╬═══╩═╦═╩═══╣\n",
+            "║ data2 ║ C     ║ 1  ║ 3  ║ 4  ║ a     ║ 12    ║ 11    ║ 1   ║ 1   ║\n",
+            "╚═══════╩═══════╩════╩════╩════╩═══════╩═══════╩═══════╩═════╩═════╝",
+        )
+    );
+}
+
+#[test]
+fn collapse_array_orientation_test_5() {
+    let value = json!({
+        "data": ["Click Here", "asda", "123132", "1"],
+        "data1": [["Click", "1", "3", "4"], ["aa", "123132"], [11, 1, 1, 1, 1, 1]],
+        "data2": [["C", "1", "3", "4"], ["a", "12"], [11, 1, 1]],
+    });
+
+    let table = json_to_table(&value)
+        .with(Style::extended())
+        .array_orientation(Orientation::Horizontal)
+        .collapse()
+        .to_string();
+
+    assert_eq!(
+        table,
+        concat!(
+            "╔═══════╦════════════════════╦════════════╦══════════════╦═════════╗\n",
+            "║ data  ║ Click Here         ║ asda       ║ 123132       ║ 1       ║\n",
+            "╠═══════╬═══════╦═══╦═══╦═══╦╩═══╦════════╬════╦═══╦═══╦═╩═╦═══╦═══╣\n",
+            "║ data1 ║ Click ║ 1 ║ 3 ║ 4 ║ aa ║ 123132 ║ 11 ║ 1 ║ 1 ║ 1 ║ 1 ║ 1 ║\n",
+            "╠═══════╬═══════╬═══╩╦══╩═╦═╩══╦═╩═════╦══╩════╬═══╩═══╬═══╩═╦═╩═══╣\n",
+            "║ data2 ║ C     ║ 1  ║ 3  ║ 4  ║ a     ║ 12    ║ 11    ║ 1   ║ 1   ║\n",
+            "╚═══════╩═══════╩════╩════╩════╩═══════╩═══════╩═══════╩═════╩═════╝",
+        )
+    );
+}
+
+#[test]
+fn collapse_array_orientation_test_6() {
+    let value = json!({
+        "data": ["Click Here", "asda", "123132", "1"],
+        "data1": [["Click", "1", "3", "4"], {"aa": "123132", "bb": "123132"}, [11, 1, 1, 1, 1, 1]],
+        "data2": { "11": {"x": "xxx"}, "22": 1 },
+        "data3": [["C", "1", "3", "4"], ["a", "12"], [11, 1, 1]],
+    });
+
+    let table = json_to_table(&value)
+        .with(Style::extended())
+        .array_orientation(Orientation::Horizontal)
+        .collapse()
+        .to_string();
+
+    assert_eq!(
+        table,
+        concat!(
+            "╔═══════╦════════════════════╦════════════╦══════════════╦═════════╗\n",
+            "║ data  ║ Click Here         ║ asda       ║ 123132       ║ 1       ║\n",
+            "╠═══════╬═══════╦═══╦═══╦═══╦╩═══╦════════╬════╦═══╦═══╦═╩═╦═══╦═══╣\n",
+            "║ data1 ║ Click ║ 1 ║ 3 ║ 4 ║ aa ║ 123132 ║ 11 ║ 1 ║ 1 ║ 1 ║ 1 ║ 1 ║\n",
+            "║       ║       ║   ║   ║   ╠════╬════════╣    ║   ║   ║   ║   ║   ║\n",
+            "║       ║       ║   ║   ║   ║ bb ║ 123132 ║    ║   ║   ║   ║   ║   ║\n",
+            "╠═══════╬════╦══╩╦══╩═══╩═══╩════╩════════╩════╩═══╩═══╩═══╩═══╩═══╣\n",
+            "║ data2 ║ 11 ║ x ║ xxx                                             ║\n",
+            "║       ╠════╬═══╩═════════════════════════════════════════════════╣\n",
+            "║       ║ 22 ║ 1                                                   ║\n",
+            "╠═══════╬════╩══╦════╦════╦════╦═══════╦═══════╦═══════╦═════╦═════╣\n",
+            "║ data3 ║ C     ║ 1  ║ 3  ║ 4  ║ a     ║ 12    ║ 11    ║ 1   ║ 1   ║\n",
+            "╚═══════╩═══════╩════╩════╩════╩═══════╩═══════╩═══════╩═════╩═════╝",
+        )
+    );
+}
+
+#[test]
+fn collapse_object_orientation_test_1() {
+    let value = json!({
+        "widget": {
+            "debug": "on",
+            "text": {
+                "data": ["Click Here", "asda", "123132"],
+                "size": 36,
+                "style": "bold",
+                "name": "text1",
+                "hOffset": 250,
+                "vOffset": 100,
+                "alignment": "center",
+                "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
+            }
+        }
+    });
+
+    let table = json_to_table(&value)
+        .with(Style::extended())
+        .object_orientation(Orientation::Horizontal)
+        .collapse()
+        .to_string();
+
+    assert_eq!(
+        table,
+        concat!(
+            "╔═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗\n",
+            "║ widget                                                                                                                ║\n",
+            "╠═══════╦═══════════════════════════════════════════════════════════════════════════════════════════════════════════════╣\n",
+            "║ debug ║ text                                                                                                          ║\n",
+            "╠═══════╬═══════════╦════════════╦═════════╦═══════╦═══════════════════════════════════════════╦══════╦═══════╦═════════╣\n",
+            "║ on    ║ alignment ║ data       ║ hOffset ║ name  ║ onMouseUp                                 ║ size ║ style ║ vOffset ║\n",
+            "║       ╠═══════════╬════════════╬═════════╬═══════╬═══════════════════════════════════════════╬══════╬═══════╬═════════╣\n",
+            "║       ║ center    ║ Click Here ║ 250     ║ text1 ║ sun1.opacity = (sun1.opacity / 100) * 90; ║ 36   ║ bold  ║ 100     ║\n",
+            "║       ║           ╠════════════╣         ║       ║                                           ║      ║       ║         ║\n",
+            "║       ║           ║ asda       ║         ║       ║                                           ║      ║       ║         ║\n",
+            "║       ║           ╠════════════╣         ║       ║                                           ║      ║       ║         ║\n",
+            "║       ║           ║ 123132     ║         ║       ║                                           ║      ║       ║         ║\n",
+            "╚═══════╩═══════════╩════════════╩═════════╩═══════╩═══════════════════════════════════════════╩══════╩═══════╩═════════╝",
+        )
+    );
+}
+
+#[test]
+fn collapse_object_orientation_test_2() {
+    let value = json!(
+        {"widget": {
+            "debug": "on",
+            "text": {
+                "data": ["Click Here", "asda", "123132"],
+                "data1": [["Click", "1", "3", "4"], "aa", {"123132": 11}],
+                "size": 36,
+                "style": "bold",
+                "name": "text1",
+                "hOffset": 250,
+                "vOffset": 100,
+                "alignment": "center",
+                "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
+            }
+        }}
+    );
+
+    let table = json_to_table(&value)
+        .with(Style::extended())
+        .object_orientation(Orientation::Horizontal)
+        .collapse()
+        .to_string();
+
+    assert_eq!(
+        table,
+        concat!(
+            "╔════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗\n",
+            "║ widget                                                                                                                         ║\n",
+            "╠═══════╦════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╣\n",
+            "║ debug ║ text                                                                                                                   ║\n",
+            "╠═══════╬═══════════╦════════════╦════════╦═════════╦═══════╦═══════════════════════════════════════════╦══════╦═══════╦═════════╣\n",
+            "║ on    ║ alignment ║ data       ║ data1  ║ hOffset ║ name  ║ onMouseUp                                 ║ size ║ style ║ vOffset ║\n",
+            "║       ╠═══════════╬════════════╬════════╬═════════╬═══════╬═══════════════════════════════════════════╬══════╬═══════╬═════════╣\n",
+            "║       ║ center    ║ Click Here ║ Click  ║ 250     ║ text1 ║ sun1.opacity = (sun1.opacity / 100) * 90; ║ 36   ║ bold  ║ 100     ║\n",
+            "║       ║           ║            ╠════════╣         ║       ║                                           ║      ║       ║         ║\n",
+            "║       ║           ║            ║ 1      ║         ║       ║                                           ║      ║       ║         ║\n",
+            "║       ║           ║            ╠════════╣         ║       ║                                           ║      ║       ║         ║\n",
+            "║       ║           ║            ║ 3      ║         ║       ║                                           ║      ║       ║         ║\n",
+            "║       ║           ╠════════════╬════════╣         ║       ║                                           ║      ║       ║         ║\n",
+            "║       ║           ║ asda       ║ 4      ║         ║       ║                                           ║      ║       ║         ║\n",
+            "║       ║           ║            ╠════════╣         ║       ║                                           ║      ║       ║         ║\n",
+            "║       ║           ║            ║ aa     ║         ║       ║                                           ║      ║       ║         ║\n",
+            "║       ║           ╠════════════╬════════╣         ║       ║                                           ║      ║       ║         ║\n",
+            "║       ║           ║ 123132     ║ 123132 ║         ║       ║                                           ║      ║       ║         ║\n",
+            "║       ║           ║            ╠════════╣         ║       ║                                           ║      ║       ║         ║\n",
+            "║       ║           ║            ║ 11     ║         ║       ║                                           ║      ║       ║         ║\n",
+            "╚═══════╩═══════════╩════════════╩════════╩═════════╩═══════╩═══════════════════════════════════════════╩══════╩═══════╩═════════╝",
+        )
+    );
+}
+
+#[test]
+fn collapse_object_orientation_test_3() {
+    let value = json!(
+        {"widget": {
+            "debug": "on",
+            "text": {
+                "data": ["Click Here", "asda", "123132"],
+                "data1": [["Click", "1", "3", "4"], "aa", "123132", 11],
+                "size": 36,
+                "style": "bold",
+                "name": "text1",
+                "hOffset": 250,
+                "vOffset": 100,
+                "alignment": "center",
+                "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
+            }
+        }}
+    );
+
+    let table = json_to_table(&value)
+        .with(Style::modern())
+        .object_orientation(Orientation::Horizontal)
+        .collapse()
+        .to_string();
+
+    assert_eq!(
+        table,
+        concat!(
+            "┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐\n",
+            "│ widget                                                                                                                         │\n",
+            "├───────┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤\n",
+            "│ debug │ text                                                                                                                   │\n",
+            "├───────┼───────────┬────────────┬────────┬─────────┬───────┬───────────────────────────────────────────┬──────┬───────┬─────────┤\n",
+            "│ on    │ alignment │ data       │ data1  │ hOffset │ name  │ onMouseUp                                 │ size │ style │ vOffset │\n",
+            "│       ├───────────┼────────────┼────────┼─────────┼───────┼───────────────────────────────────────────┼──────┼───────┼─────────┤\n",
+            "│       │ center    │ Click Here │ Click  │ 250     │ text1 │ sun1.opacity = (sun1.opacity / 100) * 90; │ 36   │ bold  │ 100     │\n",
+            "│       │           │            ├────────┤         │       │                                           │      │       │         │\n",
+            "│       │           │            │ 1      │         │       │                                           │      │       │         │\n",
+            "│       │           │            ├────────┤         │       │                                           │      │       │         │\n",
+            "│       │           │            │ 3      │         │       │                                           │      │       │         │\n",
+            "│       │           ├────────────┼────────┤         │       │                                           │      │       │         │\n",
+            "│       │           │ asda       │ 4      │         │       │                                           │      │       │         │\n",
+            "│       │           │            ├────────┤         │       │                                           │      │       │         │\n",
+            "│       │           │            │ aa     │         │       │                                           │      │       │         │\n",
+            "│       │           ├────────────┼────────┤         │       │                                           │      │       │         │\n",
+            "│       │           │ 123132     │ 123132 │         │       │                                           │      │       │         │\n",
+            "│       │           │            ├────────┤         │       │                                           │      │       │         │\n",
+            "│       │           │            │ 11     │         │       │                                           │      │       │         │\n",
+            "└───────┴───────────┴────────────┴────────┴─────────┴───────┴───────────────────────────────────────────┴──────┴───────┴─────────┘",
+        )
+    );
+}
+
+#[test]
+fn collapse_object_orientation_test_4() {
+    let value = json!({
+        "data": ["Click Here", "asda", "123132"],
+        "data0":  "",
+        "data1": [["Click", "1", "3", "4"], ["aa", "123132"], [11, 1, 1, 1, 1, 1]],
+        "data2": [["C", "1", "3", "4"], ["a", "12"], [11, 1, 1]],
+    });
+
+    let table = json_to_table(&value)
+        .with(Style::extended())
+        .object_orientation(Orientation::Horizontal)
+        .collapse()
+        .to_string();
+
+    assert_eq!(
+        table,
+        concat!(
+            "╔════════════╦═══════╦════════╦═══════╗\n",
+            "║ data       ║ data0 ║ data1  ║ data2 ║\n",
+            "╠════════════╬═══════╬════════╬═══════╣\n",
+            "║ Click Here ║       ║ Click  ║ C     ║\n",
+            "║            ║       ╠════════╣       ║\n",
+            "║            ║       ║ 1      ║       ║\n",
+            "║            ║       ╠════════╬═══════╣\n",
+            "║            ║       ║ 3      ║ 1     ║\n",
+            "║            ║       ╠════════╬═══════╣\n",
+            "║            ║       ║ 4      ║ 3     ║\n",
+            "╠════════════║       ╠════════╬═══════╣\n",
+            "║ asda       ║       ║ aa     ║ 4     ║\n",
+            "║            ║       ╠════════╬═══════╣\n",
+            "║            ║       ║ 123132 ║ a     ║\n",
+            "║            ║       ╠════════╣       ║\n",
+            "║            ║       ║ 11     ╠═══════╣\n",
+            "║            ║       ╠════════╣ 12    ║\n",
+            "║            ║       ║ 1      ║       ║\n",
+            "╠════════════║       ╠════════╬═══════╣\n",
+            "║ 123132     ║       ║ 1      ║ 11    ║\n",
+            "║            ║       ╠════════╣       ║\n",
+            "║            ║       ║ 1      ║       ║\n",
+            "║            ║       ╠════════╬═══════╣\n",
+            "║            ║       ║ 1      ║ 1     ║\n",
+            "║            ║       ╠════════╬═══════╣\n",
+            "║            ║       ║ 1      ║ 1     ║\n",
+            "╚════════════╩═══════╩════════╩═══════╝",
+        )
+    );
+}
+
+#[test]
+fn collapse_object_orientation_test_5() {
+    let value = json!({
+        "data": ["Click Here", "asda", "123132", "1"],
+        "data1": [["Click", "1", "3", "4"], ["aa", "123132"], [11, 1, 1, 1, 1, 1]],
+        "data2": [["C", "1", "3", "4"], ["a", "12"], [11, 1, 1]],
+    });
+
+    let table = json_to_table(&value)
+        .with(Style::extended())
+        .object_orientation(Orientation::Horizontal)
+        .collapse()
+        .to_string();
+
+    assert_eq!(
+        table,
+        concat!(
+            "╔════════════╦════════╦═══════╗\n",
+            "║ data       ║ data1  ║ data2 ║\n",
+            "╠════════════╬════════╬═══════╣\n",
+            "║ Click Here ║ Click  ║ C     ║\n",
+            "║            ╠════════╣       ║\n",
+            "║            ║ 1      ║       ║\n",
+            "║            ╠════════╬═══════╣\n",
+            "║            ║ 3      ║ 1     ║\n",
+            "╠════════════╬════════╬═══════╣\n",
+            "║ asda       ║ 4      ║ 3     ║\n",
+            "║            ╠════════╬═══════╣\n",
+            "║            ║ aa     ║ 4     ║\n",
+            "║            ╠════════╬═══════╣\n",
+            "║            ║ 123132 ║ a     ║\n",
+            "╠════════════╬════════╣       ║\n",
+            "║ 123132     ║ 11     ╠═══════╣\n",
+            "║            ╠════════╣ 12    ║\n",
+            "║            ║ 1      ║       ║\n",
+            "║            ╠════════╬═══════╣\n",
+            "║            ║ 1      ║ 11    ║\n",
+            "╠════════════╬════════╣       ║\n",
+            "║ 1          ║ 1      ║       ║\n",
+            "║            ╠════════╬═══════╣\n",
+            "║            ║ 1      ║ 1     ║\n",
+            "║            ╠════════╬═══════╣\n",
+            "║            ║ 1      ║ 1     ║\n",
+            "╚════════════╩════════╩═══════╝",
+        )
+    );
+}
+
+#[test]
+fn collapse_object_orientation_test_6() {
+    let value = json!({
+        "data": ["Click Here", "asda", "123132", "1"],
+        "data1": [["Click", "1", "3", "4"], {"aa": "123132", "bb": "123132"}, [11, 1, 1, 1, 1, 1]],
+        "data2": { "11": {"x": "xxx"}, "22": 1 },
+        "data3": [["C", "1", "3", "4"], ["a", "12"], [11, 1, 1]],
+    });
+
+    let table = json_to_table(&value)
+        .with(Style::extended())
+        .object_orientation(Orientation::Horizontal)
+        .collapse()
+        .to_string();
+
+    assert_eq!(
+        table,
+        concat!(
+            "╔════════════╦═════════════════╦══════════╦═══════╗\n",
+            "║ data       ║ data1           ║ data2    ║ data3 ║\n",
+            "╠════════════╬═════════════════╬═════╦════╬═══════╣\n",
+            "║ Click Here ║ Click           ║ 11  ║ 22 ║ C     ║\n",
+            "║            ╠═════════════════╬═════╬════╣       ║\n",
+            "║            ║ 1               ║ x   ║ 1  ║       ║\n",
+            "║            ╠═════════════════╬═════╣    ╠═══════╣\n",
+            "║            ║ 3               ║ xxx ║    ║ 1     ║\n",
+            "╠════════════╬═════════════════╣     ║    ╠═══════╣\n",
+            "║ asda       ║ 4               ║     ║    ║ 3     ║\n",
+            "║            ╠════════╦════════╣     ║    ╠═══════╣\n",
+            "║            ║ aa     ║ bb     ║     ║    ║ 4     ║\n",
+            "║            ╠════════╬════════╣     ║    ╠═══════╣\n",
+            "║            ║ 123132 ║ 123132 ║     ║    ║ a     ║\n",
+            "╠════════════╬════════╩════════╣     ║    ║       ║\n",
+            "║ 123132     ║ 11              ║     ║    ╠═══════╣\n",
+            "║            ╠═════════════════║     ║    ║ 12    ║\n",
+            "║            ║ 1               ║     ║    ║       ║\n",
+            "║            ╠═════════════════║     ║    ╠═══════╣\n",
+            "║            ║ 1               ║     ║    ║ 11    ║\n",
+            "╠════════════╬═════════════════║     ║    ║       ║\n",
+            "║ 1          ║ 1               ║     ║    ║       ║\n",
+            "║            ╠═════════════════║     ║    ╠═══════╣\n",
+            "║            ║ 1               ║     ║    ║ 1     ║\n",
+            "║            ╠═════════════════║     ║    ╠═══════╣\n",
+            "║            ║ 1               ║     ║    ║ 1     ║\n",
+            "╚════════════╩═════════════════╩═════╩════╩═══════╝",
+        )
+    );
+}
+
+#[test]
+fn collapse_object_array_orientation_test_1() {
+    let value = json!({
+        "widget": {
+            "debug": "on",
+            "text": {
+                "data": ["Click Here", "asda", "123132"],
+                "size": 36,
+                "style": "bold",
+                "name": "text1",
+                "hOffset": 250,
+                "vOffset": 100,
+                "alignment": "center",
+                "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
+            }
+        }
+    });
+
+    let table = json_to_table(&value)
+        .with(Style::extended())
+        .object_orientation(Orientation::Horizontal)
+        .array_orientation(Orientation::Horizontal)
+        .collapse()
+        .to_string();
+
+    assert_eq!(
+        table,
+        concat!(
+            "╔═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗\n",
+            "║ widget                                                                                                                                ║\n",
+            "╠═══════╦═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╣\n",
+            "║ debug ║ text                                                                                                                          ║\n",
+            "╠═══════╬═══════════╦════════════════════════════╦═════════╦═══════╦═══════════════════════════════════════════╦══════╦═══════╦═════════╣\n",
+            "║ on    ║ alignment ║ data                       ║ hOffset ║ name  ║ onMouseUp                                 ║ size ║ style ║ vOffset ║\n",
+            "║       ╠═══════════╬════════════╦══════╦════════╬═════════╬═══════╬═══════════════════════════════════════════╬══════╬═══════╬═════════╣\n",
+            "║       ║ center    ║ Click Here ║ asda ║ 123132 ║ 250     ║ text1 ║ sun1.opacity = (sun1.opacity / 100) * 90; ║ 36   ║ bold  ║ 100     ║\n",
+            "╚═══════╩═══════════╩════════════╩══════╩════════╩═════════╩═══════╩═══════════════════════════════════════════╩══════╩═══════╩═════════╝",
+        )
+    );
+}
+
+#[test]
+fn collapse_object_array_orientation_test_2() {
+    let value = json!(
+        {"widget": {
+            "debug": "on",
+            "text": {
+                "data": ["Click Here", "asda", "123132"],
+                "data1": [["Click", "1", "3", "4"], "aa", {"123132": 11}],
+                "size": 36,
+                "style": "bold",
+                "name": "text1",
+                "hOffset": 250,
+                "vOffset": 100,
+                "alignment": "center",
+                "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
+            }
+        }}
+    );
+
+    let table = json_to_table(&value)
+        .with(Style::extended())
+        .object_orientation(Orientation::Horizontal)
+        .array_orientation(Orientation::Horizontal)
+        .collapse()
+        .to_string();
+
+    assert_eq!(
+        table,
+        concat!(
+            "╔═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗\n",
+            "║ widget                                                                                                                                                                  ║\n",
+            "╠═══════╦═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╣\n",
+            "║ debug ║ text                                                                                                                                                            ║\n",
+            "╠═══════╬═══════════╦════════════════════════════╦═════════════════════════════════╦═════════╦═══════╦═══════════════════════════════════════════╦══════╦═══════╦═════════╣\n",
+            "║ on    ║ alignment ║ data                       ║ data1                           ║ hOffset ║ name  ║ onMouseUp                                 ║ size ║ style ║ vOffset ║\n",
+            "║       ╠═══════════╬════════════╦══════╦════════╬═══════╦═══╦═══╦═══╦════╦════════╬═════════╬═══════╬═══════════════════════════════════════════╬══════╬═══════╬═════════╣\n",
+            "║       ║ center    ║ Click Here ║ asda ║ 123132 ║ Click ║ 1 ║ 3 ║ 4 ║ aa ║ 123132 ║ 250     ║ text1 ║ sun1.opacity = (sun1.opacity / 100) * 90; ║ 36   ║ bold  ║ 100     ║\n",
+            "║       ║           ║            ║      ║        ║       ║   ║   ║   ║    ╠════════╣         ║       ║                                           ║      ║       ║         ║\n",
+            "║       ║           ║            ║      ║        ║       ║   ║   ║   ║    ║ 11     ║         ║       ║                                           ║      ║       ║         ║\n",
+            "╚═══════╩═══════════╩════════════╩══════╩════════╩═══════╩═══╩═══╩═══╩════╩════════╩═════════╩═══════╩═══════════════════════════════════════════╩══════╩═══════╩═════════╝",
+        )
+    );
+}
+
+#[test]
+fn collapse_object_array_orientation_test_3() {
+    let value = json!(
+        {"widget": {
+            "debug": "on",
+            "text": {
+                "data": ["Click Here", "asda", "123132"],
+                "data1": [["Click", "1", "3", "4"], "aa", "123132", 11],
+                "size": 36,
+                "style": "bold",
+                "name": "text1",
+                "hOffset": 250,
+                "vOffset": 100,
+                "alignment": "center",
+                "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
+            }
+        }}
+    );
+
+    let table = json_to_table(&value)
+        .with(Style::modern())
+        .object_orientation(Orientation::Horizontal)
+        .array_orientation(Orientation::Horizontal)
+        .collapse()
+        .to_string();
+
+    assert_eq!(
+        table,
+        concat!(
+            "┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐\n",
+            "│ widget                                                                                                                                                                       │\n",
+            "├───────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤\n",
+            "│ debug │ text                                                                                                                                                                 │\n",
+            "├───────┼───────────┬────────────────────────────┬──────────────────────────────────────┬─────────┬───────┬───────────────────────────────────────────┬──────┬───────┬─────────┤\n",
+            "│ on    │ alignment │ data                       │ data1                                │ hOffset │ name  │ onMouseUp                                 │ size │ style │ vOffset │\n",
+            "│       ├───────────┼────────────┬──────┬────────┼───────┬───┬───┬───┬────┬────────┬────┼─────────┼───────┼───────────────────────────────────────────┼──────┼───────┼─────────┤\n",
+            "│       │ center    │ Click Here │ asda │ 123132 │ Click │ 1 │ 3 │ 4 │ aa │ 123132 │ 11 │ 250     │ text1 │ sun1.opacity = (sun1.opacity / 100) * 90; │ 36   │ bold  │ 100     │\n",
+            "└───────┴───────────┴────────────┴──────┴────────┴───────┴───┴───┴───┴────┴────────┴────┴─────────┴───────┴───────────────────────────────────────────┴──────┴───────┴─────────┘",
+        )
+    );
+}
+
+#[test]
+fn collapse_object_array_orientation_test_4() {
+    let value = json!({
+        "data": ["Click Here", "asda", "123132"],
+        "data0":  "",
+        "data1": [["Click", "1", "3", "4"], ["aa", "123132"], [11, 1, 1, 1, 1, 1]],
+        "data2": [["C", "1", "3", "4"], ["a", "12"], [11, 1, 1]],
+    });
+
+    let table = json_to_table(&value)
+        .with(Style::extended())
+        .object_orientation(Orientation::Horizontal)
+        .array_orientation(Orientation::Horizontal)
+        .collapse()
+        .to_string();
+
+    assert_eq!(
+        table,
+        concat!(
+            "╔════════════════════════════╦═══════╦══════════════════════════════════════════════════════════╦═════════════════════════════════════╗\n",
+            "║ data                       ║ data0 ║ data1                                                    ║ data2                               ║\n",
+            "╠════════════╦══════╦════════╬═══════╬═══════╦═══╦═══╦═══╦════╦════════╦════╦═══╦═══╦═══╦═══╦═══╬═══╦═══╦═══╦═══╦═══╦════╦════╦═══╦═══╣\n",
+            "║ Click Here ║ asda ║ 123132 ║       ║ Click ║ 1 ║ 3 ║ 4 ║ aa ║ 123132 ║ 11 ║ 1 ║ 1 ║ 1 ║ 1 ║ 1 ║ C ║ 1 ║ 3 ║ 4 ║ a ║ 12 ║ 11 ║ 1 ║ 1 ║\n",
+            "╚════════════╩══════╩════════╩═══════╩═══════╩═══╩═══╩═══╩════╩════════╩════╩═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╩════╩════╩═══╩═══╝",
+        )
+    );
+}
+
+#[test]
+fn collapse_object_array_orientation_test_5() {
+    let value = json!({
+        "data": ["Click Here", "asda", "123132", "1"],
+        "data1": [["Click", "1", "3", "4"], ["aa", "123132"], [11, 1, 1, 1, 1, 1]],
+        "data2": [["C", "1", "3", "4"], ["a", "12"], [11, 1, 1]],
+    });
+
+    let table = json_to_table(&value)
+        .with(Style::extended())
+        .object_orientation(Orientation::Horizontal)
+        .array_orientation(Orientation::Horizontal)
+        .collapse()
+        .to_string();
+
+    assert_eq!(
+        table,
+        concat!(
+            "╔════════════════════════════════╦══════════════════════════════════════════════════════════╦═════════════════════════════════════╗\n",
+            "║ data                           ║ data1                                                    ║ data2                               ║\n",
+            "╠════════════╦══════╦════════╦═══╬═══════╦═══╦═══╦═══╦════╦════════╦════╦═══╦═══╦═══╦═══╦═══╬═══╦═══╦═══╦═══╦═══╦════╦════╦═══╦═══╣\n",
+            "║ Click Here ║ asda ║ 123132 ║ 1 ║ Click ║ 1 ║ 3 ║ 4 ║ aa ║ 123132 ║ 11 ║ 1 ║ 1 ║ 1 ║ 1 ║ 1 ║ C ║ 1 ║ 3 ║ 4 ║ a ║ 12 ║ 11 ║ 1 ║ 1 ║\n",
+            "╚════════════╩══════╩════════╩═══╩═══════╩═══╩═══╩═══╩════╩════════╩════╩═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╩════╩════╩═══╩═══╝",
+        )
+    );
+}
+
+#[test]
+fn collapse_object_array_orientation_test_6() {
+    let value = json!({
+        "data": ["Click Here", "asda", "123132", "1"],
+        "data1": [["Click", "1", "3", "4"], {"aa": "123132", "bb": "123132"}, [11, 1, 1, 1, 1, 1]],
+        "data2": { "11": {"x": "xxx"}, "22": 1 },
+        "data3": [["C", "1", "3", "4"], ["a", "12"], [11, 1, 1]],
+    });
+
+    let table = json_to_table(&value)
+        .with(Style::extended())
+        .object_orientation(Orientation::Horizontal)
+        .array_orientation(Orientation::Horizontal)
+        .collapse()
+        .to_string();
+
+    assert_eq!(
+        table,
+        concat!(
+            "╔════════════════════════════════╦══════════════════════════════════════════════════════════════╦══════════╦═════════════════════════════════════╗\n",
+            "║ data                           ║ data1                                                        ║ data2    ║ data3                               ║\n",
+            "╠════════════╦══════╦════════╦═══╬═══════╦═══╦═══╦═══╦════════╦════════╦════╦═══╦═══╦═══╦═══╦═══╬═════╦════╬═══╦═══╦═══╦═══╦═══╦════╦════╦═══╦═══╣\n",
+            "║ Click Here ║ asda ║ 123132 ║ 1 ║ Click ║ 1 ║ 3 ║ 4 ║ aa     ║ bb     ║ 11 ║ 1 ║ 1 ║ 1 ║ 1 ║ 1 ║ 11  ║ 22 ║ C ║ 1 ║ 3 ║ 4 ║ a ║ 12 ║ 11 ║ 1 ║ 1 ║\n",
+            "║            ║      ║        ║   ║       ║   ║   ║   ╠════════╬════════╣    ║   ║   ║   ║   ║   ╠═════╬════╣   ║   ║   ║   ║   ║    ║    ║   ║   ║\n",
+            "║            ║      ║        ║   ║       ║   ║   ║   ║ 123132 ║ 123132 ║    ║   ║   ║   ║   ║   ║ x   ║ 1  ║   ║   ║   ║   ║   ║    ║    ║   ║   ║\n",
+            "║            ║      ║        ║   ║       ║   ║   ║   ║        ║        ║    ║   ║   ║   ║   ║   ╠═════╣    ║   ║   ║   ║   ║   ║    ║    ║   ║   ║\n",
+            "║            ║      ║        ║   ║       ║   ║   ║   ║        ║        ║    ║   ║   ║   ║   ║   ║ xxx ║    ║   ║   ║   ║   ║   ║    ║    ║   ║   ║\n",
+            "╚════════════╩══════╩════════╩═══╩═══════╩═══╩═══╩═══╩════════╩════════╩════╩═══╩═══╩═══╩═══╩═══╩═════╩════╩═══╩═══╩═══╩═══╩═══╩════╩════╩═══╩═══╝",
+        )
+    );
+}
+
+#[test]
+fn collapse_object_array_orientation_test_7() {
+    let value = json!({
+        "widget": {
+            "debug": "on",
+            "text": {
+                "data": ["Click Here", "asda", "123132"],
+                "size": 36,
+                "style": "bold",
+                "name": "text1",
+                "hOffset": 250,
+                "vOffset": 100,
+                "alignment": "center",
+                "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
+            }
+        },
+        "123": ["1123", "qwe", "sad"],
+        "2345": {
+            "debug1\ndebug1": "on",
+            "debug2": "on",
+            "text": {
+                "data": ["Click Here", "asda", "123132"],
+                "alignment": ";\n;\n;",
+                "onMouseUp": ";"
+            }
+        },
+        "132456": "1123",
+        "wwwww23": "1123",
+    });
+
+    let table = json_to_table(&value)
+        .with(Style::extended())
+        .object_orientation(Orientation::Horizontal)
+        .array_orientation(Orientation::Horizontal)
+        .collapse()
+        .to_string();
+
+    assert_eq!(
+        table,
+        concat!(
+            "╔══════════════════╦════════╦══════════════════════════════════════════════════════════════════════╦═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╦═════════╗\n",
+            "║ 123              ║ 132456 ║ 2345                                                                 ║ widget                                                                                                                                ║ wwwww23 ║\n",
+            "╠══════╦═════╦═════╬════════╬════════╦════════╦════════════════════════════════════════════════════╬═══════╦═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╬═════════╣\n",
+            "║ 1123 ║ qwe ║ sad ║ 1123   ║ debug1 ║ debug2 ║ text                                               ║ debug ║ text                                                                                                                          ║ 1123    ║\n",
+            "║      ║     ║     ║        ║ debug1 ║        ║                                                    ╠═══════╬═══════════╦════════════════════════════╦═════════╦═══════╦═══════════════════════════════════════════╦══════╦═══════╦═════════╣         ║\n",
+            "║      ║     ║     ║        ╠════════╬════════╬═══════════╦════════════════════════════╦═══════════╣ on    ║ alignment ║ data                       ║ hOffset ║ name  ║ onMouseUp                                 ║ size ║ style ║ vOffset ║         ║\n",
+            "║      ║     ║     ║        ║ on     ║ on     ║ alignment ║ data                       ║ onMouseUp ║       ╠═══════════╬════════════╦══════╦════════╬═════════╬═══════╬═══════════════════════════════════════════╬══════╬═══════╬═════════╣         ║\n",
+            "║      ║     ║     ║        ║        ║        ╠═══════════╬════════════╦══════╦════════╬═══════════╣       ║ center    ║ Click Here ║ asda ║ 123132 ║ 250     ║ text1 ║ sun1.opacity = (sun1.opacity / 100) * 90; ║ 36   ║ bold  ║ 100     ║         ║\n",
+            "║      ║     ║     ║        ║        ║        ║ ;         ║ Click Here ║ asda ║ 123132 ║ ;         ║       ║           ║            ║      ║        ║         ║       ║                                           ║      ║       ║         ║         ║\n",
+            "║      ║     ║     ║        ║        ║        ║ ;         ║            ║      ║        ║           ║       ║           ║            ║      ║        ║         ║       ║                                           ║      ║       ║         ║         ║\n",
+            "║      ║     ║     ║        ║        ║        ║ ;         ║            ║      ║        ║           ║       ║           ║            ║      ║        ║         ║       ║                                           ║      ║       ║         ║         ║\n",
+            "╚══════╩═════╩═════╩════════╩════════╩════════╩═══════════╩════════════╩══════╩════════╩═══════════╩═══════╩═══════════╩════════════╩══════╩════════╩═════════╩═══════╩═══════════════════════════════════════════╩══════╩═══════╩═════════╩═════════╝",
+        )
+    );
+}
+
 // #[test]
 // fn orientation_collapse_test_1() {
 //     let value = json!(
diff --git a/json_to_table/tests/test_table.rs b/json_to_table/tests/test_table.rs
index 24a1f7e..b84b4b6 100644
--- a/json_to_table/tests/test_table.rs
+++ b/json_to_table/tests/test_table.rs
@@ -1,4 +1,4 @@
-use json_to_table::json_to_table;
+use json_to_table::{json_to_table, Orientation};
 use serde_json::json;
 use tabled::settings::Style;
 
@@ -33,9 +33,7 @@ fn general_json_1_test() {
         }}
     );
 
-    let table = json_to_table(&value)
-        .set_style(Style::extended())
-        .to_string();
+    let table = json_to_table(&value).with(Style::extended()).to_string();
 
     assert_eq!(
         table,
@@ -89,7 +87,7 @@ fn general_json_1_test() {
     );
 
     let table = json_to_table(&value)
-        .set_style(Style::extended())
+        .with(Style::extended())
         .collapse()
         .to_string();
 
@@ -164,7 +162,7 @@ fn general_json_2_test() {
         }
     );
 
-    let table = json_to_table(&value).set_style(Style::modern()).to_string();
+    let table = json_to_table(&value).with(Style::modern()).to_string();
 
     assert_eq!(
         table,
@@ -208,7 +206,7 @@ fn general_json_2_test() {
     );
 
     let table = json_to_table(&value)
-        .set_style(Style::modern())
+        .with(Style::modern())
         .collapse()
         .to_string();
 
@@ -274,7 +272,7 @@ fn general_json_3_test() {
         }}
     );
 
-    let table = json_to_table(&value).set_style(Style::modern()).to_string();
+    let table = json_to_table(&value).with(Style::modern()).to_string();
 
     assert_eq!(
         table,
@@ -394,7 +392,7 @@ fn general_json_3_test() {
     );
 
     let table = json_to_table(&value)
-        .set_style(Style::modern())
+        .with(Style::modern())
         .collapse()
         .to_string();
 
@@ -480,15 +478,15 @@ fn general_json_3_test() {
 fn many_splits_bettween_map_entries_test() {
     let value = json!(
         {
-            "menu": { "header": { "header": { "header": "SVG Viewer" } } },
-            "menu2": { "header": { "header": { "header": { "header": { "header": { "header": { "header": "SVG Viewer" } } } } } } },
+            "menu": { "heade1": { "heade2": { "heade3": "SVG Viewer" } } },
+            "menu2": { "heade4": { "heade5": { "heade6": { "header": { "header": { "header": { "header": "SVG Viewer" } } } } } } },
             "menu3": { "he": { "asdd": { "x": { "1": { "header": { "header": { "header": "SVG Viewer" } } } } } } },
             "menu4": { "he": { "asdd": { "xxxx": { "": { "3333": { "2": { "header": "SVG Viewer" } } } } } } },
         }
     );
 
     let table = json_to_table(&value)
-        .set_style(Style::modern())
+        .with(Style::modern())
         .collapse()
         .to_string();
 
@@ -496,9 +494,9 @@ fn many_splits_bettween_map_entries_test() {
         table,
         concat!(
             "┌───────┬────────┬────────┬────────┬────────────────────────────────────────────────┐\n",
-            "│ menu  │ header │ header │ header │ SVG Viewer                                     │\n",
+            "│ menu  │ heade1 │ heade2 │ heade3 │ SVG Viewer                                     │\n",
             "├───────┼────────┼────────┼────────┼────────┬────────┬────────┬────────┬────────────┤\n",
-            "│ menu2 │ header │ header │ header │ header │ header │ header │ header │ SVG Viewer │\n",
+            "│ menu2 │ heade4 │ heade5 │ heade6 │ header │ header │ header │ header │ SVG Viewer │\n",
             "├───────┼────┬───┴──┬───┬─┴─┬──────┴─┬──────┴─┬──────┴─┬──────┴────────┴────────────┤\n",
             "│ menu3 │ he │ asdd │ x │ 1 │ header │ header │ header │ SVG Viewer                 │\n",
             "├───────┼────┼──────┼───┴──┬┴─┬──────┼───┬────┴───┬────┴────────────────────────────┤\n",
@@ -509,30 +507,60 @@ fn many_splits_bettween_map_entries_test() {
 }
 
 #[test]
-fn array_split_test() {
+fn aray_split_test() {
     let value = json!(
         {
-            "menu2": [ { "header": { "header": "SVG Viewer" } }, { "header": { "header": "SVG Viewer" } } ],
-            "menu3": [ { "header": { "header": "SVG Viewer" } }, { "header": { "header": "SVG Viewer" } } ],
+            "menu2": [ { "heade1": { "heade3": "SVG Viewe1" } }, { "heade5": { "heade7": "SVG Viewe9" } } ],
+            "menu3": [ { "heade2": { "heade4": "SVG Viewe2" } }, { "heade6": { "heade8": "SVG View10" } } ],
         }
     );
 
     let table = json_to_table(&value)
-        .set_style(Style::modern())
+        .with(Style::modern())
         .collapse()
         .to_string();
 
+    println!("{table}");
+
     assert_eq!(
         table,
         concat!(
             "┌───────┬────────┬────────┬────────────┐\n",
-            "│ menu2 │ header │ header │ SVG Viewer │\n",
+            "│ menu2 │ heade1 │ heade3 │ SVG Viewe1 │\n",
             "│       ├────────┼────────┼────────────┤\n",
-            "│       │ header │ header │ SVG Viewer │\n",
+            "│       │ heade5 │ heade7 │ SVG Viewe9 │\n",
             "├───────┼────────┼────────┼────────────┤\n",
-            "│ menu3 │ header │ header │ SVG Viewer │\n",
+            "│ menu3 │ heade2 │ heade4 │ SVG Viewe2 │\n",
             "│       ├────────┼────────┼────────────┤\n",
-            "│       │ header │ header │ SVG Viewer │\n",
+            "│       │ heade6 │ heade8 │ SVG View10 │\n",
+            "└───────┴────────┴────────┴────────────┘",
+        )
+    );
+}
+
+#[test]
+fn aray_split_test2() {
+    let value = json!({
+        "menu2": [
+            { "heade1": { "heade3": "SVG Viewe1" } },
+            { "heade5": { "heade7": "SVG Viewe9" } },
+        ],
+    });
+
+    let table = json_to_table(&value)
+        .with(Style::modern())
+        .collapse()
+        .to_string();
+
+    println!("{table}");
+
+    assert_eq!(
+        table,
+        concat!(
+            "┌───────┬────────┬────────┬────────────┐\n",
+            "│ menu2 │ heade1 │ heade3 │ SVG Viewe1 │\n",
+            "│       ├────────┼────────┼────────────┤\n",
+            "│       │ heade5 │ heade7 │ SVG Viewe9 │\n",
             "└───────┴────────┴────────┴────────────┘",
         )
     );
@@ -548,7 +576,7 @@ fn array_split_2_test() {
     );
 
     let table = json_to_table(&value)
-        .set_style(Style::modern())
+        .with(Style::modern())
         .collapse()
         .to_string();
 
@@ -578,7 +606,7 @@ fn array_split_4_test() {
     );
 
     let table = json_to_table(&value)
-        .set_style(Style::modern())
+        .with(Style::modern())
         .collapse()
         .to_string();
 
@@ -609,10 +637,12 @@ fn array_split_3_test() {
     );
 
     let table = json_to_table(&value)
-        .set_style(Style::modern())
+        .with(Style::modern())
         .collapse()
         .to_string();
 
+    println!("{table}");
+
     assert_eq!(
         table,
         concat!(
@@ -639,7 +669,7 @@ fn array_split_with_inner_array_test() {
     );
 
     let table = json_to_table(&value)
-        .set_style(Style::modern())
+        .with(Style::modern())
         .collapse()
         .to_string();
 
@@ -669,7 +699,7 @@ fn array_split_with_inner_array_2_test() {
     );
 
     let table = json_to_table(&value)
-        .set_style(Style::modern())
+        .with(Style::modern())
         .collapse()
         .to_string();
 
@@ -706,7 +736,7 @@ fn test_map_empty_entity_collapsed_0() {
     );
 
     let table = json_to_table(&value)
-        .set_style(Style::modern())
+        .with(Style::modern())
         .collapse()
         .to_string();
 
@@ -741,7 +771,7 @@ fn test_map_empty_entity_collapsed_1() {
     );
 
     let table = json_to_table(&value)
-        .set_style(Style::modern())
+        .with(Style::modern())
         .collapse()
         .to_string();
 
@@ -786,7 +816,7 @@ fn test_map_empty_entity_collapsed_2() {
     );
 
     let table = json_to_table(&value)
-        .set_style(Style::modern())
+        .with(Style::modern())
         .collapse()
         .to_string();
 
@@ -825,7 +855,7 @@ fn test_list_empty_entity_collapsed_0() {
     let value = json!([{}, "field1", {}, "field2", {}]);
 
     let table = json_to_table(&value)
-        .set_style(Style::modern())
+        .with(Style::modern())
         .collapse()
         .to_string();
 
@@ -852,10 +882,12 @@ fn test_list_empty_entity_collapsed_1() {
     let value = json!([{}, {}, {}]);
 
     let table = json_to_table(&value)
-        .set_style(Style::modern())
+        .with(Style::modern())
         .collapse()
         .to_string();
 
+    println!("{table}");
+
     assert_eq!(
         table,
         concat!(
@@ -875,7 +907,7 @@ fn test_list_empty_entity_collapsed_2() {
     let value = json!([[], [], []]);
 
     let table = json_to_table(&value)
-        .set_style(Style::modern())
+        .with(Style::modern())
         .collapse()
         .to_string();
 
@@ -893,6 +925,288 @@ fn test_list_empty_entity_collapsed_2() {
     );
 }
 
+#[test]
+fn test_map_empty_entity_collapsed_1_horizontal() {
+    let value = json!(
+        {
+            "field1" : [],
+            "field2": "Value",
+            "field3" : [],
+            "field4": 3,
+            "field5" : []
+        }
+    );
+
+    let table = json_to_table(&value)
+        .with(Style::modern())
+        .collapse()
+        .array_orientation(Orientation::Horizontal)
+        .to_string();
+
+    assert_eq!(
+        table,
+        concat!(
+            "┌────────┬───────┐\n",
+            "│ field1 │       │\n",
+            "├────────┼───────┤\n",
+            "│ field2 │ Value │\n",
+            "├────────┼───────┤\n",
+            "│ field3 │       │\n",
+            "├────────┼───────┤\n",
+            "│ field4 │ 3     │\n",
+            "├────────┼───────┤\n",
+            "│ field5 │       │\n",
+            "└────────┴───────┘",
+        )
+    );
+}
+
+#[test]
+fn test_map_empty_entity_collapsed_2_horizontal() {
+    let value = json!(
+        {
+            "key0": {},
+            "field1" : {
+                "key1": "value1",
+                "key2": []
+            },
+            "field2": "Value",
+            "field3" : [],
+            "field4": [
+                {},
+                "123",
+                {},
+                "sadas",
+                {}
+            ],
+            "field5" : []
+        }
+    );
+
+    let table = json_to_table(&value)
+        .with(Style::modern())
+        .collapse()
+        .array_orientation(Orientation::Horizontal)
+        .to_string();
+
+    assert_eq!(
+        table,
+        concat!(
+            "┌────────┬──────┬───────────────┐\n",
+            "│ field1 │ key1 │ value1        │\n",
+            "│        ├──────┼───────────────┤\n",
+            "│        │ key2 │               │\n",
+            "├────────┼──────┴───────────────┤\n",
+            "│ field2 │ Value                │\n",
+            "├────────┼──────────────────────┤\n",
+            "│ field3 │                      │\n",
+            "├────────┼──┬─────┬──┬───────┬──┤\n",
+            "│ field4 │  │ 123 │  │ sadas │  │\n",
+            "├────────┼──┴─────┴──┴───────┴──┤\n",
+            "│ field5 │                      │\n",
+            "├────────┼──────────────────────┤\n",
+            "│ key0   │                      │\n",
+            "└────────┴──────────────────────┘",
+        )
+    );
+}
+
+#[test]
+fn test_list_empty_entity_collapsed_0_horizontal() {
+    let value = json!([{}, "field1", {}, "field2", {}]);
+
+    let table = json_to_table(&value)
+        .with(Style::modern())
+        .collapse()
+        .array_orientation(Orientation::Horizontal)
+        .to_string();
+
+    assert_eq!(
+        table,
+        concat!(
+            "┌──┬────────┬──┬────────┬──┐\n",
+            "│  │ field1 │  │ field2 │  │\n",
+            "└──┴────────┴──┴────────┴──┘",
+        )
+    );
+}
+
+#[test]
+fn test_list_empty_entity_collapsed_1_horizontal() {
+    let value = json!([{}, {}, {}]);
+
+    let table = json_to_table(&value)
+        .with(Style::modern())
+        .collapse()
+        .array_orientation(Orientation::Horizontal)
+        .to_string();
+
+    assert_eq!(
+        table,
+        concat!("┌──┬──┬──┐\n", "│  │  │  │\n", "└──┴──┴──┘",)
+    );
+}
+
+#[test]
+fn test_list_empty_entity_collapsed_2_horizontal() {
+    let value = json!([[], [], []]);
+
+    let table = json_to_table(&value)
+        .with(Style::modern())
+        .collapse()
+        .array_orientation(Orientation::Horizontal)
+        .to_string();
+
+    assert_eq!(
+        table,
+        concat!("┌──┬──┬──┐\n", "│  │  │  │\n", "└──┴──┴──┘",)
+    );
+}
+
+#[test]
+fn test_map_empty_entity_collapsed_1_horizontal_map() {
+    let value = json!(
+        {
+            "field1" : [],
+            "field2": "Value",
+            "field3" : [],
+            "field4": 3,
+            "field5" : []
+        }
+    );
+
+    let table = json_to_table(&value)
+        .with(Style::modern())
+        .collapse()
+        .object_orientation(Orientation::Horizontal)
+        .to_string();
+
+    assert_eq!(
+        table,
+        "┌────────┬────────┬────────┬────────┬────────┐\n\
+         │ field1 │ field2 │ field3 │ field4 │ field5 │\n\
+         ├────────┼────────┼────────┼────────┼────────┤\n\
+         │        │ Value  │        │ 3      │        │\n\
+         └────────┴────────┴────────┴────────┴────────┘"
+    );
+}
+
+#[test]
+fn test_map_empty_entity_collapsed_2_horizontal_map() {
+    let value = json!(
+        {
+            "key0": {},
+            "field1" : {
+                "key1": "value1",
+                "key2": []
+            },
+            "field2": "Value",
+            "field3" : [],
+            "field4": [
+                {},
+                "123",
+                {},
+                "sadas",
+                {}
+            ],
+            "field5" : []
+        }
+    );
+
+    let table = json_to_table(&value)
+        .with(Style::modern())
+        .collapse()
+        .object_orientation(Orientation::Horizontal)
+        .to_string();
+
+    assert_eq!(
+        table,
+        "┌───────────────┬────────┬────────┬────────┬────────┬──────┐\n\
+         │ field1        │ field2 │ field3 │ field4 │ field5 │ key0 │\n\
+         ├────────┬──────┼────────┼────────┼────────┼────────┼──────┤\n\
+         │ key1   │ key2 │ Value  │        │        │        │      │\n\
+         ├────────┼──────┤        │        ├────────┤        │      │\n\
+         │ value1 │      │        │        │ 123    │        │      │\n\
+         │        │      │        │        ├────────┤        │      │\n\
+         │        │      │        │        │        │        │      │\n\
+         │        │      │        │        ├────────┤        │      │\n\
+         │        │      │        │        │ sadas  │        │      │\n\
+         │        │      │        │        ├────────┤        │      │\n\
+         │        │      │        │        │        │        │      │\n\
+         └────────┴──────┴────────┴────────┴────────┴────────┴──────┘"
+    );
+}
+
+#[test]
+fn test_list_empty_entity_collapsed_0_horizontal_map() {
+    let value = json!([{}, "field1", {}, "field2", {}]);
+
+    let table = json_to_table(&value)
+        .with(Style::modern())
+        .collapse()
+        .object_orientation(Orientation::Horizontal)
+        .to_string();
+
+    assert_eq!(
+        table,
+        "┌────────┐\n\
+         │        │\n\
+         ├────────┤\n\
+         │ field1 │\n\
+         ├────────┤\n\
+         │        │\n\
+         ├────────┤\n\
+         │ field2 │\n\
+         ├────────┤\n\
+         │        │\n\
+         └────────┘"
+    );
+}
+
+#[test]
+fn test_list_empty_entity_collapsed_1_horizontal_map() {
+    let value = json!([{}, {}, {}]);
+
+    let table = json_to_table(&value)
+        .with(Style::modern())
+        .collapse()
+        .object_orientation(Orientation::Horizontal)
+        .to_string();
+
+    assert_eq!(
+        table,
+        "┌──┐\n\
+         │  │\n\
+         ├──┤\n\
+         │  │\n\
+         ├──┤\n\
+         │  │\n\
+         └──┘"
+    );
+}
+
+#[test]
+fn test_list_empty_entity_collapsed_2_horizontal_map() {
+    let value = json!([[], [], []]);
+
+    let table = json_to_table(&value)
+        .with(Style::modern())
+        .collapse()
+        .object_orientation(Orientation::Horizontal)
+        .to_string();
+
+    assert_eq!(
+        table,
+        "┌──┐\n\
+         │  │\n\
+         ├──┤\n\
+         │  │\n\
+         ├──┤\n\
+         │  │\n\
+         └──┘"
+    );
+}
+
 #[test]
 fn test_map_empty_entity_plain_0() {
     let value = json!(
@@ -905,7 +1219,7 @@ fn test_map_empty_entity_plain_0() {
         }
     );
 
-    let table = json_to_table(&value).set_style(Style::modern()).to_string();
+    let table = json_to_table(&value).with(Style::modern()).to_string();
 
     assert_eq!(
         table,
@@ -929,7 +1243,7 @@ fn test_map_empty_entity_plain_0() {
 fn test_list_empty_entity_plain_0() {
     let value = json!([{}, "field1", {}, "field2", {}]);
 
-    let table = json_to_table(&value).set_style(Style::modern()).to_string();
+    let table = json_to_table(&value).with(Style::modern()).to_string();
 
     assert_eq!(
         table,
@@ -953,7 +1267,7 @@ fn test_list_empty_entity_plain_0() {
 fn test_list_empty_entity_plain_1() {
     let value = json!([[], "field1", [], "field2", []]);
 
-    let table = json_to_table(&value).set_style(Style::modern()).to_string();
+    let table = json_to_table(&value).with(Style::modern()).to_string();
 
     assert_eq!(
         table,
@@ -977,7 +1291,7 @@ fn test_list_empty_entity_plain_1() {
 fn test_list_empty_entity_plain_2() {
     let value = json!([{}, {}, {}]);
 
-    let table = json_to_table(&value).set_style(Style::modern()).to_string();
+    let table = json_to_table(&value).with(Style::modern()).to_string();
 
     assert_eq!(
         table,
@@ -1000,7 +1314,7 @@ fn test_multiline_key_height_bigger_then_value() {
     });
 
     let table = json_to_table(&value)
-        .set_style(Style::modern())
+        .with(Style::modern())
         .collapse()
         .to_string();
 
@@ -1027,10 +1341,12 @@ fn test_multiline_key_height_less_then_value() {
     });
 
     let table = json_to_table(&value)
-        .set_style(Style::modern())
+        .with(Style::modern())
         .collapse()
         .to_string();
 
+    println!("{table}");
+
     assert_eq!(
         table,
         concat!(
diff --git a/json_to_table/tests/test_types.rs b/json_to_table/tests/test_types.rs
index d373580..4d9a007 100644
--- a/json_to_table/tests/test_types.rs
+++ b/json_to_table/tests/test_types.rs
@@ -5,7 +5,7 @@ use tabled::settings::Style;
 #[test]
 fn string_test() {
     let value = json!("Some text string");
-    let table = json_to_table(&value).set_style(Style::modern()).to_string();
+    let table = json_to_table(&value).with(Style::modern()).to_string();
 
     assert_eq!(
         table,
@@ -20,7 +20,7 @@ fn string_test() {
 #[test]
 fn string_multiline_test() {
     let value = json!("Some text string\ntext on a new line\nmore text\nand a new line");
-    let table = json_to_table(&value).set_style(Style::modern()).to_string();
+    let table = json_to_table(&value).with(Style::modern()).to_string();
 
     assert_eq!(
         table,
@@ -35,7 +35,7 @@ fn string_multiline_test() {
     );
 
     let value = json!("Some text string\ntext on a new line\nmore text\nand a new line\n");
-    let table = json_to_table(&value).set_style(Style::modern()).to_string();
+    let table = json_to_table(&value).with(Style::modern()).to_string();
 
     assert_eq!(
         table,
@@ -54,7 +54,7 @@ fn string_multiline_test() {
 #[test]
 fn number_test() {
     let value = json!(123.2);
-    let table = json_to_table(&value).set_style(Style::modern()).to_string();
+    let table = json_to_table(&value).with(Style::modern()).to_string();
 
     assert_eq!(
         table,
@@ -64,7 +64,7 @@ fn number_test() {
     );
 
     let value = json!(123);
-    let table = json_to_table(&value).set_style(Style::modern()).to_string();
+    let table = json_to_table(&value).with(Style::modern()).to_string();
 
     assert_eq!(
         table,
@@ -77,14 +77,14 @@ fn number_test() {
 #[test]
 fn null_test() {
     let value = json!(null);
-    let table = json_to_table(&value).set_style(Style::modern()).to_string();
+    let table = json_to_table(&value).with(Style::modern()).to_string();
     assert_eq!(table, "");
 }
 
 #[test]
 fn list_test() {
     let value = json!(["Hello", "World", "123"]);
-    let table = json_to_table(&value).set_style(Style::modern()).to_string();
+    let table = json_to_table(&value).with(Style::modern()).to_string();
 
     assert_eq!(
         table,
@@ -100,7 +100,7 @@ fn list_test() {
     );
 
     let value = json!([{"key": "Hello"}, {"1": "2", "2": "3", "4": "5"}, 123.222229]);
-    let table = json_to_table(&value).set_style(Style::modern()).to_string();
+    let table = json_to_table(&value).with(Style::modern()).to_string();
 
     assert_eq!(
         table,
@@ -127,7 +127,7 @@ fn list_test() {
 #[test]
 fn object_test() {
     let value = json!({"message": "Hello World", "code": "123"});
-    let table = json_to_table(&value).set_style(Style::modern()).to_string();
+    let table = json_to_table(&value).with(Style::modern()).to_string();
 
     assert_eq!(
         table,
@@ -142,7 +142,7 @@ fn object_test() {
 
     let value =
         json!({"message": {"real": "Hello World", "cypher": "2132132"}, "code": ["123", "213"]});
-    let table = json_to_table(&value).set_style(Style::modern()).to_string();
+    let table = json_to_table(&value).with(Style::modern()).to_string();
 
     assert_eq!(
         table,
@@ -171,16 +171,16 @@ mod squashed {
     fn string_test() {
         let value = json!("Some text string");
 
-        let table = json_to_table(&value).set_style(Style::modern()).to_string();
+        let table = json_to_table(&value).with(Style::modern()).to_string();
         let table_squashed = json_to_table(&value)
-            .set_style(Style::modern())
+            .with(Style::modern())
             .collapse()
             .to_string();
 
         assert_eq!(table, table_squashed);
 
         let table = json_to_table(&json!(""))
-            .set_style(Style::modern())
+            .with(Style::modern())
             .collapse()
             .to_string();
 
@@ -191,9 +191,9 @@ mod squashed {
     fn string_multiline_test() {
         let value = json!("Some text string\ntext on a new line\nmore text\nand a new line");
 
-        let table = json_to_table(&value).set_style(Style::modern()).to_string();
+        let table = json_to_table(&value).with(Style::modern()).to_string();
         let table_squashed = json_to_table(&value)
-            .set_style(Style::modern())
+            .with(Style::modern())
             .collapse()
             .to_string();
 
@@ -201,9 +201,9 @@ mod squashed {
 
         let value = json!("Some text string\ntext on a new line\nmore text\nand a new line\n");
 
-        let table = json_to_table(&value).set_style(Style::modern()).to_string();
+        let table = json_to_table(&value).with(Style::modern()).to_string();
         let table_squashed = json_to_table(&value)
-            .set_style(Style::modern())
+            .with(Style::modern())
             .collapse()
             .to_string();
 
@@ -214,9 +214,9 @@ mod squashed {
     fn number_test() {
         let value = json!(123.2);
 
-        let table = json_to_table(&value).set_style(Style::modern()).to_string();
+        let table = json_to_table(&value).with(Style::modern()).to_string();
         let table_squashed = json_to_table(&value)
-            .set_style(Style::modern())
+            .with(Style::modern())
             .collapse()
             .to_string();
 
@@ -224,9 +224,9 @@ mod squashed {
 
         let value = json!(123);
 
-        let table = json_to_table(&value).set_style(Style::modern()).to_string();
+        let table = json_to_table(&value).with(Style::modern()).to_string();
         let table_squashed = json_to_table(&value)
-            .set_style(Style::modern())
+            .with(Style::modern())
             .collapse()
             .to_string();
 
@@ -237,7 +237,7 @@ mod squashed {
     fn null_test() {
         let value = json!(null);
         let table_squashed = json_to_table(&value)
-            .set_style(Style::modern())
+            .with(Style::modern())
             .collapse()
             .to_string();
 
@@ -253,7 +253,7 @@ mod squashed {
     fn list_test() {
         let value = json!(["Hello", "World", "123"]);
         let table = json_to_table(&value)
-            .set_style(Style::modern())
+            .with(Style::modern())
             .collapse()
             .to_string();
 
@@ -272,7 +272,7 @@ mod squashed {
 
         let value = json!([{"key": "Hello"}, {"1": "2", "2": "3", "4": "5"}, 123.222229]);
         let table = json_to_table(&value)
-            .set_style(Style::modern())
+            .with(Style::modern())
             .collapse()
             .to_string();
 
@@ -295,7 +295,7 @@ mod squashed {
 
         let value = json!([]);
         let table = json_to_table(&value)
-            .set_style(Style::modern())
+            .with(Style::modern())
             .collapse()
             .to_string();
 
@@ -306,7 +306,7 @@ mod squashed {
     fn object_test() {
         let value = json!({"message": "Hello World", "code": "123"});
         let table = json_to_table(&value)
-            .set_style(Style::modern())
+            .with(Style::modern())
             .collapse()
             .to_string();
 
@@ -323,7 +323,7 @@ mod squashed {
 
         let value = json!({"message": {"real": "Hello World", "cypher": "2132132"}, "code": ["123", "213"]});
         let table = json_to_table(&value)
-            .set_style(Style::modern())
+            .with(Style::modern())
             .collapse()
             .to_string();
 
@@ -344,7 +344,7 @@ mod squashed {
 
         let value = json!({});
         let table = json_to_table(&value)
-            .set_style(Style::modern())
+            .with(Style::modern())
             .collapse()
             .to_string();
 
diff --git a/tabled/tests/pool_table.rs b/tabled/tests/pool_table.rs
new file mode 100644
index 0000000..3417f6c
--- /dev/null
+++ b/tabled/tests/pool_table.rs
@@ -0,0 +1,396 @@
+#![cfg(feature = "std")]
+
+mod util;
+
+use tabled::{
+    settings::{Alignment, Margin, Padding, Style},
+    tables::{PoolTable, TableValue},
+};
+use util::{create_matrix, test_table};
+
+test_table!(
+    pool_table,
+    PoolTable::new(create_matrix::<3, 3>()),
+    "+-----+-----+-----+"
+    "| 0-0 | 0-1 | 0-2 |"
+    "+-----+-----+-----+"
+    "| 1-0 | 1-1 | 1-2 |"
+    "+-----+-----+-----+"
+    "| 2-0 | 2-1 | 2-2 |"
+    "+-----+-----+-----+"
+);
+
+test_table!(
+    pool_table_1,
+    PoolTable::new([vec!["111111", "222"], vec!["111", "2233", "1", "2", "3"]]),
+    "+-------------+----------+"
+    "| 111111      | 222      |"
+    "+-----+------++--+---+---+"
+    "| 111 | 2233 | 1 | 2 | 3 |"
+    "+-----+------+---+---+---+"
+);
+
+test_table!(
+    pool_table_2,
+    PoolTable::new([vec!["111", "2233", "1", "2", "3"], vec!["111111", "222"]]),
+    "+-----+------+---+---+---+"
+    "| 111 | 2233 | 1 | 2 | 3 |"
+    "+-----+------++--+---+---+"
+    "| 111111      | 222      |"
+    "+-------------+----------+"
+);
+
+test_table!(
+    pool_table_3,
+    PoolTable::new([vec!["1\n11", "2\n2\n3\n3", "1", "\n2\n", "3"], vec!["11\n111\n1", "2\n2\n2"]]),
+    "+----+---+---+---+---+"
+    "| 1  | 2 | 1 |   | 3 |"
+    "| 11 | 2 |   | 2 |   |"
+    "|    | 3 |   |   |   |"
+    "|    | 3 |   |   |   |"
+    "+----+---+--++---+---+"
+    "| 11        | 2      |"
+    "| 111       | 2      |"
+    "| 1         | 2      |"
+    "+-----------+--------+"
+);
+
+test_table!(
+    pool_table_4,
+    PoolTable::new([vec!["11\n111\n1", "2\n2\n2"], vec!["1\n11", "2\n2\n3\n3", "1", "\n2\n", "3"]]),
+    "+-----------+--------+"
+    "| 11        | 2      |"
+    "| 111       | 2      |"
+    "| 1         | 2      |"
+    "+----+---+--++---+---+"
+    "| 1  | 2 | 1 |   | 3 |"
+    "| 11 | 2 |   | 2 |   |"
+    "|    | 3 |   |   |   |"
+    "|    | 3 |   |   |   |"
+    "+----+---+---+---+---+"
+);
+
+test_table!(
+    pool_table_multiline,
+    PoolTable::new([
+        ["1", "2\n2", "3\n3\n3"],
+        ["3\n3\n3", "2\n2", "1"],
+        ["1", "3\n3\n3", "2\n2"]
+    ]),
+    "+---+---+---+"
+    "| 1 | 2 | 3 |"
+    "|   | 2 | 3 |"
+    "|   |   | 3 |"
+    "+---+---+---+"
+    "| 3 | 2 | 1 |"
+    "| 3 | 2 |   |"
+    "| 3 |   |   |"
+    "+---+---+---+"
+    "| 1 | 3 | 2 |"
+    "|   | 3 | 2 |"
+    "|   | 3 |   |"
+    "+---+---+---+"
+);
+
+test_table!(
+    pool_table_value,
+    PoolTable::from(TableValue::Row(vec![
+        TableValue::Column(vec![TableValue::Cell(String::from("0-0")), TableValue::Cell(String::from("0-1")), TableValue::Cell(String::from("0-2"))]),
+        TableValue::Column(vec![TableValue::Cell(String::from("1-0")), TableValue::Cell(String::from("1-1")), TableValue::Cell(String::from("1-2"))]),
+        TableValue::Column(vec![TableValue::Cell(String::from("2-0")), TableValue::Cell(String::from("2-1")), TableValue::Cell(String::from("2-2"))]),
+    ]))
+    .with(Style::modern()),
+    "┌─────┬─────┬─────┐"
+    "│ 0-0 │ 1-0 │ 2-0 │"
+    "├─────┼─────┼─────┤"
+    "│ 0-1 │ 1-1 │ 2-1 │"
+    "├─────┼─────┼─────┤"
+    "│ 0-2 │ 1-2 │ 2-2 │"
+    "└─────┴─────┴─────┘"
+);
+
+test_table!(
+    pool_table_value_1,
+    PoolTable::from(TableValue::Row(vec![
+        TableValue::Column(vec![TableValue::Cell(String::from("0-0")), TableValue::Cell(String::from("0-1")), TableValue::Cell(String::from("0-2"))]),
+        TableValue::Column(vec![TableValue::Cell(String::from("1-0")), TableValue::Cell(String::from("1-1")), TableValue::Cell(String::from("1-2"))]),
+        TableValue::Column(vec![
+            TableValue::Column(vec![TableValue::Cell(String::from("2-01")), TableValue::Cell(String::from("2-02")), TableValue::Cell(String::from("2-03"))]),
+            TableValue::Cell(String::from("2-1")),
+            TableValue::Cell(String::from("2-2")),
+        ]),
+    ]))
+    .with(Style::modern()),
+    "┌─────┬─────┬──────┐"
+    "│ 0-0 │ 1-0 │ 2-01 │"
+    "│     │     ├──────┤"
+    "│     │     │ 2-02 │"
+    "├─────┼─────┼──────┤"
+    "│ 0-1 │ 1-1 │ 2-03 │"
+    "│     │     ├──────┤"
+    "├─────┼─────┤ 2-1  │"
+    "│ 0-2 │ 1-2 ├──────┤"
+    "│     │     │ 2-2  │"
+    "└─────┴─────┴──────┘"
+);
+
+test_table!(
+    pool_table_value_2,
+    PoolTable::from(TableValue::Row(vec![
+        TableValue::Column(vec![TableValue::Cell(String::from("0-0")), TableValue::Cell(String::from("0-1")), TableValue::Cell(String::from("0-2"))]),
+        TableValue::Column(vec![
+            TableValue::Row(vec![TableValue::Cell(String::from("2-01")), TableValue::Cell(String::from("2-02")), TableValue::Cell(String::from("2-03"))]),
+            TableValue::Column(vec![TableValue::Cell(String::from("2-01")), TableValue::Cell(String::from("2-02")), TableValue::Cell(String::from("2-03"))]),
+            TableValue::Cell(String::from("1-1")),
+            TableValue::Cell(String::from("1-2"))
+        ]),
+        TableValue::Column(vec![
+            TableValue::Column(vec![TableValue::Cell(String::from("2-01")), TableValue::Cell(String::from("2-02")), TableValue::Cell(String::from("2-03"))]),
+            TableValue::Cell(String::from("2-1")),
+            TableValue::Cell(String::from("2-2"))
+        ]),
+    ]))
+    .with(Style::modern()),
+    "┌─────┬──────┬──────┬──────┬──────┐"
+    "│ 0-0 │ 2-01 │ 2-02 │ 2-03 │ 2-01 │"
+    "│     ├──────┴──────┴──────┤      │"
+    "│     │ 2-01               │      │"
+    "├─────┼────────────────────┼──────┤"
+    "│ 0-1 │ 2-02               │ 2-02 │"
+    "│     ├────────────────────┼──────┤"
+    "│     │ 2-03               │ 2-03 │"
+    "├─────┼────────────────────┼──────┤"
+    "│ 0-2 │ 1-1                │ 2-1  │"
+    "│     ├────────────────────┼──────┤"
+    "│     │ 1-2                │ 2-2  │"
+    "└─────┴────────────────────┴──────┘"
+);
+
+test_table!(
+    pool_table_value_3,
+    PoolTable::from(TableValue::Row(vec![
+        TableValue::Column(vec![TableValue::Cell(String::from("0-0")), TableValue::Cell(String::from("0-1")), TableValue::Cell(String::from("0-2"))]),
+        TableValue::Column(vec![
+            TableValue::Row(vec![TableValue::Cell(String::from("2-01")), TableValue::Cell(String::from("2-02")), TableValue::Cell(String::from("2-03"))]),
+            TableValue::Column(vec![TableValue::Cell(String::from("2-01")), TableValue::Cell(String::from("2-02")), TableValue::Cell(String::from("2-03"))]),
+            TableValue::Cell(String::from("1-1")),
+            TableValue::Row(vec![TableValue::Cell(String::from("2-01")), TableValue::Cell(String::from("2-02")), TableValue::Cell(String::from("2-03"))]),
+            TableValue::Cell(String::from("1-2"))
+        ]),
+        TableValue::Column(vec![
+            TableValue::Column(vec![TableValue::Cell(String::from("2-\n0\n1")), TableValue::Cell(String::from("2\n-\n0\n2")), TableValue::Cell(String::from("2-03"))]),
+            TableValue::Cell(String::from("2-1")),
+            TableValue::Column(vec![TableValue::Cell(String::from("2-0\n1")), TableValue::Cell(String::from("2-02")), TableValue::Cell(String::from("2-03"))]),
+            TableValue::Cell(String::from("2-2"))
+        ]),
+    ]))
+    .with(Style::modern()),
+    "┌─────┬──────┬──────┬──────┬──────┐"
+    "│ 0-0 │ 2-01 │ 2-02 │ 2-03 │ 2-   │"
+    "│     │      │      │      │ 0    │"
+    "│     │      │      │      │ 1    │"
+    "│     │      │      │      ├──────┤"
+    "│     │      │      │      │ 2    │"
+    "│     ├──────┴──────┴──────┤ -    │"
+    "│     │ 2-01               │ 0    │"
+    "├─────┤                    │ 2    │"
+    "│ 0-1 ├────────────────────┼──────┤"
+    "│     │ 2-02               │ 2-03 │"
+    "│     ├────────────────────┼──────┤"
+    "│     │ 2-03               │ 2-1  │"
+    "│     ├────────────────────┼──────┤"
+    "│     │ 1-1                │ 2-0  │"
+    "├─────┤                    │ 1    │"
+    "│ 0-2 ├──────┬──────┬──────┼──────┤"
+    "│     │ 2-01 │ 2-02 │ 2-03 │ 2-02 │"
+    "│     │      │      │      ├──────┤"
+    "│     ├──────┴──────┴──────┤ 2-03 │"
+    "│     │ 1-2                ├──────┤"
+    "│     │                    │ 2-2  │"
+    "└─────┴────────────────────┴──────┘"
+);
+
+test_table!(
+    pool_table_value_empty_row,
+    PoolTable::from(TableValue::Row(vec![]))
+    .with(Style::modern()),
+    "┌──┐"
+    "│  │"
+    "└──┘"
+);
+
+test_table!(
+    pool_table_value_empty_column,
+    PoolTable::from(TableValue::Column(vec![]))
+    .with(Style::modern()),
+    "┌──┐"
+    "│  │"
+    "└──┘"
+);
+
+test_table!(
+    pool_table_value_empty_cell,
+    PoolTable::from(TableValue::Cell(String::from("")))
+    .with(Style::modern()),
+    "┌──┐"
+    "│  │"
+    "└──┘"
+);
+
+test_table!(
+    pool_table_padding,
+    PoolTable::new(create_matrix::<3, 3>()).with(Padding::new(1, 2, 3, 4)),
+    "+------+------+------+"
+    "|      |      |      |"
+    "|      |      |      |"
+    "|      |      |      |"
+    "| 0-0  | 0-1  | 0-2  |"
+    "|      |      |      |"
+    "|      |      |      |"
+    "|      |      |      |"
+    "|      |      |      |"
+    "+------+------+------+"
+    "|      |      |      |"
+    "|      |      |      |"
+    "|      |      |      |"
+    "| 1-0  | 1-1  | 1-2  |"
+    "|      |      |      |"
+    "|      |      |      |"
+    "|      |      |      |"
+    "|      |      |      |"
+    "+------+------+------+"
+    "|      |      |      |"
+    "|      |      |      |"
+    "|      |      |      |"
+    "| 2-0  | 2-1  | 2-2  |"
+    "|      |      |      |"
+    "|      |      |      |"
+    "|      |      |      |"
+    "|      |      |      |"
+    "+------+------+------+"
+);
+
+test_table!(
+    pool_table_margin,
+    PoolTable::new(create_matrix::<3, 3>()).with(Margin::new(1, 2, 3, 4)),
+    "                            "
+    "                            "
+    "                            "
+    " +-----   +-----   +-----+  "
+    " | 0-0    | 0-1    | 0-2 |  "
+    "                            "
+    "                            "
+    "                            "
+    "                            "
+    "                            "
+    "                            "
+    "                            "
+    " +-----   +-----   +-----+  "
+    " | 1-0    | 1-1    | 1-2 |  "
+    "                            "
+    "                            "
+    "                            "
+    "                            "
+    "                            "
+    "                            "
+    "                            "
+    " +-----   +-----   +-----+  "
+    " | 2-0    | 2-1    | 2-2 |  "
+    " +-----   +-----   +-----+  "
+    "                            "
+    "                            "
+    "                            "
+    "                            "
+);
+
+test_table!(
+    pool_table_alignment_bottom,
+    PoolTable::new([
+        ["1", "2\n2", "3\n3\n3"],
+        ["3\n3\n3", "2\n2", "1"],
+        ["1", "3\n3\n3", "2\n2"]
+    ])
+    .with(Alignment::bottom()),
+    "+---+---+---+"
+    "|   |   | 3 |"
+    "|   | 2 | 3 |"
+    "| 1 | 2 | 3 |"
+    "+---+---+---+"
+    "| 3 |   |   |"
+    "| 3 | 2 |   |"
+    "| 3 | 2 | 1 |"
+    "+---+---+---+"
+    "|   | 3 |   |"
+    "|   | 3 | 2 |"
+    "| 1 | 3 | 2 |"
+    "+---+---+---+"
+);
+
+test_table!(
+    pool_table_alignment_center_vertical,
+    PoolTable::new([
+        ["1", "2\n2", "3\n3\n3"],
+        ["3\n3\n3", "2\n2", "1"],
+        ["1", "3\n3\n3", "2\n2"]
+    ])
+    .with(Alignment::center_vertical()),
+    "+---+---+---+"
+    "|   | 2 | 3 |"
+    "| 1 | 2 | 3 |"
+    "|   |   | 3 |"
+    "+---+---+---+"
+    "| 3 | 2 |   |"
+    "| 3 | 2 | 1 |"
+    "| 3 |   |   |"
+    "+---+---+---+"
+    "|   | 3 | 2 |"
+    "| 1 | 3 | 2 |"
+    "|   | 3 |   |"
+    "+---+---+---+"
+);
+
+test_table!(
+    pool_table_alignment_right,
+    PoolTable::new([
+        ["1                     ", "2\n2       ", "3\n3\n3"],
+        ["3\n3\n3", "2\n2", "1"],
+        ["1", "3\n3\n3                   ", "2\n2"]
+    ])
+    .with(Alignment::right()),
+    "+------------------------+----------+---+"
+    "| 1                      |        2 | 3 |"
+    "|                        | 2        | 3 |"
+    "|                        |          | 3 |"
+    "+-------------+----------+-+--------+---+"
+    "|           3 |          2 |          1 |"
+    "|           3 |          2 |            |"
+    "|           3 |            |            |"
+    "+------+------+------------+-----+------+"
+    "|    1 |                       3 |    2 |"
+    "|      |                       3 |    2 |"
+    "|      |    3                    |      |"
+    "+------+-------------------------+------+"
+);
+
+test_table!(
+    pool_table_alignment_center_horizontal,
+    PoolTable::new([
+        ["1                     ", "2\n2       ", "3\n3\n3"],
+        ["3\n3\n3", "2\n2", "1"],
+        ["1", "3\n3\n3                   ", "2\n2"]
+    ])
+    .with(Alignment::center()),
+    "+------------------------+----------+---+"
+    "| 1                      |    2     | 3 |"
+    "|                        | 2        | 3 |"
+    "|                        |          | 3 |"
+    "+-------------+----------+-+--------+---+"
+    "|      3      |     2      |     1      |"
+    "|      3      |     2      |            |"
+    "|      3      |            |            |"
+    "+------+------+------------+-----+------+"
+    "|  1   |            3            |  2   |"
+    "|      |            3            |  2   |"
+    "|      |  3                      |      |"
+    "+------+-------------------------+------+"
+);