1//! An easy to use library for pretty print tables of Rust `struct`s and `enum`s.
2//!
3//! The library supports different approaches of table building.
4//! You can use [`Tabled`] trait if the data type is known.
5//! Or you can use [`Builder`] to construct the table from scratch.
6//!
7//! ## Derive
8//!
9//! If you want to build a table for your custom type.
10//! A starting point is to a anotate your type with `#[derive(Tabled)]`.
11//!
12//! Then to provide your collection to [`Table::new`] and you will be set to render table.
13//!
14#![cfg_attr(all(feature = "derive", feature = "std"), doc = "```")]
15#![cfg_attr(not(all(feature = "derive", feature = "std")), doc = "```ignore")]
16//! use tabled::{Tabled, Table};
17//!
18//! #[derive(Tabled)]
19//! struct Language {
20//! name: &'static str,
21//! designed_by: &'static str,
22//! invented_year: usize,
23//! }
24//!
25//! let languages = vec![
26//! Language{
27//! name: "C",
28//! designed_by: "Dennis Ritchie",
29//! invented_year: 1972
30//! },
31//! Language{
32//! name: "Rust",
33//! designed_by: "Graydon Hoare",
34//! invented_year: 2010
35//! },
36//! Language{
37//! name: "Go",
38//! designed_by: "Rob Pike",
39//! invented_year: 2009
40//! },
41//! ];
42//!
43//! let table = Table::new(languages).to_string();
44//!
45//! let expected = "+------+----------------+---------------+\n\
46//! | name | designed_by | invented_year |\n\
47//! +------+----------------+---------------+\n\
48//! | C | Dennis Ritchie | 1972 |\n\
49//! +------+----------------+---------------+\n\
50//! | Rust | Graydon Hoare | 2010 |\n\
51//! +------+----------------+---------------+\n\
52//! | Go | Rob Pike | 2009 |\n\
53//! +------+----------------+---------------+";
54//!
55//! assert_eq!(table, expected);
56//! ```
57//!
58//! BEWARE not all types can derive [`Tabled`] trait.
59//! The example below can't be compiled.
60//!
61//! Because `tabled` must know what we're up to print as a field, so
62//! each field must implement [`std::fmt::Display`].
63//!
64//! ```rust,compile_fail
65//! # use tabled::Tabled;
66//! #[derive(Tabled)]
67//! struct SomeType {
68//! field1: SomeOtherType,
69//! }
70//!
71//! struct SomeOtherType;
72//! ```
73//!
74//! You can tweak it by derive options.
75//!
76//! ### Default implementations
77//!
78//! [`Table`] can be build from vast majority of Rust's standard types.
79//! This allows you to run the following code.
80//!
81#![cfg_attr(feature = "std", doc = "```")]
82#![cfg_attr(not(feature = "std"), doc = "```ignore")]
83//! use tabled::{Tabled, Table};
84//! let table = Table::new(&[1, 2, 3]);
85//! # let expected = "+-----+\n\
86//! # | i32 |\n\
87//! # +-----+\n\
88//! # | 1 |\n\
89//! # +-----+\n\
90//! # | 2 |\n\
91//! # +-----+\n\
92//! # | 3 |\n\
93//! # +-----+";
94//! # assert_eq!(table.to_string(), expected);
95//! ```
96//!
97//! ### Builder
98//!
99//! When you data scheme is not known at compile time.
100//! You most likely will not able to relay on [`Tabled`] trait.
101//!
102//! So one option would be is to use [`Builder`].
103//!
104#![cfg_attr(feature = "std", doc = "```")]
105#![cfg_attr(not(feature = "std"), doc = "```ignore")]
106//! use std::iter;
107//!
108//! use tabled::{
109//! builder::Builder,
110//! settings::{Modify, object::Rows, Alignment, Style}
111//! };
112//!
113//! let (x, y) = (3, 10);
114//!
115//! let mut builder = Builder::default();
116//!
117//! let header = iter::once(String::from("i")).chain((0..y).map(|i| i.to_string()));
118//! builder.push_record(header);
119//!
120//! for i in 0..x {
121//! let row = iter::once(i).chain((0..y).map(|j| i * j)).map(|i| i.to_string());
122//! builder.push_record(row);
123//! }
124//!
125//! let table = builder.build()
126//! .with(Style::rounded())
127//! .modify(Rows::new(1..), Alignment::left())
128//! .to_string();
129//!
130//! assert_eq!(
131//! table,
132//! concat!(
133//! "╭───┬───┬───┬───┬───┬───┬────┬────┬────┬────┬────╮\n",
134//! "│ i │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │\n",
135//! "├───┼───┼───┼───┼───┼───┼────┼────┼────┼────┼────┤\n",
136//! "│ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │\n",
137//! "│ 1 │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │\n",
138//! "│ 2 │ 0 │ 2 │ 4 │ 6 │ 8 │ 10 │ 12 │ 14 │ 16 │ 18 │\n",
139//! "╰───┴───┴───┴───┴───┴───┴────┴────┴────┴────┴────╯",
140//! )
141//! );
142//! ```
143//!
144//! ### Build table using [`row!`] and [`col!`] macros.
145//!
146#![cfg_attr(all(feature = "macros", feature = "std"), doc = "```")]
147#![cfg_attr(not(all(feature = "macros", feature = "std")), doc = "```ignore")]
148//! use tabled::{row, col};
149//!
150//! let table = row![
151//! col!["Hello", "World", "!"],
152//! col!["Hello"; 3],
153//! col!["World"; 3],
154//! ];
155//!
156//! assert_eq!(
157//! table.to_string(),
158//! concat!(
159//! "+-----------+-----------+-----------+\n",
160//! "| +-------+ | +-------+ | +-------+ |\n",
161//! "| | Hello | | | Hello | | | World | |\n",
162//! "| +-------+ | +-------+ | +-------+ |\n",
163//! "| | World | | | Hello | | | World | |\n",
164//! "| +-------+ | +-------+ | +-------+ |\n",
165//! "| | ! | | | Hello | | | World | |\n",
166//! "| +-------+ | +-------+ | +-------+ |\n",
167//! "+-----------+-----------+-----------+",
168//! )
169//! );
170//! ```
171//!
172//! ### Settings
173//!
174//! You can use many settings which is found in [`tabled::settings`] module.
175//!
176//! # Features
177//!
178//! - `std` - Used by default. If not its considered `no_std` with a limited set of functionality.
179//! - `derive` - Used by default. A support for `Tabled` derive macro.
180//! - `ansi` - A support for ANSI sequences.
181//! - `macros` - A support for `row!`, `col!` macro.
182//!
183//! # Advanced
184//!
185//! ## Table types
186//!
187//! [`Table`] keeps data buffered, which sometimes not ideal choise.
188//! For such reason there is [`IterTable`] and [`CompactTable`].
189//!
190//! ### [`IterTable`]
191//!
192//! [`IterTable`] stands on a middle ground between [`Table`] and [`CompactTable`].
193//!
194//! It does allocate memory but in a much smaller chunks that a [`Table`] does.
195//! The benefit is that it can be used interchangebly with [`Table`].
196//!
197#![cfg_attr(feature = "std", doc = "```")]
198#![cfg_attr(not(feature = "std"), doc = "```ignore")]
199//! use tabled::tables::IterTable;
200//!
201//! let iterator = (0..3).map(|row| (0..4).map(move |col| format!("{}-{}", row, col)));
202//!
203//! let table = IterTable::new(iterator).to_string();
204//!
205//! assert_eq!(
206//! table,
207//! "+-----+-----+-----+-----+\n\
208//! | 0-0 | 0-1 | 0-2 | 0-3 |\n\
209//! +-----+-----+-----+-----+\n\
210//! | 1-0 | 1-1 | 1-2 | 1-3 |\n\
211//! +-----+-----+-----+-----+\n\
212//! | 2-0 | 2-1 | 2-2 | 2-3 |\n\
213//! +-----+-----+-----+-----+",
214//! );
215//! ```
216//!
217//! ### [`CompactTable`]
218//!
219//! Alloc free can be configured ('1) to not make any allocations.
220//! But the price is that the set of settings which can be applied to it is limited.
221//!
222//! It also can be printed directly to [`fmt::Write`] to not have any intermidiaries.
223//!
224//! '1. It does not make any allocations in case you provide it with `width` and `count_rows`.
225//!
226//! ```
227//! use tabled::{settings::Style, tables::CompactTable};
228//! use core::fmt::{Write, Result};
229//!
230//! struct StubWriter;
231//!
232//! impl Write for StubWriter {
233//! fn write_str(&mut self, _: &str) -> Result {
234//! Ok(())
235//! }
236//! }
237//!
238//! let data = [
239//! ["FreeBSD", "1993", "William and Lynne Jolitz", "?"],
240//! ["OpenBSD", "1995", "Theo de Raadt", ""],
241//! ["HardenedBSD", "2014", "Oliver Pinter and Shawn Webb", ""],
242//! ];
243//!
244//! let table = CompactTable::from(data).with(Style::psql());
245//!
246//! table.fmt(StubWriter);
247//! ```
248//!
249//! ## `no_std`
250//!
251//! [`CompactTable`] can be used in `no_std` context.
252//!
253//! ## More information
254//!
255//! You can find more examples of settings and attributes in
256//! [README.md](https://github.com/zhiburt/tabled/blob/master/README.md)
257//!
258//! [`Builder`]: crate::builder::Builder
259//! [`IterTable`]: crate::tables::IterTable
260//! [`CompactTable`]: crate::tables::CompactTable
261//! [`fmt::Write`]: core::fmt::Write
262//! [`row!`]: crate::row
263//! [`col!`]: crate::col
264//! [`tabled::settings`]: crate::settings
265
266#![cfg_attr(not(any(feature = "std", test)), no_std)]
267#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
268#![doc(
269 html_logo_url = "https://raw.githubusercontent.com/zhiburt/tabled/86ac146e532ce9f7626608d7fd05072123603a2e/assets/tabled-gear.svg"
270)]
271#![deny(unused_must_use)]
272#![warn(
273 missing_docs,
274 rust_2018_idioms,
275 rust_2018_compatibility,
276 missing_debug_implementations,
277 unreachable_pub,
278 future_incompatible,
279 single_use_lifetimes,
280 trivial_casts,
281 trivial_numeric_casts,
282 unused_extern_crates,
283 unused_import_braces,
284 unused_qualifications,
285 unused_results,
286 unused_variables,
287 variant_size_differences
288)]
289#![allow(clippy::uninlined_format_args)]
290
291mod util;
292
293#[cfg(feature = "std")]
294mod tabled;
295
296#[cfg(feature = "std")]
297#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
298pub mod builder;
299pub mod settings;
300pub mod tables;
301
302#[cfg(feature = "macros")]
303#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
304pub mod macros;
305
306pub mod grid;
307
308#[cfg(feature = "std")]
309#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
310pub use crate::{tabled::Tabled, tables::Table};
311
312/// A derive macro to implement a [`Tabled`] trait.
313///
314/// The macro available only when `derive` feature in turned on (and it is by default).
315///
316/// To be able to use the derive each field must implement `std::fmt::Display`.
317/// The following example will cause an error because of that.
318///
319/// ```rust,compile_fail
320/// use tabled::Tabled;
321/// #[derive(Tabled)]
322/// struct SomeType {
323/// field1: SomeOtherType,
324/// }
325///
326/// struct SomeOtherType;
327/// ```
328///
329/// Bellow you'll find available options for it.
330///
331/// ### Override a column name
332///
333/// You can use a `#[tabled(rename = "")]` attribute to override a column name.
334///
335/// ```rust,no_run
336/// use tabled::Tabled;
337///
338/// #[derive(Tabled)]
339/// struct Person {
340/// #[tabled(rename = "Name")]
341/// first_name: String,
342/// #[tabled(rename = "Surname")]
343/// last_name: String,
344/// }
345/// ```
346///
347/// ### Hide a column
348///
349/// You can mark fields as hidden in which case they fill be ignored and not be present on a sheet.
350///
351/// A similar affect could be achieved by the means of a `Disable` setting.
352///
353/// ```rust,no_run
354/// use tabled::Tabled;
355///
356/// #[derive(Tabled)]
357/// struct Person {
358/// id: u8,
359/// #[tabled(skip)]
360/// number: String,
361/// name: String,
362/// }
363/// ```
364///
365/// ### Set column order
366///
367/// You can change the order in which they will be displayed in table.
368///
369/// ```rust,no_run
370/// use tabled::Tabled;
371///
372/// #[derive(Tabled)]
373/// struct Person {
374/// id: u8,
375/// #[tabled(order = 0)]
376/// number: String,
377/// #[tabled(order = 1)]
378/// name: String,
379/// }
380/// ```
381///
382/// ### Format fields
383///
384/// As was said already, using `#[derive(Tabled)]` is possible only when all fields implement a `Display` trait.
385/// However, this may be often not the case for example when a field uses the `Option` type. There's 2 common ways how to solve this:
386///
387/// - Implement `Tabled` trait manually for a type.
388/// - Wrap `Option` to something like `DisplayedOption<T>(Option<T>)` and implement a Display trait for it.
389///
390/// Alternatively, you can use the `#[tabled(display_with = "func")]` attribute for the field to specify a display function.
391///
392/// ```rust,no_run
393/// use tabled::Tabled;
394///
395/// #[derive(Tabled)]
396/// pub struct MyRecord {
397/// pub id: i64,
398/// #[tabled(display_with = "display_option")]
399/// pub valid: Option<bool>
400/// }
401///
402/// fn display_option(o: &Option<bool>) -> String {
403/// match o {
404/// Some(s) => format!("is valid thing = {}", s),
405/// None => format!("is not valid"),
406/// }
407/// }
408/// ```
409///
410/// It's also possible to change function argument to be `&self`,
411/// using `#[tabled(display_with("some_function", self))]`
412///
413/// ```rust,no_run
414/// use tabled::Tabled;
415///
416/// #[derive(Tabled)]
417/// pub struct MyRecord {
418/// pub id: i64,
419/// #[tabled(display_with("Self::display_valid", self))]
420/// pub valid: Option<bool>
421/// }
422///
423/// impl MyRecord {
424/// fn display_valid(&self) -> String {
425/// match self.valid {
426/// Some(s) => format!("is valid thing = {}", s),
427/// None => format!("is not valid"),
428/// }
429/// }
430/// }
431/// ```
432///
433/// ### Format headers
434///
435/// Beside `#[tabled(rename = "")]` you can change a format of a column name using
436/// `#[tabled(rename_all = "UPPERCASE")]`.
437///
438/// ```rust,no_run
439/// use tabled::Tabled;
440///
441/// #[derive(Tabled)]
442/// #[tabled(rename_all = "CamelCase")]
443/// struct Person {
444/// id: u8,
445/// number: String,
446/// name: String,
447/// #[tabled(rename_all = "snake_case")]
448/// middle_name: String,
449/// }
450/// ```
451///
452/// ### Inline
453///
454/// It's possible to inline internal data if it implements the `Tabled` trait using `#[tabled(inline)]`.
455/// You can also set a prefix which will be used for all inlined elements by `#[tabled(inline("prefix>>"))]`.
456///
457/// ```rust,no_run
458/// use tabled::Tabled;
459///
460/// #[derive(Tabled)]
461/// struct Person {
462/// id: u8,
463/// name: String,
464/// #[tabled(inline)]
465/// ed: Education,
466/// }
467///
468/// #[derive(Tabled)]
469/// struct Education {
470/// uni: String,
471/// graduated: bool,
472/// }
473/// ```
474///
475/// And it works for enums as well.
476///
477/// ```rust,no_run
478/// use tabled::Tabled;
479///
480/// #[derive(Tabled)]
481/// enum Vehicle {
482/// #[tabled(inline("Auto::"))]
483/// Auto {
484/// model: String,
485/// engine: String,
486/// },
487/// #[tabled(inline)]
488/// Bikecycle(
489/// String,
490/// #[tabled(inline)] Bike,
491/// ),
492/// }
493///
494/// #[derive(Tabled)]
495/// struct Bike {
496/// brand: &'static str,
497/// price: f32,
498/// }
499/// ```
500#[cfg(feature = "derive")]
501#[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
502pub use tabled_derive::Tabled;
503

Provided by KDAB

Privacy Policy
Learn Rust with the experts
Find out more