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}