File: nested_table.rs

package info (click to toggle)
rustc-web 1.85.0%2Bdfsg3-1~deb12u3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bookworm-proposed-updates
  • size: 1,759,988 kB
  • sloc: xml: 158,127; python: 35,830; javascript: 19,497; cpp: 19,002; sh: 17,245; ansic: 13,127; asm: 4,376; makefile: 1,056; lisp: 29; perl: 29; ruby: 19; sql: 11
file content (119 lines) | stat: -rw-r--r-- 3,526 bytes parent folder | download | duplicates (16)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
//! This example demonstrates how [`Tables`](Table) can be comprised of other tables.
//!
//! * This first nested [`Table`] example showcases the [`Builder`] approach.
//!
//! * Note how a great deal of manual customizations have been applied to create a
//! highly unique display.
//!
//! * 🎉 Inspired by https://github.com/p-ranav/tabulate#nested-tables/

use std::iter::FromIterator;

use tabled::{
    builder::Builder,
    settings::{
        object::{Rows, Segment},
        style::{HorizontalLine, Style},
        Alignment, Modify, Padding, Width,
    },
    Table,
};

fn main() {
    let animal = create_class(
        "Animal",
        &[("age", "Int", ""), ("gender", "String", "")],
        &["isMammal", "mate"],
    );

    let duck = create_class(
        "Duck",
        &[("beakColor", "String", "yellow")],
        &["swim", "quack"],
    );

    let data = [
        [animal.to_string()],
        [String::from("â–²")],
        [String::from("|")],
        [String::from("|")],
        [duck.to_string()],
    ];

    let mut table = Builder::from_iter(data).build();

    table
        .with(Style::ascii().remove_horizontal())
        .with(Padding::new(5, 5, 0, 0))
        .with(Alignment::center());

    println!("{table}");
}

fn create_class(name: &str, fields: &[(&str, &str, &str)], methods: &[&str]) -> Table {
    let fields = fields
        .iter()
        .map(|(field, t, d)| [format_field(field, t, d)]);
    let mut table_fields = Builder::from_iter(fields).build();
    table_fields.with(Style::ascii().remove_horizontal().remove_vertical());

    let methods = methods.iter().map(|method| [format_method(method)]);
    let mut table_methods = Builder::from_iter(methods).build();
    table_methods.with(Style::ascii().remove_horizontal().remove_vertical());

    let (table_fields, table_methods) = make_equal_width(table_fields, table_methods);

    let data = [
        [name.to_string()],
        [table_fields.to_string()],
        [table_methods.to_string()],
    ];

    let mut table = Builder::from_iter(data).build();

    let style = Style::ascii()
        .horizontals([(1, HorizontalLine::inherit(Style::ascii()))])
        .remove_horizontal()
        .remove_vertical();

    table
        .with(style)
        .with(Modify::new(Segment::all()).with(Alignment::left()))
        .with(Modify::new(Rows::first()).with(Alignment::center()));

    table
}

fn format_field(field: &&str, field_type: &&str, default_value: &&str) -> String {
    if default_value.is_empty() {
        format!("+{field}: {field_type}")
    } else {
        format!("+{field}: {field_type} = {default_value:?}")
    }
}

fn format_method(method: &str) -> String {
    format!("+{method}()")
}

fn make_equal_width(mut table1: Table, mut table2: Table) -> (Table, Table) {
    // We want to make a fields table and methods table to have the same width.
    // To not set it to constant, we check a width of each of them and correct the other.
    //
    // it's safe to do .len() because we use ascii theme and no colors.

    let table1_width = table1.to_string().lines().next().unwrap().len();
    let table2_width = table2.to_string().lines().next().unwrap().len();

    match table1_width.cmp(&table2_width) {
        std::cmp::Ordering::Less => {
            table1.with(Width::increase(table2_width));
        }
        std::cmp::Ordering::Greater => {
            table2.with(Width::increase(table1_width));
        }
        std::cmp::Ordering::Equal => (),
    }

    (table1, table2)
}