litex/common/
json_value.rs1use crate::common::defaults::{is_default_line_file, LineFile};
2
3#[derive(Debug, Clone)]
5pub enum JsonValue {
6 Null,
7 Bool(bool),
8 Number(usize),
9 JsonString(String),
10 Array(Vec<JsonValue>),
11 Object(Vec<(String, JsonValue)>),
12}
13
14pub fn json_string_literal(source_text: &str) -> String {
15 let mut output = String::with_capacity(source_text.len() + 2);
16 output.push('"');
17 for ch in source_text.chars() {
18 match ch {
19 '"' => output.push_str("\\\""),
20 '\\' => output.push_str("\\\\"),
21 '\n' => output.push_str("\\n"),
22 '\r' => output.push_str("\\r"),
23 '\t' => output.push_str("\\t"),
24 c if (c as u32) < 32 => {
25 output.push_str(format!("\\u{:04x}", c as u32).as_str());
26 }
27 c => output.push(c),
28 }
29 }
30 output.push('"');
31 output
32}
33
34pub fn json_one_level_indent(unit_count: usize) -> String {
35 " ".repeat(unit_count)
36}
37
38pub fn line_file_line_json_value(line_file: &LineFile) -> JsonValue {
39 if is_default_line_file(line_file) {
40 JsonValue::Null
41 } else {
42 JsonValue::Number(line_file.0)
43 }
44}
45
46pub fn line_file_source_json_value(line_file: &LineFile) -> JsonValue {
47 if is_default_line_file(line_file) {
48 JsonValue::Null
49 } else {
50 JsonValue::JsonString(line_file.1.as_ref().to_string())
51 }
52}
53
54fn render_json_primitive(v: &JsonValue) -> String {
55 match v {
56 JsonValue::Null => "null".to_string(),
57 JsonValue::Bool(b) => b.to_string(),
58 JsonValue::Number(n) => n.to_string(),
59 JsonValue::JsonString(s) => json_string_literal(s),
60 JsonValue::Array(_) | JsonValue::Object(_) => {
61 unreachable!("render_json_primitive: non-primitive")
62 }
63 }
64}
65
66pub fn line_file_line_json_fragment(line_file: &LineFile) -> String {
68 render_json_primitive(&line_file_line_json_value(line_file))
69}
70
71pub fn line_file_source_json_fragment(line_file: &LineFile) -> String {
73 render_json_primitive(&line_file_source_json_value(line_file))
74}
75
76pub fn render_json_value(v: &JsonValue, depth: usize) -> String {
78 match v {
79 JsonValue::Object(fields) => {
80 let indent_outer = json_one_level_indent(depth);
81 let indent_inner = json_one_level_indent(depth + 1);
82 let mut field_lines: Vec<String> = Vec::new();
83 for (key, field_value) in fields.iter() {
84 let line = match field_value {
85 JsonValue::Array(items) => {
86 if items.is_empty() {
87 format!("{}\"{}\": []", indent_inner, key)
88 } else {
89 let mut line = format!("{}\"{}\": [\n", indent_inner, key);
90 for (i, item) in items.iter().enumerate() {
91 if i > 0 {
92 line.push_str(",\n");
93 }
94 match item {
95 JsonValue::Object(_) => {
96 line.push_str(&render_json_value(item, depth + 2));
97 }
98 _ => {
99 line.push_str(&json_one_level_indent(depth + 2));
100 line.push_str(&render_json_primitive(item));
101 }
102 }
103 }
104 line.push('\n');
105 line.push_str(&indent_inner);
106 line.push(']');
107 line
108 }
109 }
110 JsonValue::Object(_) => {
111 format!(
112 "{}\"{}\": {}",
113 indent_inner,
114 key,
115 render_json_value(field_value, depth + 1)
116 )
117 }
118 _ => {
119 format!(
120 "{}\"{}\": {}",
121 indent_inner,
122 key,
123 render_json_primitive(field_value)
124 )
125 }
126 };
127 field_lines.push(line);
128 }
129 format!(
130 "{}{{\n{}\n{}}}",
131 indent_outer,
132 field_lines.join(",\n"),
133 indent_outer
134 )
135 }
136 JsonValue::Array(_) => {
137 unreachable!("render_json_value: Array only appears as object field value")
138 }
139 JsonValue::Null | JsonValue::Bool(_) | JsonValue::Number(_) | JsonValue::JsonString(_) => {
140 render_json_primitive(v)
141 }
142 }
143}