tabled
A Rust library for pretty-printing structs and enums as customizable ASCII/Unicode tables.
Repository Health
Technical Analysis
tabled turns Rust Vecs of structs or enums into readable tables with a single derive macro, translating each field into a column and each item into a row. Beyond the default Table, the crate ships alternate renderers — IterTable for streaming data that doesn’t fit in memory, CompactTable for no-std/embedded targets, and PoolTable/ExtendedTable for other display needs — plus companion crates (json_to_table, csv_to_table, toml_to_table, ron_to_table, table_to_html) that convert other formats straight into the same table renderer.
Formatting is handled through a composable settings system: Style, Alignment, Padding, Margin, Width, Height, Merge, Span, and more apply via chained .with() calls or a bundled Settings object, and the underlying papergrid layout engine gives fine-grained control over borders, spans, and ANSI-colored content without hand-rolled string formatting.
What You Get
- A
#[derive(Tabled)]macro that turns any struct or enum into table rows without manual formatting code - Multiple table renderers (
Table,IterTable,CompactTable,PoolTable,ExtendedTable) for different memory and layout constraints, including ano_std-compatible option - A composable settings system (
Style,Alignment,Padding,Margin,Width,Height,Merge,Span,Highlight) applied via.with()calls - Built-in border styles (ASCII, Markdown, PSQL, reStructuredText, rounded, sharp, extended, dots, and more) plus full custom-border support
- Companion crates (
json_to_table,csv_to_table,toml_to_table,ron_to_table,table_to_html) that render other data formats through the same table engine
Common Use Cases
- Printing query results or config summaries as aligned tables in a CLI tool
- Debug-formatting structured data during development instead of raw
{:?}dumps - Rendering CSV, JSON, TOML, or RON files as terminal tables for inspection
- Building ops/admin output for terminal apps that need dynamic column widths and merged cells
- Streaming large datasets through
IterTableorCompactTablewhen the full result set can’t be buffered in memory
Under The Hood
Architecture
The project is a 10-crate Cargo workspace layered around a low-level grid engine: papergrid owns dimension calculation, cell/border configuration, and the actual grid-rendering algorithms (with separate compact/iterable/peekable grid implementations for different memory strategies), while the public tabled crate builds the ergonomic API on top of it. Inside tabled, src/settings/ defines the extensibility mechanism — a CellOption/TableOption trait pair (a strategy/visitor pattern) that lets every setting type (Style, Alignment, Width, Merge, etc.) modify either a single cell or the whole table uniformly, composed through a .with() chain or a bundled Settings list. src/tables/ hosts the different renderer implementations (Table, IterTable, CompactTable, PoolTable, ExtendedTable) that all consume the same settings abstractions but trade off buffering, allocation, and layout-pass behavior differently, and src/builder/ and src/derive/ provide the two entry points (runtime builder vs. compile-time derive) for getting data into that pipeline. A change to papergrid’s core grid/dimension logic would ripple through every table type in tabled and its adapter crates, since they all render through it.
Tech Stack
Pure Rust (edition 2018), organized as a Cargo workspace with papergrid (the grid engine), tabled (the public API), tabled_derive (the proc-macro crate), testing_table (an internal assertion/testing helper), and adapter crates (json_to_table, csv_to_table, toml_to_table, ron_to_table, table_to_html, static_table). Optional dependencies (ansi-str, ansitok) support ANSI-aware width measurement behind an ansi feature flag, and the crate is feature-gated (std, derive, macros, assert) so CompactTable can run in no_std environments. No async runtime or database layer — this is a pure formatting/layout library with zero I/O.
Code Quality
Testing is extensive and multi-layered: 58 test files spread across tests/settings, tests/core, tests/derive, tests/macros, and a dedicated tests/qc suite using property-based (quickcheck-style) tests, run as a separate CI job. CI (ci.yml) checks every crate across a matrix of Rust toolchains (stable/nightly), operating systems (Linux/Windows/macOS), and feature-flag combinations, including a WASM target check and a pinned MSRV build (Rust 1.83.0). Beyond compilation checks, CI runs cargo fmt --check, cargo clippy -- -D warnings (warnings as errors), and cargo test --workspace. Unsafe code is minimal (a handful of occurrences across the whole workspace). The public API is documented almost entirely with executable doctests embedded in /// comments, which double as regression tests.
What Makes It Unique
Most Rust table-printing crates ship a single table type; tabled instead offers a family of renderers tuned for different constraints — a buffered default Table, a single-row-buffered IterTable for datasets too large to hold in memory, and an allocation-free CompactTable usable in no_std/embedded contexts — all driven by the same settings API, so switching renderers doesn’t mean relearning the styling system. The CellOption/TableOption abstraction lets third-party code define new settings that compose with built-in ones, and the family of *_to_table adapter crates extends the same rendering pipeline to JSON, CSV, TOML, and RON input without going through an intermediate struct definition.