json_to_table/lib.rs
1//! The crate contains a [`json_to_table`] function which builds a [`Table`] from an ordinary json.
2//!
3//! You can build the table either generally or in a squash.
4//! See the examples below.
5//!
6//! ```
7//! use serde_json::json;
8//! use json_to_table::json_to_table;
9//!
10//! let value = json!(
11//! {
12//! "name": "John Doe",
13//! "age": 43,
14//! "address": {
15//! "street": "10 Downing Street",
16//! "city": "London"
17//! },
18//! "phones": [
19//! "+44 1234567",
20//! "+44 2345678"
21//! ]
22//! }
23//! );
24//!
25//! // recursive table
26//! let table = json_to_table(&value).to_string();
27//!
28//! println!("{}", table);
29//!
30//! assert_eq!(
31//! table,
32//! concat!(
33//! "+---------+----------------------------------+\n",
34//! "| address | +--------+---------------------+ |\n",
35//! "| | | city | London | |\n",
36//! "| | +--------+---------------------+ |\n",
37//! "| | | street | 10 Downing Street | |\n",
38//! "| | +--------+---------------------+ |\n",
39//! "+---------+----------------------------------+\n",
40//! "| age | 43 |\n",
41//! "+---------+----------------------------------+\n",
42//! "| name | John Doe |\n",
43//! "+---------+----------------------------------+\n",
44//! "| phones | +---------------+ |\n",
45//! "| | | +44 1234567 | |\n",
46//! "| | +---------------+ |\n",
47//! "| | | +44 2345678 | |\n",
48//! "| | +---------------+ |\n",
49//! "+---------+----------------------------------+",
50//! ),
51//! );
52//!
53//! // squash tables together
54//! let table = json_to_table(&value).collapse().to_string();
55//!
56//! assert_eq!(
57//! table,
58//! concat!(
59//! "+---------+--------+-------------------+\n",
60//! "| address | city | London |\n",
61//! "| +--------+-------------------+\n",
62//! "| | street | 10 Downing Street |\n",
63//! "+---------+--------+-------------------+\n",
64//! "| age | 43 |\n",
65//! "+---------+----------------------------+\n",
66//! "| name | John Doe |\n",
67//! "+---------+----------------------------+\n",
68//! "| phones | +44 1234567 |\n",
69//! "| +----------------------------+\n",
70//! "| | +44 2345678 |\n",
71//! "+---------+----------------------------+",
72//! ),
73//! );
74//! ```
75//!
76//! [`Table`]: tabled::Table
77
78#![deny(unused_must_use)]
79#![warn(
80 missing_docs,
81 rust_2018_idioms,
82 missing_debug_implementations,
83 unreachable_pub
84)]
85#![allow(clippy::uninlined_format_args)]
86#![doc(
87 html_logo_url = "https://raw.githubusercontent.com/zhiburt/tabled/86ac146e532ce9f7626608d7fd05072123603a2e/assets/tabled-gear.svg"
88)]
89
90use serde_json::Value;
91
92pub use table::{JsonTable, Orientation};
93use tabled::{builder::Builder, Table};
94
95mod table;
96
97/// The function converts a given [`Value`] to a [`JsonTable`].
98///
99/// ```
100/// let json = serde_json::json!({
101/// "key1": "value1",
102/// "key2": {
103/// "key1": 123,
104/// "key2": [1, 2, 3, 4, 5],
105/// },
106/// "key3": [
107/// {"key": 123.3},
108/// 2,
109/// "asd"
110/// ],
111/// "key4": 1234.567
112/// });
113///
114/// let table = json_to_table::json_to_table(&json).to_string();
115///
116/// assert_eq!(
117/// table,
118/// concat!(
119/// "+------+-----------------------+\n",
120/// "| key1 | value1 |\n",
121/// "+------+-----------------------+\n",
122/// "| key2 | +------+---------+ |\n",
123/// "| | | key1 | 123 | |\n",
124/// "| | +------+---------+ |\n",
125/// "| | | key2 | +-----+ | |\n",
126/// "| | | | | 1 | | |\n",
127/// "| | | | +-----+ | |\n",
128/// "| | | | | 2 | | |\n",
129/// "| | | | +-----+ | |\n",
130/// "| | | | | 3 | | |\n",
131/// "| | | | +-----+ | |\n",
132/// "| | | | | 4 | | |\n",
133/// "| | | | +-----+ | |\n",
134/// "| | | | | 5 | | |\n",
135/// "| | | | +-----+ | |\n",
136/// "| | +------+---------+ |\n",
137/// "+------+-----------------------+\n",
138/// "| key3 | +-------------------+ |\n",
139/// "| | | +-----+---------+ | |\n",
140/// "| | | | key | 123.3 | | |\n",
141/// "| | | +-----+---------+ | |\n",
142/// "| | +-------------------+ |\n",
143/// "| | | 2 | |\n",
144/// "| | +-------------------+ |\n",
145/// "| | | asd | |\n",
146/// "| | +-------------------+ |\n",
147/// "+------+-----------------------+\n",
148/// "| key4 | 1234.567 |\n",
149/// "+------+-----------------------+",
150/// ),
151/// )
152/// ```
153pub fn json_to_table(value: &Value) -> JsonTable<&Value> {
154 JsonTable::new(value)
155}
156
157/// The function converts a given [`Value`] to a [`Table`].
158///
159/// It's quite different from [`json_to_table`], cause it is not recursive
160/// and treats `json` `object` and `array` as string values.
161///
162/// ```
163/// let json = serde_json::json!({
164/// "key1": "value1",
165/// "key2": {
166/// "key1": 123,
167/// "key2": [1, 2, 3, 4, 5],
168/// },
169/// "key3": [
170/// {"key": 123.3},
171/// 2,
172/// "asd"
173/// ],
174/// "key4": 1234.567
175/// });
176///
177/// let table = json_to_table::parse(&json).to_string();
178///
179/// assert_eq!(
180/// table,
181/// concat!(
182/// "+------+---------------------------------+\n",
183/// "| key1 | value1 |\n",
184/// "+------+---------------------------------+\n",
185/// "| key2 | {\"key1\":123,\"key2\":[1,2,3,4,5]} |\n",
186/// "+------+---------------------------------+\n",
187/// "| key3 | [{\"key\":123.3},2,\"asd\"] |\n",
188/// "+------+---------------------------------+\n",
189/// "| key4 | 1234.567 |\n",
190/// "+------+---------------------------------+",
191/// ),
192/// )
193/// ```
194///
195/// [`Table`]: tabled::Table
196pub fn parse(value: &Value) -> Table {
197 json_into_table(value)
198}
199
200fn json_into_table(value: &Value) -> Table {
201 match value {
202 Value::Array(array) => {
203 let list = array.iter().map(json_value_to_string).collect::<Vec<_>>();
204 Builder::from(vec![list]).build()
205 }
206 Value::Object(map) => {
207 let list = map
208 .iter()
209 .map(|(key, value)| vec![key.clone(), json_value_to_string(value)])
210 .collect::<Vec<_>>();
211
212 Builder::from(list).build()
213 }
214 Value::Null => Builder::default().build(),
215 Value::Bool(value) => single_value_table(value),
216 Value::Number(value) => single_value_table(value),
217 Value::String(value) => single_value_table(value),
218 }
219}
220
221fn single_value_table<V: ToString>(value: V) -> Table {
222 Builder::from(vec![vec![value.to_string()]]).build()
223}
224
225fn json_value_to_string(value: &Value) -> String {
226 match value {
227 Value::Null => String::new(),
228 Value::Bool(value) => value.to_string(),
229 Value::Number(value) => value.to_string(),
230 Value::String(value) => value.to_string(),
231 Value::Array(_) | Value::Object(_) => {
232 serde_json::to_string(value).unwrap_or_else(|_| format!("{:?}", value))
233 }
234 }
235}