use crate::lexer::{get_string_quote_type, StringQuoteType};
use std::io;
pub struct Printer<'l, W: 'l>
{
writer: &'l mut W,
depth: u32,
in_array: Vec<bool>,
one_line: Vec<bool>,
is_empty: Vec<bool>,
in_root: bool,
}
impl<'l, W: io::Write> Printer<'l, W>
{
pub fn new(writer: &'l mut W) -> Printer<'l, W>
{
Printer {
writer: writer,
depth: 0,
in_array: vec![false],
one_line: vec![false],
is_empty: vec![true],
in_root: false,
}
}
fn write_indent(&mut self) -> Result<(), io::Error>
{
for _ in 0..self.depth
{
write!(self.writer, "\t")?;
}
Ok(())
}
fn in_array(&self) -> bool
{
self.in_array[self.in_array.len() - 1]
}
fn one_line(&self) -> bool
{
self.one_line[self.one_line.len() - 1]
}
fn is_empty(&self) -> bool
{
self.is_empty[self.is_empty.len() - 1]
}
fn set_empty(&mut self, empty: bool)
{
let l = self.is_empty.len();
self.is_empty[l - 1] = empty;
}
fn start_value(&mut self) -> Result<(), io::Error>
{
if (self.in_array() || self.one_line()) && !self.is_empty()
{
write!(self.writer, ",")?;
}
if !self.one_line()
{
if !(self.depth == 0 && self.in_root && self.is_empty())
{
write!(self.writer, "\n")?;
}
self.write_indent()?;
}
else
{
if !self.is_empty()
{
write!(self.writer, " ")?;
}
}
Ok(())
}
fn write_string(&mut self, s: &str) -> Result<(), io::Error>
{
match get_string_quote_type(s)
{
StringQuoteType::Naked => write!(self.writer, "{}", s)?,
StringQuoteType::Quoted(num_braces) =>
{
for _ in 0..num_braces
{
write!(self.writer, "{{")?;
}
write!(self.writer, r#""{}""#, s)?;
for _ in 0..num_braces
{
write!(self.writer, "}}")?;
}
}
}
Ok(())
}
pub fn value(&mut self, name: Option<&str>, value: &str) -> Result<(), io::Error>
{
self.start_value()?;
match name
{
Some(name) =>
{
self.write_string(name)?;
write!(self.writer, " = ")?;
}
_ => (),
}
self.write_string(value)?;
self.set_empty(false);
Ok(())
}
pub fn start_array(&mut self, name: Option<&str>, one_line: bool) -> Result<(), io::Error>
{
self.start_value()?;
match name
{
Some(name) =>
{
self.write_string(name)?;
write!(self.writer, " =")?;
if one_line
{
write!(self.writer, " ")?;
}
else
{
write!(self.writer, "\n")?;
self.write_indent()?;
}
}
_ => (),
}
write!(self.writer, "[")?;
self.set_empty(false);
self.depth += 1;
self.in_array.push(true);
self.is_empty.push(true);
self.one_line.push(one_line);
Ok(())
}
pub fn start_tagged_array(
&mut self, name: Option<&str>, tag: &str, one_line: bool,
) -> Result<(), io::Error>
{
self.start_value()?;
match name
{
Some(name) =>
{
self.write_string(name)?;
write!(self.writer, " = ")?;
}
_ => (),
}
self.write_string(tag)?;
if one_line
{
write!(self.writer, " ")?;
}
else
{
write!(self.writer, "\n")?;
self.write_indent()?;
}
write!(self.writer, "[")?;
self.set_empty(false);
self.depth += 1;
self.in_array.push(true);
self.is_empty.push(true);
self.one_line.push(one_line);
Ok(())
}
pub fn start_tagged_table(
&mut self, name: Option<&str>, tag: &str, is_root: bool, one_line: bool,
) -> Result<(), io::Error>
{
if is_root
{
self.in_root = true;
return Ok(());
}
self.start_value()?;
match name
{
Some(name) =>
{
self.write_string(name)?;
write!(self.writer, " = ")?;
}
_ => (),
}
self.write_string(tag)?;
if one_line
{
write!(self.writer, " ")?;
}
else
{
write!(self.writer, "\n")?;
self.write_indent()?;
}
write!(self.writer, "{{")?;
self.set_empty(false);
self.depth += 1;
self.in_array.push(false);
self.is_empty.push(true);
self.one_line.push(one_line);
Ok(())
}
pub fn end_array(&mut self) -> Result<(), io::Error>
{
if !self.one_line() && !self.is_empty()
{
write!(self.writer, "\n")?;
}
self.depth -= 1;
if !self.one_line() && !self.is_empty()
{
self.write_indent()?;
}
self.in_array.pop();
self.is_empty.pop();
self.one_line.pop();
write!(self.writer, "]")?;
Ok(())
}
pub fn start_table(
&mut self, name: Option<&str>, is_root: bool, one_line: bool,
) -> Result<(), io::Error>
{
if is_root
{
self.in_root = true;
return Ok(());
}
self.start_value()?;
match name
{
Some(name) =>
{
self.write_string(name)?;
if one_line
{
write!(self.writer, " ")?;
}
else
{
write!(self.writer, "\n")?;
self.write_indent()?;
}
}
_ => (),
}
write!(self.writer, "{{")?;
self.set_empty(false);
self.depth += 1;
self.in_array.push(false);
self.is_empty.push(true);
self.one_line.push(one_line);
Ok(())
}
pub fn end_table(&mut self, is_root: bool) -> Result<(), io::Error>
{
if !self.one_line() && !self.is_empty()
{
write!(self.writer, "\n")?;
}
if is_root
{
return Ok(());
}
self.depth -= 1;
if !self.one_line() && !self.is_empty()
{
self.write_indent()?;
}
self.in_array.pop();
self.is_empty.pop();
self.one_line.pop();
write!(self.writer, "}}")?;
Ok(())
}
}