1use crate::item::TreeItem;
2use crate::style::Style;
3
4use std::borrow::Cow;
5use std::io;
6
7use serde_value::Value;
8
9fn value_to_string(v: &Value) -> String {
10 match v {
11 Value::Bool(b) => b.to_string(),
12 Value::U8(u) => u.to_string(),
13 Value::U16(u) => u.to_string(),
14 Value::U32(u) => u.to_string(),
15 Value::U64(u) => u.to_string(),
16 Value::I8(i) => i.to_string(),
17 Value::I16(i) => i.to_string(),
18 Value::I32(i) => i.to_string(),
19 Value::I64(i) => i.to_string(),
20 Value::F32(f) => f.to_string(),
21 Value::F64(f) => f.to_string(),
22 Value::Char(c) => c.to_string(),
23 Value::String(s) => s.clone(),
24 Value::Option(Some(b)) => value_to_string(b),
25 Value::Newtype(b) => value_to_string(b),
26 _ => "".to_string(),
27 }
28}
29
30impl TreeItem for Value {
31 type Child = (String, Value);
32
33 fn write_self<W: io::Write>(&self, f: &mut W, style: &Style) -> io::Result<()> {
34 write!(f, "{}", style.paint(value_to_string(self)))
35 }
36
37 fn children(&self) -> Cow<[Self::Child]> {
38 match self {
39 Value::Seq(v) => Cow::from(v.iter().map(|v| ("".to_string(), v.clone())).collect::<Vec<_>>()),
40 Value::Map(m) => {
41 let v: Vec<_> = m
42 .iter()
43 .map(|(k, v)| match v {
44 Value::Seq(_) => (value_to_string(k), v.clone()),
45 Value::Map(_) => (value_to_string(k), v.clone()),
46 _ => (
47 "".to_string(),
48 Value::String(format!("{} = {}", value_to_string(k), value_to_string(v))),
49 ),
50 })
51 .collect();
52 Cow::from(v)
53 }
54 _ => Cow::from(vec![]),
55 }
56 }
57}
58
59impl TreeItem for (String, Value) {
60 type Child = Self;
61
62 fn write_self<W: io::Write>(&self, f: &mut W, style: &Style) -> io::Result<()> {
63 if self.0.is_empty() {
64 write!(f, "{}", style.paint(value_to_string(&self.1)))
65 } else {
66 write!(f, "{}", style.paint(&self.0))
67 }
68 }
69
70 fn children(&self) -> Cow<[Self::Child]> {
71 match &self.1 {
72 Value::Seq(v) => Cow::from(v.iter().map(|v| ("".to_string(), v.clone())).collect::<Vec<_>>()),
73 Value::Map(m) => {
74 let v: Vec<_> = m
75 .iter()
76 .map(|(k, v)| match v {
77 Value::Seq(_) => (value_to_string(k), v.clone()),
78 Value::Map(_) => (value_to_string(k), v.clone()),
79 _ => (
80 "".to_string(),
81 Value::String(format!("{} = {}", value_to_string(k), value_to_string(v))),
82 ),
83 })
84 .collect();
85 Cow::from(v)
86 }
87 _ => Cow::from(vec![]),
88 }
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95 use std::io::Cursor;
96 use std::str::from_utf8;
97
98 use crate::output::write_tree_with;
99 use crate::print_config::PrintConfig;
100
101 use serde_any;
102
103 #[test]
104 fn toml_value_output() {
105 let toml = "\
106 configuration = [\"toml\", \"yaml\", \"json\", \"environment\"]\n\
107 charactersets = [\"utf\", \"ascii\"]\n\
108 \n\
109 default_depth = 3\n\
110 \n\
111 ";
112
113 let value: Value = serde_any::from_str(toml, serde_any::Format::Toml).unwrap();
114 let tree = ("toml".to_string(), value);
115
116 let config = PrintConfig {
117 indent: 4,
118 leaf: Style::default(),
119 branch: Style::default(),
120 ..PrintConfig::default()
121 };
122
123 let mut cursor: Cursor<Vec<u8>> = Cursor::new(Vec::new());
124
125 write_tree_with(&tree, &mut cursor, &config).unwrap();
126
127 let data = cursor.into_inner();
128 let expected = "\
129 toml\n\
130 ├── charactersets\n\
131 │ ├── utf\n\
132 │ └── ascii\n\
133 ├── configuration\n\
134 │ ├── toml\n\
135 │ ├── yaml\n\
136 │ ├── json\n\
137 │ └── environment\n\
138 └── default_depth = 3\n\
139 ";
140 assert_eq!(from_utf8(&data).unwrap(), expected);
141 }
142}