diff --git a/serde2/src/json/builder.rs b/serde2/src/json/builder.rs new file mode 100644 index 00000000..c66b63bc --- /dev/null +++ b/serde2/src/json/builder.rs @@ -0,0 +1,131 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::collections::TreeMap; +use std::str::StrAllocating; + +use ser::{mod, Serialize}; +use json::value::{mod, Value}; + +pub struct ArrayBuilder { + array: Vec, +} + +impl ArrayBuilder { + pub fn new() -> ArrayBuilder { + ArrayBuilder { array: Vec::new() } + } + + pub fn unwrap(self) -> Value { + Value::Array(self.array) + } + + pub fn push(mut self, v: T) -> ArrayBuilder { + self.array.push(value::to_value(&v)); + self + } + + pub fn push_array(mut self, f: |ArrayBuilder| -> ArrayBuilder) -> ArrayBuilder { + let builder = ArrayBuilder::new(); + self.array.push(f(builder).unwrap()); + self + } + + pub fn push_object(mut self, f: |ObjectBuilder| -> ObjectBuilder) -> ArrayBuilder { + let builder = ObjectBuilder::new(); + self.array.push(f(builder).unwrap()); + self + } +} + +pub struct ObjectBuilder { + object: TreeMap, +} + +impl ObjectBuilder { + pub fn new() -> ObjectBuilder { + ObjectBuilder { object: TreeMap::new() } + } + + pub fn unwrap(self) -> Value { + Value::Object(self.object) + } + + pub fn insert(mut self, k: K, v: V) -> ObjectBuilder { + self.object.insert(k.into_string(), value::to_value(&v)); + self + } + + pub fn insert_array(mut self, key: S, f: |ArrayBuilder| -> ArrayBuilder) -> ObjectBuilder { + let builder = ArrayBuilder::new(); + self.object.insert(key.into_string(), f(builder).unwrap()); + self + } + + pub fn insert_object(mut self, key: S, f: |ObjectBuilder| -> ObjectBuilder) -> ObjectBuilder { + let builder = ObjectBuilder::new(); + self.object.insert(key.into_string(), f(builder).unwrap()); + self + } +} + +#[cfg(test)] +mod tests { + use std::collections::TreeMap; + + use json::value::Value; + use super::{ArrayBuilder, ObjectBuilder}; + + #[test] + fn test_array_builder() { + let value = ArrayBuilder::new().unwrap(); + assert_eq!(value, Value::Array(Vec::new())); + + let value = ArrayBuilder::new() + .push(1i) + .push(2i) + .push(3i) + .unwrap(); + assert_eq!(value, Value::Array(vec!(Value::I64(1), Value::I64(2), Value::I64(3)))); + + let value = ArrayBuilder::new() + .push_array(|bld| bld.push(1i).push(2i).push(3i)) + .unwrap(); + assert_eq!(value, Value::Array(vec!(Value::Array(vec!(Value::I64(1), Value::I64(2), Value::I64(3)))))); + + let value = ArrayBuilder::new() + .push_object(|bld| + bld + .insert("a".to_string(), 1i) + .insert("b".to_string(), 2i)) + .unwrap(); + + let mut map = TreeMap::new(); + map.insert("a".to_string(), Value::I64(1)); + map.insert("b".to_string(), Value::I64(2)); + assert_eq!(value, Value::Array(vec!(Value::Object(map)))); + } + + #[test] + fn test_object_builder() { + let value = ObjectBuilder::new().unwrap(); + assert_eq!(value, Value::Object(TreeMap::new())); + + let value = ObjectBuilder::new() + .insert("a".to_string(), 1i) + .insert("b".to_string(), 2i) + .unwrap(); + + let mut map = TreeMap::new(); + map.insert("a".to_string(), Value::I64(1)); + map.insert("b".to_string(), Value::I64(2)); + assert_eq!(value, Value::Object(map)); + } +} diff --git a/serde2/src/json/error.rs b/serde2/src/json/error.rs new file mode 100644 index 00000000..911f94d2 --- /dev/null +++ b/serde2/src/json/error.rs @@ -0,0 +1,126 @@ +use std::error; +use std::fmt; +use std::io; + +/// The errors that can arise while parsing a JSON stream. +#[deriving(Clone, PartialEq)] +pub enum ErrorCode { + EOFWhileParsingList, + EOFWhileParsingObject, + EOFWhileParsingString, + EOFWhileParsingValue, + ExpectedColon, + ExpectedConversion, + ExpectedEnumEnd, + ExpectedEnumEndToken, + ExpectedEnumMapStart, + ExpectedEnumToken, + ExpectedEnumVariantString, + ExpectedListCommaOrEnd, + ExpectedName, + ExpectedObjectCommaOrEnd, + ExpectedSomeIdent, + ExpectedSomeValue, + InvalidEscape, + InvalidNumber, + InvalidUnicodeCodePoint, + KeyMustBeAString, + LoneLeadingSurrogateInHexEscape, + MissingField(&'static str), + NotFourDigit, + NotUtf8, + TrailingCharacters, + UnexpectedEndOfHexEscape, + UnknownVariant, + UnrecognizedHex, +} + +impl fmt::Show for ErrorCode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + //ErrorCode::ConversionError(ref token) => write!(f, "failed to convert {}", token), + ErrorCode::EOFWhileParsingList => "EOF While parsing list".fmt(f), + ErrorCode::EOFWhileParsingObject => "EOF While parsing object".fmt(f), + ErrorCode::EOFWhileParsingString => "EOF While parsing string".fmt(f), + ErrorCode::EOFWhileParsingValue => "EOF While parsing value".fmt(f), + ErrorCode::ExpectedColon => "expected `:`".fmt(f), + ErrorCode::ExpectedConversion => "expected conversion".fmt(f), + ErrorCode::ExpectedEnumEnd => "expected enum end".fmt(f), + ErrorCode::ExpectedEnumEndToken => "expected enum map end".fmt(f), + ErrorCode::ExpectedEnumMapStart => "expected enum map start".fmt(f), + ErrorCode::ExpectedEnumToken => "expected enum token".fmt(f), + ErrorCode::ExpectedEnumVariantString => "expected variant".fmt(f), + ErrorCode::ExpectedListCommaOrEnd => "expected `,` or `]`".fmt(f), + ErrorCode::ExpectedName => "expected name".fmt(f), + ErrorCode::ExpectedObjectCommaOrEnd => "expected `,` or `}`".fmt(f), + ErrorCode::ExpectedSomeIdent => "expected ident".fmt(f), + ErrorCode::ExpectedSomeValue => "expected value".fmt(f), + //ErrorCode::ExpectedTokens(ref token, tokens) => write!(f, "expected {}, found {}", tokens, token), + ErrorCode::InvalidEscape => "invalid escape".fmt(f), + ErrorCode::InvalidNumber => "invalid number".fmt(f), + ErrorCode::InvalidUnicodeCodePoint => "invalid unicode code point".fmt(f), + ErrorCode::KeyMustBeAString => "key must be a string".fmt(f), + ErrorCode::LoneLeadingSurrogateInHexEscape => "lone leading surrogate in hex escape".fmt(f), + ErrorCode::MissingField(ref field) => write!(f, "missing field \"{}\"", field), + ErrorCode::NotFourDigit => "invalid \\u escape (not four digits)".fmt(f), + ErrorCode::NotUtf8 => "contents not utf-8".fmt(f), + ErrorCode::TrailingCharacters => "trailing characters".fmt(f), + ErrorCode::UnexpectedEndOfHexEscape => "unexpected end of hex escape".fmt(f), + //ErrorCode::UnexpectedName(ref name) => write!(f, "unexpected name {}", name), + ErrorCode::UnknownVariant => "unknown variant".fmt(f), + ErrorCode::UnrecognizedHex => "invalid \\u escape (unrecognized hex)".fmt(f), + } + } +} + +#[deriving(Clone, PartialEq, Show)] +pub enum Error { + /// msg, line, col + SyntaxError(ErrorCode, uint, uint), + IoError(io::IoError), + /* + ExpectedError(String, String), + MissingFieldError(String), + UnknownVariantError(String), + */ +} + +impl error::Error for Error { + fn description(&self) -> &str { + match *self { + Error::SyntaxError(..) => "syntax error", + Error::IoError(ref error) => error.description(), + /* + Error::ExpectedError(ref expected, _) => expected.as_slice(), + Error::MissingFieldError(_) => "missing field", + Error::UnknownVariantError(_) => "unknown variant", + */ + } + } + + fn detail(&self) -> Option { + match *self { + Error::SyntaxError(ref code, line, col) => { + Some(format!("{} at line {} column {}", code, line, col)) + } + Error::IoError(ref error) => error.detail(), + /* + Error::ExpectedError(ref expected, ref found) => { + Some(format!("expected {}, found {}", expected, found)) + } + Error::MissingFieldError(ref field) => { + Some(format!("missing field {}", field)) + } + Error::UnknownVariantError(ref variant) => { + Some(format!("unknown variant {}", variant)) + } + */ + } + } +} + +impl error::FromError for Error { + fn from_error(error: io::IoError) -> Error { + Error::IoError(error) + } +} diff --git a/serde2/src/json/mod.rs b/serde2/src/json/mod.rs index bfbad813..55b6bab3 100644 --- a/serde2/src/json/mod.rs +++ b/serde2/src/json/mod.rs @@ -4,6 +4,8 @@ pub use self::ser::escape_str; pub use self::de::from_str; -pub mod ser; +pub mod builder; pub mod de; pub mod error; +pub mod ser; +pub mod value; diff --git a/serde2/src/json/ser.rs b/serde2/src/json/ser.rs index c122fd0d..e7817eb6 100644 --- a/serde2/src/json/ser.rs +++ b/serde2/src/json/ser.rs @@ -1,6 +1,5 @@ use std::f64; -use std::io::IoError; -use std::io; +use std::io::{mod, ByRefWriter, IoError}; use std::num::{Float, FPNaN, FPInfinite}; use ser; @@ -230,14 +229,23 @@ fn fmt_f64_or_null(wr: &mut W, value: f64) -> Result<(), IoError> } } +#[inline] +pub fn to_writer< + W: io::Writer, + T: ser::Serialize, +>(wr: &mut W, value: &T) -> Result<(), IoError> { + let mut wr = Writer::new(wr.by_ref()); + try!(wr.visit(value)); + Ok(()) +} + #[inline] pub fn to_vec< T: ser::Serialize, >(value: &T) -> Result, IoError> { - let writer = Vec::with_capacity(128); - let mut writer = Writer::new(writer); - try!(writer.visit(value)); - Ok(writer.into_inner()) + let mut wr = Vec::with_capacity(128); + to_writer(&mut wr, value).unwrap(); + Ok(wr) } #[inline] diff --git a/serde2/src/json/value.rs b/serde2/src/json/value.rs index 83c214f5..821dcca8 100644 --- a/serde2/src/json/value.rs +++ b/serde2/src/json/value.rs @@ -1,122 +1,250 @@ +use std::collections::TreeMap; +use std::fmt; +use std::io; + +use ser::{mod, Serializer}; + #[deriving(PartialEq)] -pub enum Json { - Integer(int), +pub enum Value { + Null, + Bool(bool), + I64(i64), + F64(f64), String(String), - Array(Vec), - Object(TreeMap), + Array(Vec), + Object(TreeMap), } -pub struct JsonSerializer { - key: Option -} - -impl JsonSerializer { - pub fn new() -> JsonSerializer { - JsonSerializer { - key: None +impl ser::Serialize for Value { + #[inline] + fn visit< + S, + R, + E, + V: ser::Visitor, + >(&self, s: &mut S, visitor: V) -> Result { + match *self { + Value::Null => { + visitor.visit_null(s) + } + Value::Bool(v) => { + visitor.visit_bool(s, v) + } + Value::I64(v) => { + visitor.visit_i64(s, v) + } + Value::F64(v) => { + visitor.visit_f64(s, v) + } + Value::String(ref v) => { + visitor.visit_str(s, v.as_slice()) + } + Value::Array(ref v) => { + v.visit(s, visitor) + } + Value::Object(ref v) => { + v.visit(s, visitor) + } } } } -impl VisitorState for JsonSerializer { - fn visit_int(&mut self, value: int) -> Json { - Integer(value) +struct WriterFormatter<'a, 'b: 'a>(&'a mut fmt::Formatter<'b>); + +impl<'a, 'b> io::Writer for WriterFormatter<'a, 'b> { + fn write(&mut self, buf: &[u8]) -> io::IoResult<()> { + let WriterFormatter(ref mut f) = *self; + f.write(buf).map_err(|_| io::IoError::last_error()) + } +} + +impl fmt::Show for Value { + /// Serializes a json value into a string + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut wr = WriterFormatter(f); + super::ser::to_writer(&mut wr, self).map_err(|_| fmt::Error) + } +} + +pub fn to_value< + T: ser::Serialize, +>(value: &T) -> Value { + let mut writer = Writer::new(); + writer.visit(value).unwrap(); + writer.unwrap() +} + +enum State { + Value(Value), + Array(Vec), + Object(TreeMap), +} + +pub struct Writer { + state: Vec, +} + +impl Writer { + pub fn new() -> Writer { + Writer { + state: Vec::with_capacity(4), + } } - fn visit_str(&mut self, value: &'static str) -> Json { - String(value.to_string()) + pub fn unwrap(mut self) -> Value { + match self.state.pop().unwrap() { + State::Value(value) => value, + _ => panic!(), + } + } +} + +impl ser::Serializer for Writer { + #[inline] + fn visit< + T: ser::Serialize, + >(&mut self, value: &T) -> Result<(), ()> { + value.visit(self, Visitor) + } +} + +struct Visitor; + +impl ser::Visitor for Visitor { + #[inline] + fn visit_null(&self, state: &mut Writer) -> Result<(), ()> { + state.state.push(State::Value(Value::Null)); + Ok(()) } + #[inline] + fn visit_bool(&self, state: &mut Writer, value: bool) -> Result<(), ()> { + state.state.push(State::Value(Value::Bool(value))); + Ok(()) + } + + #[inline] + fn visit_i64(&self, state: &mut Writer, value: i64) -> Result<(), ()> { + state.state.push(State::Value(Value::I64(value))); + Ok(()) + } + + #[inline] + fn visit_u64(&self, state: &mut Writer, value: u64) -> Result<(), ()> { + state.state.push(State::Value(Value::I64(value as i64))); + Ok(()) + } + + #[inline] + fn visit_f64(&self, state: &mut Writer, value: f64) -> Result<(), ()> { + state.state.push(State::Value(Value::F64(value as f64))); + Ok(()) + } + + #[inline] + fn visit_char(&self, state: &mut Writer, value: char) -> Result<(), ()> { + state.state.push(State::Value(Value::String(value.to_string()))); + Ok(()) + } + + #[inline] + fn visit_str(&self, state: &mut Writer, value: &str) -> Result<(), ()> { + state.state.push(State::Value(Value::String(value.to_string()))); + Ok(()) + } + + #[inline] fn visit_seq< - T: Serialize, - Iter: Iterator - >(&mut self, mut iter: Iter) -> Json { - let (len, _) = iter.size_hint(); - let mut v = Vec::with_capacity(len); + V: ser::SeqVisitor + >(&self, state: &mut Writer, mut visitor: V) -> Result<(), ()> { + let len = match visitor.size_hint() { + (_, Some(len)) => len, + (len, None) => len, + }; - let mut first = true; - for elt in iter { - v.push(self.visit_seq_elt(first, elt)); - first = false; + let values = Vec::with_capacity(len); + + state.state.push(State::Array(values)); + + loop { + match try!(visitor.visit(state, Visitor)) { + Some(()) => { } + None => { break; } + } } - Array(v) + match state.state.pop().unwrap() { + State::Array(values) => { state.state.push(State::Value(Value::Array(values))); } + _ => panic!(), + } + + Ok(()) } + #[inline] fn visit_seq_elt< - T: Serialize - >(&mut self, _first: bool, value: T) -> Json { - value.serialize(self) - } + T: ser::Serialize, + >(&self, state: &mut Writer, _first: bool, value: T) -> Result<(), ()> { + try!(value.visit(state, Visitor)); + let value = match state.state.pop().unwrap() { + State::Value(value) => value, + _ => panic!(), + }; - fn visit_tuple< - V: Visitor - >(&mut self, mut visitor: V) -> Json { - let (len, _) = visitor.size_hint(); - let mut v = Vec::with_capacity(len); - - loop { - match visitor.visit(self) { - Some(value) => { v.push(value); } - None => { break; } - } + match *state.state.last_mut().unwrap() { + State::Array(ref mut values) => { values.push(value); } + _ => panic!(), } - Array(v) - } - - fn visit_tuple_struct< - V: Visitor - >(&mut self, _name: &'static str, visitor: V) -> Json { - self.visit_tuple(visitor) - } - - fn visit_enum< - V: Visitor - >(&mut self, _name: &'static str, _variant: &'static str, visitor: V) -> Json { - self.visit_tuple(visitor) + Ok(()) } + #[inline] fn visit_map< - K: Serialize, - V: Serialize, - Iter: Iterator<(K, V)> - >(&mut self, mut iter: Iter) -> Json { - let mut v = TreeMap::new(); - let mut first = true; + V: ser::MapVisitor + >(&self, state: &mut Writer, mut visitor: V) -> Result<(), ()> { + let values = TreeMap::new(); - for (key, value) in iter { - let value = self.visit_map_elt(first, key, value); - v.insert(self.key.take().unwrap(), value); - first = false; - } - - Object(v) - } - - fn visit_map_elt< - K: Serialize, - V: Serialize - >(&mut self, _first: bool, key: K, value: V) -> Json { - match key.serialize(self) { - String(key) => { self.key = Some(key); } - _ => { fail!() } - } - value.serialize(self) - } - - fn visit_struct< - V: Visitor - >(&mut self, _name: &'static str, mut visitor: V) -> Json { - let mut v = TreeMap::new(); + state.state.push(State::Object(values)); loop { - match visitor.visit(self) { - Some(value) => { v.insert(self.key.take().unwrap(), value); } + match try!(visitor.visit(state, Visitor)) { + Some(()) => { } None => { break; } } } - Object(v) + match state.state.pop().unwrap() { + State::Object(values) => { state.state.push(State::Value(Value::Object(values))); } + _ => panic!(), + } + + Ok(()) + } + + #[inline] + fn visit_map_elt< + K: ser::Serialize, + V: ser::Serialize, + >(&self, state: &mut Writer, _first: bool, key: K, value: V) -> Result<(), ()> { + try!(key.visit(state, Visitor)); + try!(value.visit(state, Visitor)); + + let key = match state.state.pop().unwrap() { + State::Value(Value::String(value)) => value, + _ => panic!(), + }; + + let value = match state.state.pop().unwrap() { + State::Value(value) => value, + _ => panic!(), + }; + + match *state.state.last_mut().unwrap() { + State::Object(ref mut values) => { values.insert(key, value); } + _ => panic!(), + } + + Ok(()) } }