use crate::json_utils::split_key_val_pair;
use crate::misc_utils::to_camelcase;
use crate::output_channel::OutputChannel;
use smallvec::SmallVec;
use std::fmt;
use std::sync::Mutex;
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum BracketType {
Curly,
Square,
}
#[derive(Clone, Debug)]
struct JSONContext {
first_item: bool,
bracket_type: BracketType,
}
impl JSONContext {
pub fn new(bracket_type: BracketType) -> JSONContext {
JSONContext {
first_item: true,
bracket_type,
}
}
}
#[derive(Debug)]
pub struct JSONPrinter {
json_enabled: bool,
output_channel: OutputChannel,
contexts: Mutex<SmallVec<[JSONContext; 8]>>,
}
impl Clone for JSONPrinter {
fn clone(&self) -> Self {
JSONPrinter {
json_enabled: self.json_enabled,
output_channel: self.output_channel,
contexts: Mutex::new(self.contexts.lock().unwrap().clone()),
}
}
}
fn write_comma_if_not_first(f: &mut fmt::Formatter, context: &mut JSONContext) -> fmt::Result {
if !context.first_item {
write!(f, ",")?;
}
context.first_item = false;
Ok(())
}
fn bracket_type_to_str_open(bracket_type: BracketType) -> &'static str {
match bracket_type {
BracketType::Curly => "{",
BracketType::Square => "[",
}
}
fn bracket_type_to_str_close(bracket_type: BracketType) -> &'static str {
match bracket_type {
BracketType::Curly => "}",
BracketType::Square => "]",
}
}
impl JSONPrinter {
pub fn new(json_enabled: bool, output_channel: OutputChannel) -> JSONPrinter {
JSONPrinter {
json_enabled,
output_channel,
contexts: Mutex::new(SmallVec::new()),
}
}
pub fn json_enabled(&self) -> bool {
self.json_enabled
}
pub fn output_channel(&self) -> OutputChannel {
self.output_channel
}
pub fn set_output_channel(&mut self, output_channel: OutputChannel) {
self.output_channel = output_channel
}
pub fn first_item(&self) -> bool {
self.contexts.lock().unwrap().last().unwrap().first_item
}
fn print_comma_if_not_first(&self, context: &mut JSONContext) {
if !context.first_item {
print_at_output_channel!(self.output_channel => ",");
}
context.first_item = false;
}
pub fn print_open_bracket(&self, name: Option<&str>, bracket_type: BracketType) {
if !self.json_enabled {
return;
}
match self.contexts.lock().unwrap().last_mut() {
None => {}
Some(x) => self.print_comma_if_not_first(x),
}
match name {
None => {}
Some(n) => print_at_output_channel!(self.output_channel => "\"{}\": ", to_camelcase(n)),
}
println_at_output_channel!(self.output_channel => "{}", bracket_type_to_str_open(bracket_type));
self.contexts
.lock()
.unwrap()
.push(JSONContext::new(bracket_type));
}
pub fn write_open_bracket(
&self,
f: &mut fmt::Formatter,
name: Option<&str>,
bracket_type: BracketType,
) -> fmt::Result {
if !self.json_enabled {
return Ok(());
}
match self.contexts.lock().unwrap().last_mut() {
None => {}
Some(x) => write_comma_if_not_first(f, x)?,
}
match name {
None => {}
Some(n) => write!(f, "\"{}\": ", to_camelcase(n))?,
}
writeln!(f, "{}", bracket_type_to_str_open(bracket_type))?;
self.contexts
.lock()
.unwrap()
.push(JSONContext::new(bracket_type));
Ok(())
}
pub fn print_close_bracket(&self) {
if !self.json_enabled {
return;
}
let context = self.contexts.lock().unwrap().pop().unwrap();
println_at_output_channel!(self.output_channel => "{}", bracket_type_to_str_close(context.bracket_type));
}
pub fn write_close_bracket(&self, f: &mut fmt::Formatter) -> fmt::Result {
if !self.json_enabled {
return Ok(());
}
let context = self.contexts.lock().unwrap().pop().unwrap();
writeln!(f, "{}", bracket_type_to_str_close(context.bracket_type))
}
pub fn print_maybe_json(&self, force_quotes: bool, msg: &str) {
if self.json_enabled {
let mut contexts = self.contexts.lock().unwrap();
let context = contexts.last_mut().unwrap();
let (l, r): (&str, &str) = split_key_val_pair(&msg);
print_json_field!(self.output_channel => l, r, force_quotes, context.first_item);
context.first_item = false;
} else {
println_at_output_channel!(self.output_channel => "{}", msg);
}
}
pub fn write_maybe_json(
&self,
f: &mut fmt::Formatter,
force_quotes: bool,
msg: &str,
) -> fmt::Result {
if self.json_enabled {
let mut contexts = self.contexts.lock().unwrap();
let context = contexts.last_mut().unwrap();
let (l, r): (&str, &str) = split_key_val_pair(&msg);
write_json_field!(f, l, r, force_quotes, context.first_item)?;
context.first_item = false;
Ok(())
} else {
writeln!(f, "{}", msg)
}
}
}