use std::io::prelude::*;
use std::io::Error;
use std::io::ErrorKind;
use crate::utils::BUFFER_SIZE;
const C_CR: u8 = b'\r';
const C_LF: u8 = b'\n';
const C_TAB: u8 = b'\t';
const C_SPACE: u8 = b' ';
const C_COMMA: u8 = b',';
const C_COLON: u8 = b':';
const C_QUOTE: u8 = b'"';
const C_BACKSLASH: u8 = b'\\';
const C_LEFT_BRACE: u8 = b'{';
const C_LEFT_BRACKET: u8 = b'[';
const C_RIGHT_BRACE: u8 = b'}';
const C_RIGHT_BRACKET: u8 = b']';
pub struct Formatter {
pub indent: String,
pub line_separator: String,
pub record_separator: String,
pub after_colon: String,
pub trailing_output: String,
pub eager_record_separators: bool,
depth: usize, in_string: bool, in_backslash: bool, empty: bool, first: bool, }
impl Formatter {
fn default() -> Formatter {
Formatter {
indent: String::from(" "),
line_separator: String::from("\n"),
record_separator: String::from("\n"),
after_colon: String::from(" "),
trailing_output: String::from(""),
eager_record_separators: false,
depth: 0,
in_string: false,
in_backslash: false,
empty: false,
first: true,
}
}
pub fn pretty_printer() -> Formatter {
Formatter::default()
}
pub fn format_stream_unbuffered(
&mut self,
input: &mut impl Read,
output: &mut impl Write,
) -> Result<(), Error> {
let mut buf = [0_u8; BUFFER_SIZE];
loop {
match input.read(&mut buf) {
Ok(0) => {
break;
}
Ok(n) => {
self.format_buf(&buf[0..n], output)?;
}
Err(e) if e.kind() == ErrorKind::Interrupted => {
continue;
}
Err(e) => {
return Err(e);
}
}
}
output.write_all(self.trailing_output.as_bytes())?;
Ok(())
}
pub fn format_buf(&mut self, buf: &[u8], writer: &mut impl Write) -> Result<(), Error> {
let mut n = 0;
while n < buf.len() {
let b = buf[n];
if self.in_string {
if self.in_backslash {
writer.write_all(&buf[n..n + 1])?;
self.in_backslash = false;
} else {
match memchr::memchr2(C_QUOTE, C_BACKSLASH, &buf[n..]) {
None => {
writer.write_all(&buf[n..])?;
break;
}
Some(index) => {
let length = index + 1;
writer.write_all(&buf[n..n + length])?;
if buf[n + index] == C_QUOTE {
self.in_string = false;
} else {
self.in_backslash = true;
}
n += length;
continue;
}
}
}
} else {
match b {
C_SPACE | C_LF | C_CR | C_TAB => {
}
C_LEFT_BRACKET | C_LEFT_BRACE => {
if self.first {
self.first = false;
writer.write_all(&buf[n..n + 1])?;
} else if self.empty {
writer.write_all(self.line_separator.as_bytes())?;
for _ in 0..self.depth {
writer.write_all(self.indent.as_bytes())?;
}
writer.write_all(&buf[n..n + 1])?;
} else if !self.eager_record_separators && self.depth == 0 {
writer.write_all(self.record_separator.as_bytes())?;
writer.write_all(&buf[n..n + 1])?;
} else {
writer.write_all(&buf[n..n + 1])?;
}
self.depth += 1;
self.empty = true;
}
C_RIGHT_BRACKET | C_RIGHT_BRACE => {
self.depth = self.depth.saturating_sub(1);
if self.empty {
self.empty = false;
writer.write_all(&buf[n..n + 1])?;
} else {
writer.write_all(self.line_separator.as_bytes())?;
for _ in 0..self.depth {
writer.write_all(self.indent.as_bytes())?;
}
writer.write_all(&buf[n..n + 1])?;
}
if self.eager_record_separators && self.depth == 0 {
writer.write_all(self.record_separator.as_bytes())?;
}
}
C_COMMA => {
writer.write_all(&buf[n..n + 1])?;
writer.write_all(self.line_separator.as_bytes())?;
for _ in 0..self.depth {
writer.write_all(self.indent.as_bytes())?;
}
}
C_COLON => {
writer.write_all(&buf[n..n + 1])?;
writer.write_all(self.after_colon.as_bytes())?;
}
_ => {
if self.empty {
writer.write_all(self.line_separator.as_bytes())?;
for _ in 0..self.depth {
writer.write_all(self.indent.as_bytes())?;
}
self.empty = false;
}
if b == C_QUOTE {
self.in_string = true;
}
writer.write_all(&buf[n..n + 1])?;
}
};
};
n += 1;
}
Ok(())
}
}