tabled

repository·master·Indexed 25 days ago

https://github.com/zhiburt/tabled

A Rust library for pretty-printing tables of structs and enums. It supports a Tabled trait for typed data, a Builder pattern for dynamic schemas, and various styles including ASCII, modern, and markdown. The ecosystem includes csv_to_table for CSV conversion, json_to_table for JSON values, and papergrid for low-level, highly customizable table generation with fine-grained control over cell spanning and alignment.

Tokens
47.6K
Snippets
144
Records
236
Agent score
80%

What's inside tabled

  1. Overview of tabled

    master
    tabled is an easy-to-use Rust library for pretty-printing tables of structs and enums. It provides multiple ways to render data, including a builder pattern for dynamic schemas and a Tabled trait for known, typed data structures. The library supports various styles (ASCII, modern, markdown, etc.), alignment, padding, and advanced features like merging cells, spanning, and exporting to formats like JSON, CSV, and HTML.
  2. Overview of `testing_table` macros

    master

    The testing_table library provides a suite of macros designed to simplify testing and defining tables in Rust using ASCII art representations:

    • test_table!: Generates a test function comparing a table object to an ASCII string.
    • static_table!: Defines a table from an ASCII string.
    • assert_table!: Asserts that a table object matches an ASCII string.
    • assert_width!: (Available in the library) Asserts the width of a table.
  3. Use papergrid for low-level pretty table generation

    master
    papergrid is a low-level library for creating highly customizable, pretty tables in Rust. It provides fine-grained control over cell spanning, alignment, borders, and padding. If you require a more user-friendly, high-level API, consider using the tabled crate instead.
  4. High-performance table rendering with IterTable and CompactTable

    master
    For scenarios where you need to perform table rendering very quickly with minimal memory footprint, consider using IterTable or CompactTable instead of the standard Table type.
  5. Compare and choose between different Table types

    master

    The tabled library provides several table representations depending on your memory constraints, data structure, and desired layout:

    • Table: The main implementation. Requires all data to be stored on the heap.
    • IterTable: Similar to Table but does not buffer all data. It only buffers one row at a time, making it suitable for datasets that do not fit in memory. It uses a .sniff(n) method to estimate layout based on $n$ rows.
    • CompactTable: A zero-allocation table type that does not use any buffer. It is the only type that supports no-std environments. Because it doesn't buffer, you must manually estimate column widths using .width([...]) and specify .rows(n) and .columns(n).
    • PoolTable: Used for diverse, non-aligned layouts where columns do not need to be strictly aligned.
    • ExtendedTable: Best for data structures with many fields. It renders data in a record-based format (vertical) rather than a standard grid.
    • Table::kv: A special layout for the standard Table that represents data as Key-Value pairs (vertical orientation per record).
  6. How CSV to table conversion approaches work

    master

    The library provides two primary mental models for handling CSV data:

    1. In-memory approach: Uses csv_to_table::from_reader. It loads the CSV into memory to construct a full table. This is best for smaller datasets where you want complete, non-truncated output.
    2. Sniffing approach: Uses csv_to_table::iter::from_reader(...).sniff(constraints). This approach limits memory usage by processing the CSV with constraints. It is ideal for very large files, but be aware that it may truncate data to stay within the specified limits.
  7. Select cell subgroups using Object methods

    master

    You can target specific subgroups of cells for modifications (like styling or alignment) using and and not methods on Object types.

    Common selection patterns:

    • Segment::all().not(Rows::first()): Select all cells except the header.
    • Columns::first().and(Columns::last()): Select cells from the first and last columns.
    • Rows::first().and(Columns::one(0)).not(Cell(0, 0)): Select the header and first column, excluding the specific cell at (0, 0).
    • ByColumnName::new("name"): Target a column by its string name.
  8. How ron_to_table modes and options work

    master

    ron_to_table provides two primary modes for rendering RON data as tables:

    1. Embedded Mode: Nested structures are rendered as tables inside the cells of the parent table.
    2. Collapsed Mode: Uses the .collapse() method on the RonTable builder to create a flattened, more compact view.

    Customization

    Because ron_to_table uses tabled as its rendering backend, you can modify the table appearance using tabled settings.

    • Orientation: You can change the orientation of map and sequence types via the Orientation type.
    • Tabled Settings: Use the .with() method on the RonTable builder to apply tabled configurations such as Style, alignment, and padding.
  9. Use Theme for dynamic style changes

    master

    Theme can be used interchangeably with Style, but it is more convenient if you need to change styles dynamically. You can create a Theme from an existing Style and then modify its properties, such as removing specific borders.

    use tabled::settings::{Style, Theme};
    
    let mut theme = Theme::from_style(Style::ascii_rounded());
    theme.remove_borders_horizontal();
    theme.remove_borders_vertical();
    
    table.with(theme);
  10. Dependency management and Semver notes

    master

    tabled follows strict Semver principles: any breaking change is released as a major version bump.

    Warning: The library occasionally introduces breaking changes in minor version bumps. To avoid unexpected breakage, it is recommended to depend on a specific version (e.g., =0.8.0) rather than a minor version range (e.g., 0.7).

    Changes to the Minimum Supported Rust Version (MSRV) are also treated as breaking changes.

  11. Format fields using `display`

    master

    If a field does not implement Display (e.g., an Option<T>), you can specify a custom display function using #[tabled(display = "func")].

    Function Signatures

    • Simple function: fn(&Type) -> String
    • Function with arguments: #[tabled(display("func_name", arg1, arg2, self))]. You can pass specific values or self to the function.

    Global Type Formatting

    You can apply a display function to all fields of a specific type within a struct using #[tabled(display(Type, "func", "default"))] to reduce boilerplate.

    use tabled::Tabled;
    
    // Example 1: Simple display function
    #[derive(Tabled)]
    pub struct Record {
        pub id: i64,
        #[tabled(display = "display_option")]
        pub valid: Option<bool>
    }
    
    fn display_option(o: &Option<bool>) -> String {
        match o {
            Some(s) => format!("is valid thing = {}", s),
            None => format!("is not valid"),
        }
    }
    
    // Example 2: Using self and arguments
    #[derive(Tabled)]
    pub struct RecordWithArgs {
        pub id: i64,
        #[tabled(display("Self::display_valid", self, 1))]
        pub valid: Option<bool>
    }
    
    impl RecordWithArgs {
        fn display_valid(&self, arg: usize) -> String {
            match self.valid {
                Some(s) => format!("is valid thing = {} {}", s, arg),
                None => format!("is not valid {}", arg),
            }
        }
    }
    
    // Example 3: Applying to all fields of a specific type
    #[derive(Tabled)]
    #[tabled(display(Option, "tabled::derive::display::option", "undefined"))]
    pub struct RecordBulk {
        pub id: i64,
        pub name: Option<String>,
        pub birthdate: Option<usize>,
    }