#![allow(dead_code)]
use std::ops::Sub;
use crate::base::{JsonArray, JsonObject, JsonValue};
pub struct JsonFormatter {
indent: usize,
indent_char: char,
current_indent: usize,
}
impl JsonFormatter {
pub fn builder() -> JsonFormatterBuilder {
JsonFormatterBuilder::new()
}
pub fn format(&mut self, target: &JsonValue) -> String {
self.current_indent = self.indent;
self.format_value(target, self.current_indent, false)
}
fn pretty_object(&mut self, json_object: &JsonObject, indent_level: usize, is_child: bool) -> String {
let mut s = String::new();
let mut data = json_object.iter().peekable();
s.push_str("{\n");
while let Some((k, v)) = data.next() {
self.current_indent = indent_level + self.indent;
s.push_str(&self.indent_str().repeat(indent_level));
s.push_str(&format!("\"{}\": {}", k, self.format_value(v, self.current_indent, true)));
if data.peek().is_some() {
s.push_str(",\n");
}
}
s.push('\n');
if is_child {
s.push_str(&self.indent_str().repeat(indent_level.sub(self.indent)));
}
s.push('}');
s
}
fn pretty_array(&mut self, json_array: &JsonArray, indent_level: usize, is_child: bool) -> String {
let mut s = String::new();
let mut data = json_array.iter().peekable();
s.push_str("[\n");
while let Some(json_value) = data.next() {
self.current_indent = indent_level + self.indent;
s.push_str(&self.indent_str().repeat(indent_level));
s.push_str(&self.format_value(json_value, self.current_indent, true));
if data.peek().is_some() {
s.push_str(",\n");
}
}
s.push('\n');
if is_child {
s.push_str(&self.indent_str().repeat(indent_level.sub(self.indent)));
}
s.push(']');
s
}
fn format_value(&mut self, json_value: &JsonValue, indent_level: usize, is_child: bool) -> String {
match json_value {
JsonValue::String(v) => format!("\"{}\"", v),
JsonValue::Number(v) => v.to_string(),
JsonValue::Boolean(v) => v.to_string(),
JsonValue::Object(v) => self.pretty_object(v, indent_level, is_child),
JsonValue::Array(v) => self.pretty_array(v, indent_level, is_child),
JsonValue::Null => "null".to_string(),
}
}
fn indent_str(&self) -> String {
self.indent_char.to_string().repeat(self.indent)
}
}
pub struct JsonFormatterBuilder {
indent: usize,
indent_char: char,
}
impl JsonFormatterBuilder {
pub fn new() -> Self {
JsonFormatterBuilder {
indent: 0,
indent_char: '\0',
}
}
pub fn with_indent(mut self, indent: usize) -> Self {
self.indent = indent;
self
}
pub fn with_indent_char(mut self, char: char) -> Self {
self.indent_char = char;
self
}
pub fn build(self) -> JsonFormatter {
JsonFormatter {
indent: self.indent,
indent_char: self.indent_char,
current_indent: 0,
}
}
}
impl Default for JsonFormatter {
fn default() -> Self {
JsonFormatterBuilder::new()
.with_indent(2)
.with_indent_char(' ')
.build()
}
}