use ast::Json;
use std::char::EncodeUtf8;
use std::error::Error;
use std::fmt;
use std::io::{self, Write};
use std::borrow::Borrow;
use std::str::Chars;
pub struct Encoder<W> {
writer: W,
stack: Stack
}
macro_rules! number {
($name: ident, f64) => {
pub fn $name(mut self, x: f64) -> EncodeResult<Encoder<W>> {
if x.is_nan() || x.is_infinite() {
return Err(EncodeError::InvalidFloat)
}
try!(self.comma_array());
try!(self.writer.write_all(x.to_string().as_bytes()));
Ok(self)
}
};
($name: ident, $ty: ty) => {
pub fn $name(mut self, x: $ty) -> EncodeResult<Encoder<W>> {
try!(self.comma_array());
try!(self.writer.write_all(x.to_string().as_bytes()));
Ok(self)
}
}
}
impl<W: Write> Encoder<W> {
pub fn new(w: W) -> Encoder<W> {
Encoder { writer: w, stack: Stack::new() }
}
pub fn into_writer(self) -> W {
self.writer
}
pub fn writer(&self) -> &W {
&self.writer
}
pub fn encode(mut self, j: &Json) -> EncodeResult<Encoder<W>> {
match *j {
Json::Null => self = try!(self.null()),
Json::Bool(x) => self = try!(self.bool(x)),
Json::Number(x) => self = try!(self.f64(x)),
Json::String(ref x) => self = try!(self.string(x.as_ref())),
Json::Array(ref xs) =>
self = try!(self.array(|mut e| {
for x in xs {
e = try!(e.encode(x))
}
Ok(e)
})),
Json::Object(ref xs) =>
self = try!(self.object(|mut e| {
for (k, v) in xs {
e = try!(e.key(k.as_ref()));
e = try!(e.encode(v))
}
Ok(e)
}))
}
Ok(self)
}
number!(u8, u8);
number!(u16, u16);
number!(u32, u32);
number!(u64, u64);
number!(usize, usize);
number!(i8, i8);
number!(i16, i16);
number!(i32, i32);
number!(i64, i64);
number!(isize, isize);
number!(f64, f64);
pub fn bool(mut self, x: bool) -> EncodeResult<Encoder<W>> {
try!(self.comma_array());
try!(self.writer.write_all(if x { b"true" } else { b"false" }));
Ok(self)
}
pub fn null(mut self) -> EncodeResult<Encoder<W>> {
try!(self.comma_array());
try!(self.writer.write_all(b"null"));
Ok(self)
}
pub fn string<S: Borrow<str>>(mut self, s: S) -> EncodeResult<Encoder<W>> {
try!(self.comma_array());
try!(self.writer.write_all(b"\""));
for x in Bytes::new(EscapedChars::new(s.borrow())) {
try!(self.writer.write_all(&[x]));
}
try!(self.writer.write_all(b"\""));
Ok(self)
}
pub fn key<S: Borrow<str>>(mut self, key: S) -> EncodeResult<Encoder<W>> {
try!(self.comma_object());
let mut e = try!(self.string(key.borrow()));
try!(e.writer.write_all(b":"));
Ok(e)
}
pub fn array<F>(mut self, mut f: F) -> EncodeResult<Encoder<W>>
where
F: FnMut(Encoder<W>) -> EncodeResult<Encoder<W>>
{
try!(self.comma_array());
try!(self.writer.write_all(b"["));
self.stack.push(Scope::A(false));
let mut e = try!(f(self));
e.stack.pop();
try!(e.writer.write_all(b"]"));
Ok(e)
}
pub fn object<F>(mut self, mut f: F) -> EncodeResult<Encoder<W>>
where
F: FnMut(Encoder<W>) -> EncodeResult<Encoder<W>>
{
try!(self.comma_array());
try!(self.writer.write_all(b"{"));
self.stack.push(Scope::O(false));
let mut e = try!(f(self));
e.stack.pop();
try!(e.writer.write_all(b"}"));
Ok(e)
}
fn comma_array(&mut self) -> EncodeResult<()> {
match self.stack.top() {
Some(Scope::A(true)) => self.writer.write_all(b",").map_err(From::from),
Some(Scope::A(false)) => {
self.stack.set();
Ok(())
}
_ => Ok(())
}
}
fn comma_object(&mut self) -> EncodeResult<()> {
match self.stack.top() {
Some(Scope::O(true)) => self.writer.write_all(b",").map_err(From::from),
Some(Scope::O(false)) => {
self.stack.set();
Ok(())
}
_ => Ok(())
}
}
}
#[derive(Debug, Copy, Clone)]
enum Scope {
A(bool), O(bool) }
struct Stack(Vec<Scope>);
impl Stack {
fn new() -> Stack {
Stack(Vec::new())
}
fn push(&mut self, s: Scope) {
self.0.push(s)
}
fn pop(&mut self) {
self.0.pop();
}
fn top(&self) -> Option<Scope> {
self.0.last().map(|x| *x)
}
fn set(&mut self) {
self.0.last_mut().map(|x| {
match *x {
Scope::A(_) => *x = Scope::A(true),
Scope::O(_) => *x = Scope::O(true)
}
});
}
}
pub type EncodeResult<A> = Result<A, EncodeError>;
#[derive(Debug)]
pub enum EncodeError {
Io(io::Error),
InvalidFloat
}
impl fmt::Display for EncodeError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
EncodeError::Io(ref e) => write!(f, "i/o: {:?}", e),
EncodeError::InvalidFloat => write!(f, "invalid f64 (NaN | Infinity)")
}
}
}
impl Error for EncodeError {
fn description(&self) -> &str {
"EncodeError"
}
fn cause(&self) -> Option<&Error> {
match *self {
EncodeError::Io(ref e) => Some(e),
_ => None
}
}
}
impl From<io::Error> for EncodeError {
fn from(e: io::Error) -> EncodeError {
EncodeError::Io(e)
}
}
struct EscapedChars<'r> {
source: Chars<'r>,
buffer: [u8; 5],
index: Option<(usize, usize)>
}
impl<'r> EscapedChars<'r> {
fn new(s: &'r str) -> EscapedChars<'r> {
EscapedChars {
source: s.chars(),
buffer: [0; 5],
index: None
}
}
fn chr(x: u8) -> u8 {
match x {
0x0 ... 0x9 => b'0' + x,
0xA ... 0xF => b'A' + x - 0xA,
_ => panic!("{} > 0xF", x)
}
}
}
impl<'r> Iterator for EscapedChars<'r> {
type Item = char;
fn next(&mut self) -> Option<char> {
match self.index {
None => (),
Some((i, e)) =>
if i < e {
self.index = Some((i + 1, e));
return Some(self.buffer[i] as char)
} else {
self.index = None
}
}
match self.source.next() {
Some(x@'\\') | Some(x@'"') => {
self.buffer[0] = x as u8;
self.index = Some((0, 1));
Some('\\')
}
Some('\n') => {
self.buffer[0] = b'n';
self.index = Some((0, 1));
Some('\\')
}
Some('\t') => {
self.buffer[0] = b't';
self.index = Some((0, 1));
Some('\\')
}
Some('\r') => {
self.buffer[0] = b'r';
self.index = Some((0, 1));
Some('\\')
}
Some(x@'\x00' ... '\x1F') | Some(x@'\x7F') => {
self.buffer[0] = b'u';
self.buffer[1] = b'0';
self.buffer[2] = b'0';
self.buffer[3] = Self::chr(x as u8 >> 4);
self.buffer[4] = Self::chr(x as u8 & 0x0F);
self.index = Some((0, 5));
Some('\\')
}
x => x
}
}
}
struct Bytes<I> {
source: I,
current: Option<EncodeUtf8>
}
impl<I> Bytes<I> {
pub fn new(i: I) -> Bytes<I> {
Bytes {
source: i,
current: None
}
}
}
impl<I: Iterator<Item=char>> Iterator for Bytes<I> {
type Item = u8;
fn next(&mut self) -> Option<u8> {
match self.current.as_mut().and_then(EncodeUtf8::next) {
None => {
self.current = self.source.next().map(char::encode_utf8);
self.current.as_mut().and_then(EncodeUtf8::next)
}
x => x
}
}
}