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
76fn render_json_array(items: &[JsonValue], depth: usize) -> String {
77 let indent_outer = json_one_level_indent(depth);
78 let indent_inner = json_one_level_indent(depth + 1);
79 if items.is_empty() {
80 return "[]".to_string();
81 }
82
83 let mut output = String::from("[\n");
84 for (i, item) in items.iter().enumerate() {
85 if i > 0 {
86 output.push_str(",\n");
87 }
88 match item {
89 JsonValue::Object(_) => output.push_str(&render_json_value(item, depth + 1)),
90 JsonValue::Array(nested_items) => {
91 output.push_str(&indent_inner);
92 output.push_str(&render_json_array(nested_items, depth + 1));
93 }
94 _ => {
95 output.push_str(&indent_inner);
96 output.push_str(&render_json_primitive(item));
97 }
98 }
99 }
100 output.push('\n');
101 output.push_str(&indent_outer);
102 output.push(']');
103 output
104}
105
106pub fn render_json_value(v: &JsonValue, depth: usize) -> String {
108 match v {
109 JsonValue::Object(fields) => {
110 let indent_outer = json_one_level_indent(depth);
111 let indent_inner = json_one_level_indent(depth + 1);
112 let mut field_lines: Vec<String> = Vec::new();
113 for (key, field_value) in fields.iter() {
114 let line = match field_value {
115 JsonValue::Array(items) => {
116 if items.is_empty() {
117 format!("{}\"{}\": []", indent_inner, key)
118 } else {
119 format!(
120 "{}\"{}\": {}",
121 indent_inner,
122 key,
123 render_json_array(items, depth + 1)
124 )
125 }
126 }
127 JsonValue::Object(_) => {
128 let rendered = render_json_value(field_value, depth + 1);
129 let rendered = rendered
130 .strip_prefix(indent_inner.as_str())
131 .unwrap_or(rendered.as_str());
132 format!("{}\"{}\": {}", indent_inner, key, rendered)
133 }
134 _ => {
135 format!(
136 "{}\"{}\": {}",
137 indent_inner,
138 key,
139 render_json_primitive(field_value)
140 )
141 }
142 };
143 field_lines.push(line);
144 }
145 format!(
146 "{}{{\n{}\n{}}}",
147 indent_outer,
148 field_lines.join(",\n"),
149 indent_outer
150 )
151 }
152 JsonValue::Array(_) => {
153 unreachable!("render_json_value: Array only appears as object field value")
154 }
155 JsonValue::Null | JsonValue::Bool(_) | JsonValue::Number(_) | JsonValue::JsonString(_) => {
156 render_json_primitive(v)
157 }
158 }
159}