use std::borrow::{Borrow, Cow};
use std::error::Error;
use std::fmt;
use std::io::{self, Write};
use std::str::Chars;
use ast::Json;
use stack::{Stack, Scope};
pub trait ToJson {
fn encode<W: Write>(&self, e: &mut Encoder<W>) -> EncodeResult<()>;
}
macro_rules! instance {
($name: ident) => {
impl ToJson for $name {
fn encode<W: Write>(&self, e: &mut Encoder<W>) -> EncodeResult<()> {
e.$name(*self)
}
}
}
}
instance!(bool);
instance!(u8);
instance!(u16);
instance!(u32);
instance!(u64);
instance!(usize);
instance!(i8);
instance!(i16);
instance!(i32);
instance!(i64);
instance!(isize);
instance!(f64);
impl ToJson for str {
fn encode<W: Write>(&self, e: &mut Encoder<W>) -> EncodeResult<()> {
e.string(self)
}
}
impl ToJson for String {
fn encode<W: Write>(&self, e: &mut Encoder<W>) -> EncodeResult<()> {
e.string(self.as_str())
}
}
impl ToJson for Json {
fn encode<W: Write>(&self, e: &mut Encoder<W>) -> EncodeResult<()> {
e.encode(self)
}
}
impl<'a, T: ToJson> ToJson for &'a T {
fn encode<W: Write>(&self, e: &mut Encoder<W>) -> EncodeResult<()> {
(*self).encode(e)
}
}
impl<'a, T: ToJson + Clone> ToJson for Cow<'a, T> {
fn encode<W: Write>(&self, e: &mut Encoder<W>) -> EncodeResult<()> {
(**self).encode(e)
}
}
impl<T: ToJson> ToJson for Option<T> {
fn encode<W: Write>(&self, e: &mut Encoder<W>) -> EncodeResult<()> {
e.optional(self.as_ref())
}
}
impl<'a, T: ToJson> ToJson for &'a [T] {
fn encode<W: Write>(&self, e: &mut Encoder<W>) -> EncodeResult<()> {
e.array()?;
for x in *self {
x.encode(e)?
}
e.end()
}
}
pub struct Encoder<W> {
writer: W,
stack: Stack
}
macro_rules! number {
($name: ident, f64) => {
pub fn $name(&mut self, x: f64) -> EncodeResult<()> {
if x.is_nan() || x.is_infinite() {
return Err(EncodeError::InvalidFloat)
}
self.comma_array()?;
self.writer.write_all(x.to_string().as_bytes())?;
Ok(())
}
};
($name: ident, $ty: ty) => {
pub fn $name(&mut self, x: $ty) -> EncodeResult<()> {
self.comma_array()?;
self.writer.write_all(x.to_string().as_bytes())?;
Ok(())
}
}
}
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_mut(&mut self) -> &mut W {
&mut self.writer
}
pub fn to_json<T: ToJson>(&mut self, t: T) -> EncodeResult<()> {
t.encode(self)
}
pub fn encode(&mut self, j: &Json) -> EncodeResult<()> {
match *j {
Json::Null => self.null()?,
Json::Bool(x) => self.bool(x)?,
Json::Number(x) => self.f64(x)?,
Json::String(ref x) => self.string(x.as_ref())?,
Json::Array(ref xs) => {
self.array()?;
for x in xs {
self.encode(x)?
}
self.end()?
}
Json::Object(ref xs) => {
self.object()?;
for (k, v) in xs {
self.key(k.as_ref())?;
self.encode(v)?
}
self.end()?
}
}
Ok(())
}
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<()> {
self.comma_array()?;
self.writer.write_all(if x { b"true" } else { b"false" })?;
Ok(())
}
pub fn null(&mut self) -> EncodeResult<()> {
self.comma_array()?;
self.writer.write_all(b"null")?;
Ok(())
}
pub fn optional<T: ToJson>(&mut self, val: Option<T>) -> EncodeResult<()> {
match val {
None => self.null(),
Some(ref v) => self.to_json(v)
}
}
pub fn string<S: Borrow<str>>(&mut self, s: S) -> EncodeResult<()> {
self.comma_array()?;
self.writer.write_all(b"\"")?;
for x in Bytes::new(EscapedChars::new(s.borrow())) {
self.writer.write_all(&[x])?;
}
self.writer.write_all(b"\"")?;
Ok(())
}
pub fn key<S: Borrow<str>>(&mut self, key: S) -> EncodeResult<()> {
self.comma_object()?;
self.string(key.borrow())?;
self.writer.write_all(b":")?;
Ok(())
}
pub fn array(&mut self) -> EncodeResult<()> {
self.comma_array()?;
self.writer.write_all(b"[")?;
self.stack.push(Scope::A(false));
Ok(())
}
pub fn object(&mut self) -> EncodeResult<()> {
self.comma_array()?;
self.writer.write_all(b"{")?;
self.stack.push(Scope::O(false));
Ok(())
}
pub fn end(&mut self) -> EncodeResult<()> {
match self.stack.pop() {
Some(Scope::A(_)) =>
self.writer.write_all(b"]").map_err(From::from),
Some(Scope::O(_)) =>
self.writer.write_all(b"}").map_err(From::from),
None => Ok(())
}
}
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(())
}
}
}
pub type EncodeResult<A> = Result<A, EncodeError>;
#[derive(Debug)]
pub enum EncodeError {
Io(io::Error),
InvalidFloat,
Message(&'static str),
Other(Box<Error + Send + Sync>)
}
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)"),
EncodeError::Message(m) => write!(f, "error: {}", m),
EncodeError::Other(ref e) => write!(f, "other: {}", e)
}
}
}
impl Error for EncodeError {
fn description(&self) -> &str {
match *self {
EncodeError::Io(_) => "i/o error",
EncodeError::InvalidFloat => "invalid float value (e.g. NAN or INFINITY)",
EncodeError::Message(_) => "generic error message",
EncodeError::Other(_) => "other error"
}
}
fn cause(&self) -> Option<&Error> {
match *self {
EncodeError::Io(ref e) => Some(e),
EncodeError::Other(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> {
src: I,
buf: [u8; 4],
pos: usize,
end: usize
}
impl<I> Bytes<I> {
pub fn new(i: I) -> Bytes<I> {
Bytes {
src: i,
buf: [0; 4],
pos: 0,
end: 0
}
}
}
impl<I: Iterator<Item=char>> Iterator for Bytes<I> {
type Item = u8;
fn next(&mut self) -> Option<u8> {
if self.pos == self.end {
match self.src.next() {
Some(c) => {
self.end = c.encode_utf8(&mut self.buf).len();
debug_assert!(self.end > 0);
self.pos = 0
}
None => return None
}
}
let x = self.buf[self.pos];
self.pos += 1;
Some(x)
}
}