blkar_lib/
json_printer.rs1use smallvec::SmallVec;
2use json_utils::split_key_val_pair;
3
4use std::sync::Mutex;
5
6use misc_utils::to_camelcase;
7
8use std::fmt;
9
10use output_channel::OutputChannel;
11
12#[derive(Copy, Clone, PartialEq, Debug)]
13pub enum BracketType {
14 Curly,
15 Square,
16}
17
18#[derive(Clone, Debug)]
19struct JSONContext {
20 first_item : bool,
21 bracket_type : BracketType,
22}
23
24impl JSONContext {
25 pub fn new(bracket_type : BracketType) -> JSONContext {
26 JSONContext {
27 first_item : true,
28 bracket_type,
29 }
30 }
31}
32
33#[derive(Debug)]
34pub struct JSONPrinter {
35 json_enabled : bool,
36 output_channel : OutputChannel,
37 contexts : Mutex<SmallVec<[JSONContext; 8]>>
38}
39
40impl Clone for JSONPrinter {
41 fn clone(&self) -> Self {
42 JSONPrinter {
43 json_enabled : self.json_enabled,
44 output_channel : self.output_channel,
45 contexts : Mutex::new(self.contexts.lock().unwrap().clone())
46 }
47 }
48}
49
50fn write_comma_if_not_first(f : &mut fmt::Formatter,
51 context : &mut JSONContext)
52 -> fmt::Result {
53 if !context.first_item {
54 write!(f, ",")?;
55 }
56 context.first_item = false;
57
58 Ok(())
59}
60
61fn bracket_type_to_str_open(bracket_type : BracketType) -> &'static str {
62 match bracket_type {
63 BracketType::Curly => "{",
64 BracketType::Square => "[",
65 }
66}
67
68fn bracket_type_to_str_close(bracket_type : BracketType) -> &'static str {
69 match bracket_type {
70 BracketType::Curly => "}",
71 BracketType::Square => "]",
72 }
73}
74
75impl JSONPrinter {
76 pub fn new(json_enabled : bool, output_channel : OutputChannel) -> JSONPrinter {
77 JSONPrinter {
78 json_enabled,
79 output_channel,
80 contexts : Mutex::new(SmallVec::new()),
81 }
82 }
83
84 pub fn json_enabled(&self) -> bool {
85 self.json_enabled
86 }
87
88 pub fn output_channel(&self) -> OutputChannel {
89 self.output_channel
90 }
91
92 pub fn set_output_channel(&mut self, output_channel : OutputChannel) {
93 self.output_channel = output_channel
94 }
95
96 pub fn first_item(&self) -> bool {
97 self.contexts.lock().unwrap().last().unwrap().first_item
98 }
99
100 fn print_comma_if_not_first(&self, context : &mut JSONContext) {
101 if !context.first_item {
102 print_at_output_channel!(self.output_channel => ",");
103 }
104 context.first_item = false;
105 }
106
107 pub fn print_open_bracket(&self,
108 name : Option<&str>,
109 bracket_type : BracketType) {
110 if !self.json_enabled { return; }
111
112 match self.contexts.lock().unwrap().last_mut() {
113 None => {},
114 Some(x) => self.print_comma_if_not_first(x)
115 }
116
117 match name {
118 None => {},
119 Some(n) => print_at_output_channel!(self.output_channel => "\"{}\": ", to_camelcase(n))
120 }
121
122 println_at_output_channel!(self.output_channel => "{}", bracket_type_to_str_open(bracket_type));
123
124 self.contexts.lock().unwrap().push(JSONContext::new(bracket_type));
125 }
126
127 pub fn write_open_bracket(&self,
128 f : &mut fmt::Formatter,
129 name : Option<&str>,
130 bracket_type : BracketType) -> fmt::Result {
131 if !self.json_enabled { return Ok(()); }
132
133 match self.contexts.lock().unwrap().last_mut() {
134 None => {},
135 Some(x) => write_comma_if_not_first(f, x)?
136 }
137
138 match name {
139 None => {},
140 Some(n) => write!(f, "\"{}\": ", to_camelcase(n))?
141 }
142
143 writeln!(f, "{}", bracket_type_to_str_open(bracket_type))?;
144
145 self.contexts.lock().unwrap().push(JSONContext::new(bracket_type));
146
147 Ok(())
148 }
149
150 pub fn print_close_bracket(&self) {
151 if !self.json_enabled { return; }
152
153 let context = self.contexts.lock().unwrap().pop().unwrap();
154
155 println_at_output_channel!(self.output_channel => "{}", bracket_type_to_str_close(context.bracket_type));
156 }
157
158 pub fn write_close_bracket(&self,
159 f : &mut fmt::Formatter) -> fmt::Result {
160 if !self.json_enabled { return Ok(()); }
161
162 let context = self.contexts.lock().unwrap().pop().unwrap();
163
164 writeln!(f, "{}", bracket_type_to_str_close(context.bracket_type))
165 }
166
167 pub fn print_maybe_json(&self,
168 skip_quotes : bool,
169 msg : &str) {
170 if self.json_enabled {
171 let mut contexts = self.contexts.lock().unwrap();
172 let context = contexts.last_mut().unwrap();
173
174 let (l, r) : (&str, &str) = split_key_val_pair(&msg);
175
176 print_json_field!(self.output_channel => l, r, skip_quotes, context.first_item);
177
178 context.first_item = false;
179 } else {
180 println_at_output_channel!(self.output_channel => "{}", msg);
181 }
182 }
183
184 pub fn write_maybe_json(&self,
185 f : &mut fmt::Formatter,
186 skip_quotes : bool,
187 msg : &str) -> fmt::Result {
188 if self.json_enabled {
189 let mut contexts = self.contexts.lock().unwrap();
190 let context = contexts.last_mut().unwrap();
191
192 let (l, r) : (&str, &str) = split_key_val_pair(&msg);
193
194 write_json_field!(f, l, r, skip_quotes, context.first_item)?;
195
196 context.first_item = false;
197
198 Ok(())
199 } else {
200 writeln!(f, "{}", msg)
201 }
202 }
203}