1use crate::Value;
2
3pub fn to_string(value: &Value) -> String {
4 fn format_indent(indent_level: usize) -> String {
5 "\t".repeat(indent_level)
6 }
7
8 fn to_string_with_indent(value: &Value, indent_level: usize) -> String {
9 let prev_indent = format_indent(indent_level - 1);
10 let curr_indent = format_indent(indent_level);
11
12 match value {
13 Value::File(header, root) => {
14 format!("{}\n{}", header, to_string_with_indent(root, indent_level))
15 }
16 Value::Object(map) => {
17 if map.is_empty() {
18 return format!("{{\n{}}}", prev_indent);
19 }
20
21 let pairs = map
22 .iter()
23 .map(|(key, value)| {
24 let separator = if value.is_object() || value.is_array() {
25 format!("\n{}", format_indent(indent_level))
26 } else {
27 " ".to_owned()
28 };
29 format!(
30 "{}{} ={}{}",
31 curr_indent,
32 key,
33 separator,
34 to_string_with_indent(value, indent_level + 1)
35 )
36 })
37 .collect::<Vec<_>>()
38 .join("\n");
39
40 format!("{{\n{}\n{}}}", pairs, prev_indent)
41 }
42
43 Value::Array(values) => {
44 if values.is_empty() {
45 return format!("[\n{}]", prev_indent);
46 }
47
48 let elements = values
49 .iter()
50 .map(|value| {
51 format!(
52 "{}{}",
53 curr_indent,
54 to_string_with_indent(value, indent_level + 1)
55 )
56 })
57 .collect::<Vec<_>>()
58 .join(",\n");
59
60 format!("[\n{},\n{}]", elements, prev_indent)
61 }
62
63 Value::Flag(key, value) => {
64 let separator = if value.is_object() || value.is_array() {
65 format!("\n{}", prev_indent)
66 } else {
67 "".to_owned()
68 };
69
70 format!(
71 "{}:{}{}",
72 key,
73 separator,
74 to_string_with_indent(value, indent_level)
75 )
76 }
77
78 Value::String(value) => format!("\"{}\"", value),
79 Value::MultilineString(value) => format!("\"\"\"\n{}\n\"\"\"\n", value),
80 Value::Number(value) => value.to_string(),
81 Value::Bool(value) => value.to_string(),
82 Value::Null => "null".to_string(),
83 }
84 }
85
86 to_string_with_indent(value, 1).trim_end().to_string() + "\n"
87}