blkar_lib/
json_printer.rs

1use 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}