crud_pretty_struct/impls/
value.rs

1use crate::{coloring, Meta, PrettyPrint};
2use miette::Result;
3use owo_colors::OwoColorize;
4use pad::PadStr;
5use serde_json::Value;
6use std::fmt::Write;
7use unicode_width::UnicodeWidthStr;
8
9impl PrettyPrint for Value {
10  fn meta(&self) -> Meta {
11    Meta {
12      padding: 0,
13      separator: None,
14      fields: vec![],
15    }
16  }
17  fn pretty(&self, colored: bool, prefix: Option<String>, _profile: Option<&str>) -> Result<String> {
18    let Meta { separator, .. } = self.meta();
19
20    let separator = separator.unwrap_or("= ");
21
22    let prefix_ = if let Some(prefix) = &prefix {
23      if colored {
24        prefix.truecolor(80, 80, 80).to_string()
25      } else {
26        prefix.to_owned()
27      }
28    } else {
29      "".into()
30    };
31    let prefix = &prefix.unwrap_or_default();
32
33    let (v, should_color, should_prefix) = match self {
34      Value::Null => ("null".to_string(), true, true),
35      Value::Bool(b) => (b.to_string(), true, true),
36      Value::Number(n) => (n.to_string(), true, true),
37      Value::String(s) => (s.to_owned(), true, true),
38      Value::Array(vv) => (
39        vv.iter().fold(String::new(), |mut output, item| {
40          let end = match item {
41            Value::Array(_) | Value::Object(_) => "",
42            _ => "\n",
43          };
44          let _ = write!(
45            output,
46            "{prefix_}{}{end}",
47            item
48              .pretty(colored, Some(prefix.clone() + "   "), _profile)
49              .unwrap_or_default()
50              .replacen(&(prefix.clone() + "   "), " - ", 1)
51          );
52          output
53        }),
54        false,
55        false,
56      ),
57      Value::Object(o) => (
58        {
59          let padding = 1 + o.keys().map(|k| k.width()).max().unwrap_or_default();
60
61          o.iter()
62            .enumerate()
63            .map(|(_i, (k, v))| {
64              let separator = match v {
65                Value::Array(_) | Value::Object(_) => "-->\n",
66                _ => separator,
67              };
68              let end = match v {
69                Value::Array(_) | Value::Object(_) => "",
70                _ => "\n",
71              };
72              let v = v
73                .pretty(
74                  colored,
75                  match v {
76                    Value::Array(_) | Value::Object(_) => Some(prefix.clone() + "| "),
77                    _ => None,
78                  },
79                  _profile,
80                )
81                .unwrap_or_default();
82              if colored {
83                let v = coloring(v, &None);
84                format!("{prefix_}{}{separator}{v}{end}", k.pad_to_width(padding))
85              } else {
86                format!("{prefix}{}{separator}{v}{end}", k.pad_to_width(padding))
87              }
88            })
89            .collect()
90        },
91        false,
92        false,
93      ),
94    };
95
96    let prefix_ = if should_prefix { prefix_ } else { "".into() };
97
98    let pretty_hashmap = if colored && should_color {
99      let v = coloring(v, &None);
100      format!("{prefix_}{v}")
101    } else {
102      format!("{prefix_}{v}")
103    };
104
105    Ok(pretty_hashmap)
106  }
107}
108
109#[cfg(test)]
110mod tests {
111  use crate::PrettyPrint;
112  use serde_json::{json, Value};
113
114  #[test]
115  fn value_object() {
116    let v: Value = json!({});
117    let result = v.pretty(false, None, None).unwrap_or_default();
118    assert_eq!(result, "".to_string());
119
120    let v: Value = json!({"a":1});
121    let result = v.pretty(false, None, None).unwrap_or_default();
122    assert_eq!(result, "a = 1\n".to_string());
123
124    let v: Value = json!({"number":1,"bool":true,"string":"string"});
125    let result = v.pretty(false, None, None).unwrap_or_default();
126    assert_eq!(
127      result,
128      "bool   = true\nnumber = 1\nstring = string\n".to_string()
129    );
130    let v: Value = json!({"array":[1, 3, 4]});
131    let result = v.pretty(false, None, None).unwrap_or_default();
132    assert_eq!(result, "array -->\n|  - 1\n|  - 3\n|  - 4\n".to_string());
133
134    let v: Value = json!({"object":{"aaa":1,"b":2}});
135    let result = v.pretty(false, None, None).unwrap_or_default();
136    assert_eq!(result, "object -->\n| aaa = 1\n| b   = 2\n".to_string());
137
138    let v: Value = json!({"object":{"aaa":1,"b":{"a":"aaaa","bbb":["a","bb","ccc"]}}});
139    let result = v.pretty(false, None, None).unwrap_or_default();
140    assert_eq!(result, "object -->\n| aaa = 1\n| b   -->\n| | a   = aaaa\n| | bbb -->\n| | |  - a\n| | |  - bb\n| | |  - ccc\n".to_string());
141
142    let v: Value = json!({"array":[{"a":1,"bb":2},{"b":2}]});
143    let result = v.pretty(false, None, None).unwrap_or_default();
144    assert_eq!(
145      result,
146      "array -->\n|  - a  = 1\n|    bb = 2\n|  - b = 2\n".to_string()
147    );
148  }
149
150  #[test]
151  fn value_object_colored() {
152    let v: Value = json!({});
153    let result = v.pretty(true, None, None).unwrap_or_default();
154    assert_eq!(result, "".to_string());
155
156    let v: Value = json!({"a":1});
157    let result = v.pretty(true, None, None).unwrap_or_default();
158    assert_eq!(
159      result,
160      "a = \u{1b}[1m\u{1b}[97m\u{1b}[1m\u{1b}[97m1\u{1b}[39m\u{1b}[0m\u{1b}[39m\u{1b}[0m\n"
161        .to_string()
162    );
163
164    let v: Value = json!({"number":1,"bool":true,"string":"string"});
165    let result = v.pretty(true, None, None).unwrap_or_default();
166    assert_eq!(
167      result,
168     "bool   = \u{1b}[1m\u{1b}[97m\u{1b}[1m\u{1b}[97mtrue\u{1b}[39m\u{1b}[0m\u{1b}[39m\u{1b}[0m\nnumber = \u{1b}[1m\u{1b}[97m\u{1b}[1m\u{1b}[97m1\u{1b}[39m\u{1b}[0m\u{1b}[39m\u{1b}[0m\nstring = \u{1b}[1m\u{1b}[97m\u{1b}[1m\u{1b}[97mstring\u{1b}[39m\u{1b}[0m\u{1b}[39m\u{1b}[0m\n".to_string()
169    );
170    let v: Value = json!({"array":[1, 3, 4]});
171    let result = v.pretty(true, None, None).unwrap_or_default();
172    assert_eq!(result,  "array -->\n\u{1b}[1m\u{1b}[97m\u{1b}[38;2;80;80;80m| \u{1b}[39m\u{1b}[38;2;80;80;80m - \u{1b}[39m\u{1b}[1m\u{1b}[97m1\u{1b}[39m\u{1b}[0m\n\u{1b}[38;2;80;80;80m| \u{1b}[39m\u{1b}[38;2;80;80;80m - \u{1b}[39m\u{1b}[1m\u{1b}[97m3\u{1b}[39m\u{1b}[0m\n\u{1b}[38;2;80;80;80m| \u{1b}[39m\u{1b}[38;2;80;80;80m - \u{1b}[39m\u{1b}[1m\u{1b}[97m4\u{1b}[39m\u{1b}[0m\n\u{1b}[39m\u{1b}[0m".to_string());
173
174    let v: Value = json!({"object":{"aaa":1,"b":2}});
175    let result = v.pretty(true, None, None).unwrap_or_default();
176    assert_eq!(result, "object -->\n\u{1b}[1m\u{1b}[97m\u{1b}[38;2;80;80;80m| \u{1b}[39maaa = \u{1b}[1m\u{1b}[97m\u{1b}[1m\u{1b}[97m1\u{1b}[39m\u{1b}[0m\u{1b}[39m\u{1b}[0m\n\u{1b}[38;2;80;80;80m| \u{1b}[39mb   = \u{1b}[1m\u{1b}[97m\u{1b}[1m\u{1b}[97m2\u{1b}[39m\u{1b}[0m\u{1b}[39m\u{1b}[0m\n\u{1b}[39m\u{1b}[0m".to_string());
177
178    let v: Value = json!({"object":{"aaa":1,"b":{"a":"aaaa","bbb":["a",{"bb":3,"a":6,"ccc":[1,2,3]},["ccc","ddddd"]]}}});
179    let result = v.pretty(true, None, None).unwrap_or_default();
180    assert_eq!(result, "object -->\n\u{1b}[1m\u{1b}[97m\u{1b}[38;2;80;80;80m| \u{1b}[39maaa = \u{1b}[1m\u{1b}[97m\u{1b}[1m\u{1b}[97m1\u{1b}[39m\u{1b}[0m\u{1b}[39m\u{1b}[0m\n\u{1b}[38;2;80;80;80m| \u{1b}[39mb   -->\n\u{1b}[1m\u{1b}[97m\u{1b}[38;2;80;80;80m| | \u{1b}[39ma   = \u{1b}[1m\u{1b}[97m\u{1b}[1m\u{1b}[97maaaa\u{1b}[39m\u{1b}[0m\u{1b}[39m\u{1b}[0m\n\u{1b}[38;2;80;80;80m| | \u{1b}[39mbbb -->\n\u{1b}[1m\u{1b}[97m\u{1b}[38;2;80;80;80m| | | \u{1b}[39m\u{1b}[38;2;80;80;80m - \u{1b}[39m\u{1b}[1m\u{1b}[97ma\u{1b}[39m\u{1b}[0m\n\u{1b}[38;2;80;80;80m| | | \u{1b}[39m\u{1b}[38;2;80;80;80m - \u{1b}[39ma   = \u{1b}[1m\u{1b}[97m\u{1b}[1m\u{1b}[97m6\u{1b}[39m\u{1b}[0m\u{1b}[39m\u{1b}[0m\n\u{1b}[38;2;80;80;80m| | |    \u{1b}[39mbb  = \u{1b}[1m\u{1b}[97m\u{1b}[1m\u{1b}[97m3\u{1b}[39m\u{1b}[0m\u{1b}[39m\u{1b}[0m\n\u{1b}[38;2;80;80;80m| | |    \u{1b}[39mccc -->\n\u{1b}[1m\u{1b}[97m\u{1b}[38;2;80;80;80m| | |    | \u{1b}[39m\u{1b}[38;2;80;80;80m - \u{1b}[39m\u{1b}[1m\u{1b}[97m1\u{1b}[39m\u{1b}[0m\n\u{1b}[38;2;80;80;80m| | |    | \u{1b}[39m\u{1b}[38;2;80;80;80m - \u{1b}[39m\u{1b}[1m\u{1b}[97m2\u{1b}[39m\u{1b}[0m\n\u{1b}[38;2;80;80;80m| | |    | \u{1b}[39m\u{1b}[38;2;80;80;80m - \u{1b}[39m\u{1b}[1m\u{1b}[97m3\u{1b}[39m\u{1b}[0m\n\u{1b}[39m\u{1b}[0m\u{1b}[38;2;80;80;80m| | | \u{1b}[39m\u{1b}[38;2;80;80;80m - \u{1b}[39m\u{1b}[38;2;80;80;80m - \u{1b}[39m\u{1b}[1m\u{1b}[97mccc\u{1b}[39m\u{1b}[0m\n\u{1b}[38;2;80;80;80m| | |    \u{1b}[39m\u{1b}[38;2;80;80;80m - \u{1b}[39m\u{1b}[1m\u{1b}[97mddddd\u{1b}[39m\u{1b}[0m\n\u{1b}[39m\u{1b}[0m\u{1b}[39m\u{1b}[0m\u{1b}[39m\u{1b}[0m".to_string());
181  }
182
183  #[test]
184  fn value_null() {
185    let v: Value = json!(null);
186    let result = v.pretty(false, None, None).unwrap_or_default();
187    assert_eq!(result, "null".to_string());
188  }
189
190  #[test]
191  fn value_bool() {
192    let v: Value = json!(false);
193    let result = v.pretty(false, None, None).unwrap_or_default();
194    assert_eq!(result, "false".to_string());
195
196    let v: Value = json!(true);
197    let result = v.pretty(false, None, None).unwrap_or_default();
198    assert_eq!(result, "true".to_string());
199  }
200
201  #[test]
202  fn value_string() {
203    let v: Value = json!("string");
204    let result = v.pretty(false, None, None).unwrap_or_default();
205    assert_eq!(result, "string".to_string());
206  }
207
208  #[test]
209  fn value_number() {
210    let v: Value = json!(5);
211    let result = v.pretty(false, None, None).unwrap_or_default();
212    assert_eq!(result, "5".to_string());
213
214    let v: Value = json!(-3.014);
215    let result = v.pretty(false, None, None).unwrap_or_default();
216    assert_eq!(result, "-3.014".to_string());
217  }
218
219  #[test]
220  fn value_number_colored() {
221    let v: Value = json!(-874);
222    let result = v.pretty(true, None, None).unwrap_or_default();
223    assert_eq!(
224      result,
225      "\u{1b}[1m\u{1b}[97m-874\u{1b}[39m\u{1b}[0m".to_string()
226    );
227  }
228
229  #[test]
230  fn value_number_porefix() {
231    let v: Value = json!(842.147854);
232    let result = v
233      .pretty(false, Some("==> ".to_string()), None)
234      .unwrap_or_default();
235    assert_eq!(result, "==> 842.147854".to_string());
236  }
237
238  #[test]
239  fn value_array() {
240    let v: Value = json!([1, 2, 3]);
241    let result = v.pretty(false, None, None).unwrap_or_default();
242    assert_eq!(result, " - 1\n - 2\n - 3\n".to_string());
243  }
244
245  #[test]
246  fn value_array_color() {
247    let v: Value = json!([1, 2, 3]);
248    let result = v.pretty(true, None, None).unwrap_or_default();
249    assert_eq!(result,"\u{1b}[38;2;80;80;80m - \u{1b}[39m\u{1b}[1m\u{1b}[97m1\u{1b}[39m\u{1b}[0m\n\u{1b}[38;2;80;80;80m - \u{1b}[39m\u{1b}[1m\u{1b}[97m2\u{1b}[39m\u{1b}[0m\n\u{1b}[38;2;80;80;80m - \u{1b}[39m\u{1b}[1m\u{1b}[97m3\u{1b}[39m\u{1b}[0m\n".to_string());
250  }
251
252  #[test]
253  fn value_array_prefix() {
254    let v: Value = json!([1, 2, 3]);
255    let result = v
256      .pretty(false, Some(">>> ".to_string()), None)
257      .unwrap_or_default();
258    assert_eq!(result, ">>>  - 1\n>>>  - 2\n>>>  - 3\n".to_string());
259  }
260
261  #[test]
262  fn value_array_prefix_colored() {
263    let v: Value = json!([1, 2, 3]);
264    let result = v
265      .pretty(true, Some(">>> ".to_string()), None)
266      .unwrap_or_default();
267    assert_eq!(result, "\u{1b}[38;2;80;80;80m>>> \u{1b}[39m\u{1b}[38;2;80;80;80m - \u{1b}[39m\u{1b}[1m\u{1b}[97m1\u{1b}[39m\u{1b}[0m\n\u{1b}[38;2;80;80;80m>>> \u{1b}[39m\u{1b}[38;2;80;80;80m - \u{1b}[39m\u{1b}[1m\u{1b}[97m2\u{1b}[39m\u{1b}[0m\n\u{1b}[38;2;80;80;80m>>> \u{1b}[39m\u{1b}[38;2;80;80;80m - \u{1b}[39m\u{1b}[1m\u{1b}[97m3\u{1b}[39m\u{1b}[0m\n".to_string());
268  }
269}