extern crate rustc_serialize;
use std::io::{self,Read,Write};
use std::mem::swap;
use rustc_serialize::json as json;
pub struct Prettifier {
token: Option<json::JsonEvent>,
}
fn spaces(wr: &mut io::Write, n: u32) -> io::Result<()> {
let mut n = n as usize;
const BUF: &'static [u8] = b" ";
while n >= BUF.len() {
try!(wr.write(BUF));
n -= BUF.len();
}
if n > 0 {
try!(wr.write(&BUF[..n]));
}
Ok(())
}
pub fn escape_bytes(wr: &mut io::Write, bytes: &[u8]) -> io::Result<()> {
try!(wr.write_all(b"\""));
let mut start = 0;
for (i, byte) in bytes.iter().enumerate() {
let escaped = match *byte {
b'"' => b"\\\"",
b'\\' => b"\\\\",
b'\x08' => b"\\b",
b'\x0c' => b"\\f",
b'\n' => b"\\n",
b'\r' => b"\\r",
b'\t' => b"\\t",
_ => { continue; }
};
if start < i {
try!(wr.write_all(&bytes[start..i]));
}
try!(wr.write_all(escaped));
start = i + 1;
}
if start != bytes.len() {
try!(wr.write_all(&bytes[start..]));
}
try!(wr.write_all(b"\""));
Ok(())
}
pub fn escape_str(wr: &mut io::Write, value: &str) -> io::Result<()> {
escape_bytes(wr, value.as_bytes())
}
impl Prettifier {
pub fn new() -> Prettifier {
Prettifier { token: None, }
}
pub fn stream(&mut self, src: &mut io::Read, dest: &mut io::Write) -> Result<(), json::BuilderError> {
let mut parser = json::Parser::new(src.bytes().map(|c| c.unwrap() as char));
self.bump(parser.next());
let result = self.build_value(&mut parser, dest, 0);
self.bump(parser.next());
match self.token.take() {
None => {}
Some(json::JsonEvent::Error(e)) => { return Err(e); }
_ => {
return Err(
json::ParserError::SyntaxError(
json::ErrorCode::InvalidSyntax, 0, 0)); }
}
result
}
fn bump(&mut self, token: Option<json::JsonEvent>) {
self.token = token;
}
fn build_value<T>(&mut self, parser: &mut json::Parser<T>, dest: &mut io::Write, curr_indent: u32)
-> Result<(), json::BuilderError>
where T: Iterator<Item = char>
{
return match self.token.take() {
Some(json::JsonEvent::NullValue) => {try!(write!(dest, "null")); Ok(())},
Some(json::JsonEvent::I64Value(n)) => {try!(write!(dest, "{}", n)); Ok(())},
Some(json::JsonEvent::U64Value(n)) => {try!(write!(dest, "{}", n)); Ok(())},
Some(json::JsonEvent::F64Value(n)) => {try!(write!(dest, "{}", n)); Ok(())},
Some(json::JsonEvent::BooleanValue(b)) => {
if b { try!(write!(dest, "true")) }
else { try!(write!(dest, "false"))};
Ok(())},
Some(json::JsonEvent::StringValue(ref mut s)) => {
let mut temp = String::new();
swap(s, &mut temp);
try!(escape_str(dest, &temp));
Ok(())
}
Some(json::JsonEvent::ArrayStart) => self.build_array(parser, dest, curr_indent),
Some(json::JsonEvent::ObjectStart) => self.build_object(parser, dest, curr_indent),
Some(json::JsonEvent::Error(e)) => Err(e),
Some(json::JsonEvent::ObjectEnd) =>
Err(json::ParserError::SyntaxError(
json::ErrorCode::InvalidSyntax, 0, 0)),
Some(json::JsonEvent::ArrayEnd) =>
Err(json::ParserError::SyntaxError(
json::ErrorCode::InvalidSyntax, 0, 0)),
None =>
Err(json::ParserError::SyntaxError(
json::ErrorCode::EOFWhileParsingValue, 0, 0)),
}
}
fn build_array<T>(&mut self, parser: &mut json::Parser<T>, dest: &mut io::Write, old_indent: u32)
-> Result<(), json::BuilderError>
where T: Iterator<Item = char>
{
let mut idx = 0;
let curr_indent = old_indent + 2;
self.bump(parser.next());
if let Some(json::JsonEvent::ArrayEnd) = self.token {
try!(write!(dest, "[]"));
return Ok(());
} else {
try!(write!(dest, "["));
loop {
if idx != 0 {
try!(write!(dest, ","));
}
try!(write!(dest, "\n"));
try!(spaces(dest, curr_indent));
if let Err(e) = self.build_value(parser, dest, curr_indent) {
return Err(e);
};
self.bump(parser.next());
idx += 1;
if let Some(json::JsonEvent::ArrayEnd) = self.token {
try!(write!(dest, "\n"));
try!(spaces(dest, curr_indent - 2));
try!(write!(dest, "]"));
return Ok(());
}
if None == self.token {
return Err(
json::ParserError::SyntaxError(
json::ErrorCode::EOFWhileParsingArray, 0, 0));
}
}
}
}
fn build_object<T>(&mut self, parser: &mut json::Parser<T>, dest: &mut io::Write, old_indent: u32)
-> Result<(), json::BuilderError>
where T: Iterator<Item = char>
{
let mut idx = 0;
self.bump(parser.next());
match self.token.take() {
Some(json::JsonEvent::ObjectEnd) => {
try!(write!(dest, "{{}}"));
return Ok(());
}
Some(json::JsonEvent::Error(e)) => { return Err(e); }
None => {
return Err(
json::ParserError::SyntaxError(
json::ErrorCode::EOFWhileParsingObject, 0, 0)); }
token => { self.token = token; }
}
try!(write!(dest, "{{"));
let curr_indent = old_indent + 2;
loop {
if idx != 0 {
try!(write!(dest, ","));
}
try!(write!(dest, "\n"));
try!(spaces(dest, curr_indent));
let key = match parser.stack().top() {
Some(json::StackElement::Key(k)) => { k.to_string() }
_ => { panic!("invalid state"); }
};
try!(write!(dest, "{:?}: ",key));
if let Err(e) = self.build_value(parser, dest, curr_indent) {
return Err(e);
};
self.bump(parser.next());
idx += 1;
match self.token.take() {
Some(json::JsonEvent::ObjectEnd) => {
try!(write!(dest, "\n"));
try!(spaces(dest, curr_indent - 2));
try!(write!(dest, "}}"));
return Ok(());
}
Some(json::JsonEvent::Error(e)) => { return Err(e); }
None => {
return Err(
json::ParserError::SyntaxError(
json::ErrorCode::EOFWhileParsingObject, 0, 0)); }
token => { self.token = token; }
}
}
}
}
pub fn prettify(src: &mut io::Read, dest: &mut io::Write)
-> Result<(), json::BuilderError> {
Prettifier::new().stream(src, dest)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let mut reader: &[u8] = b"[\"hello\"]";
let mut writer: Vec<u8> = vec![];
prettify(&mut reader, &mut writer).unwrap();
assert_eq!(b"[\n \"hello\"\n]", &writer[..]);
}
}