From 27a914cdcffc1c12bf5d92cfbcdb2b0a19f1c4f3 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Thu, 29 May 2014 07:05:19 -0700 Subject: [PATCH] Add support for json deserializing enums and options, clean up tests --- json.rs | 539 ++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 371 insertions(+), 168 deletions(-) diff --git a/json.rs b/json.rs index 4fc1627a..e74cfbb4 100644 --- a/json.rs +++ b/json.rs @@ -316,9 +316,10 @@ enum JsonDeserializerState { JsonDeserializerValueState(Json), JsonDeserializerListState(vec::MoveItems), JsonDeserializerObjectState(treemap::MoveEntries), + JsonDeserializerEndState, } -struct JsonDeserializer { +pub struct JsonDeserializer { stack: Vec, } @@ -380,6 +381,9 @@ impl Iterator> for JsonDeserializer { } } } + Some(JsonDeserializerEndState) => { + return Some(Ok(de::End)); + } None => { return None; } } } @@ -394,6 +398,131 @@ impl de::Deserializer for JsonDeserializer { fn syntax_error(&self) -> ParserError { SyntaxError(InvalidSyntax, 0, 0) } + + // Special case treating options as a nullable value. + #[inline] + fn expect_option< + U: de::Deserializable + >(&mut self, token: de::Token) -> Result, ParserError> { + match token { + de::Null => Ok(None), + token => { + let value: U = try!(de::Deserializable::deserialize_token(self, token)); + Ok(Some(value)) + } + } + } + + #[inline] + fn expect_enum_start(&mut self, token: de::Token, _name: &str, variants: &[&str]) -> Result { + let variant = match token { + de::String(variant) => { + self.stack.push(JsonDeserializerEndState); + variant + } + de::MapStart(_) => { + let state = match self.stack.pop() { + Some(state) => state, + None => { fail!("state machine error, state stack empty"); } + }; + + let mut iter = match state { + JsonDeserializerObjectState(iter) => iter, + _ => { fail!("state machine error, expected an object"); } + }; + + let mut variant = None; + let mut fields = None; + + for (key, value) in iter { + if key.equiv(&"variant") { + match value { + String(v) => { variant = Some(v); } + value => { + return Err(ExpectedError("String".to_string(), + format!("{}", value))) + } + } + } else if key.equiv(&"fields") { + match value { + List(v) => { fields = Some(v); } + value => { + return Err(ExpectedError("List".to_string(), + format!("{}", value))) + } + } + } + } + + let (variant, fields) = match (variant, fields) { + (Some(variant), Some(fields)) => (variant, fields), + (None, _) => { + return Err(MissingFieldError("variant".to_string())) + } + (_, None) => { + return Err(MissingFieldError("fields".to_string())) + } + }; + + self.stack.push(JsonDeserializerEndState); + + for field in fields.move_iter().rev() { + self.stack.push(JsonDeserializerValueState(field)); + } + + variant + } + token => { + return Err(ExpectedError("String or Object".to_string(), + format!("{}", token))) + } + }; + + + /* + + + let name = match self.stack.pop() { + String(s) => s, + Object(mut object) => { + let n = match object.pop_equiv(&"variant") { + Some(String(s)) => s, + Some(value) => { + return Err(ExpectedError("String".to_string(), + format!("{}", value))) + } + None => { + return Err(MissingFieldError("variant".to_string())) + } + }; + match object.pop_equiv(&"fields") { + Some(List(list)) => { + for field in list.move_iter().rev() { + self.stack.push(JsonDeserializerValueState(field)); + } + }, + Some(value) => { + return Err(ExpectedError("List".to_string(), + format!("{}", value))) + } + None => { + return Err(MissingFieldError("fields".to_string())) + } + } + n + } + json => { + return Err(ExpectedError("String or Object".to_string(), + format!("{}", json))) + } + }; + */ + + match variants.iter().position(|v| *v == variant.as_slice()) { + Some(idx) => Ok(idx), + None => Err(UnknownVariantError(variant)), + } + } } /// The errors that can arise while parsing a JSON stream. @@ -422,11 +551,15 @@ pub enum ParserError { /// msg, line, col SyntaxError(ErrorCode, uint, uint), IoError(io::IoErrorKind, &'static str), + ExpectedError(String, String), + MissingFieldError(String), + UnknownVariantError(String), } // Builder and Parser have the same errors. pub type BuilderError = ParserError; +/* #[deriving(Clone, Eq, Show)] pub enum DecoderError { ParseError(ParserError), @@ -434,6 +567,7 @@ pub enum DecoderError { MissingFieldError(String), UnknownVariantError(String), } +*/ /// Returns a readable error string for a given error code. pub fn error_str(error: ErrorCode) -> &'static str { @@ -469,7 +603,7 @@ fn io_error_to_error(io: io::IoError) -> ParserError { } pub type EncodeResult = io::IoResult<()>; -pub type DecodeResult = Result; +//pub type DecodeResult = Result; fn escape_str(s: &str) -> String { let mut escaped = String::from_str("\""); @@ -1754,7 +1888,7 @@ impl> de::Deserializer for Parser { #[inline] fn expect_enum_start(&mut self, token: de::Token, _name: &str, variants: &[&str]) -> Result { match token { - Str(name) => + Str(name) => } @@ -2463,7 +2597,7 @@ mod tests { Object, }; use super::{Parser, ParserError, from_iter}; - use super::{JsonDeserializer, from_json}; + use super::{JsonDeserializer, from_json, ToJson}; use super::{ EOFWhileParsingList, EOFWhileParsingObject, @@ -2472,7 +2606,7 @@ mod tests { ExpectedColon, InvalidNumber, InvalidSyntax, - KeyMustBeAString, + KeyMustBeAString, TrailingCharacters, SyntaxError, }; @@ -2483,6 +2617,14 @@ mod tests { use std::str; use collections::TreeMap; + macro_rules! treemap { + ($($k:expr => $v:expr),*) => ({ + let mut _m = ::collections::TreeMap::new(); + $(_m.insert($k, $v);)* + _m + }) + } + #[deriving(Eq, Show)] enum Animal { Dog, @@ -2574,6 +2716,18 @@ mod tests { } } + impl ToJson for Inner { + fn to_json(&self) -> Json { + Object( + treemap!( + "a".to_string() => self.a.to_json(), + "b".to_string() => self.b.to_json(), + "c".to_string() => self.c.to_json() + ) + ) + } + } + #[deriving(Eq, Show)] struct Outer { inner: Vec, @@ -2622,6 +2776,16 @@ mod tests { } } + impl ToJson for Outer { + fn to_json(&self) -> Json { + Object( + treemap!( + "inner".to_string() => self.inner.to_json() + ) + ) + } + } + /* fn mk_object(items: &[(String, Json)]) -> Json { let mut d = box TreeMap::new(); @@ -2874,59 +3038,61 @@ mod tests { } */ - fn test_parser_err< + fn test_parse_err< 'a, T: Eq + Show + de::Deserializable>> >(errors: &[(&'a str, ParserError)]) { - for &(s, err) in errors.iter() { + for &(s, ref err) in errors.iter() { let v: Result = from_iter(s.chars()); - assert_eq!(v, Err(err)); + assert_eq!(v.unwrap_err(), *err); } } - fn test_parser_ok< + fn test_parse_ok< 'a, - T: Eq + Show + de::Deserializable>> + T: Eq + Show + ToJson + de::Deserializable>> >(errors: &[(&'a str, T)]) { for &(s, ref value) in errors.iter() { let v: T = from_iter(s.chars()).unwrap(); assert_eq!(v, *value); + + let v: Json = from_iter(s.chars()).unwrap(); + assert_eq!(v, value.to_json()); } } - fn test_json_deserializer_ok< - T: Eq + Show + de::Deserializable - >(errors: &[(Json, T)]) { - for &(ref json, ref value) in errors.iter() { - let v: T = from_json(json.clone()).unwrap(); + fn test_json_deserialize_ok< + T: Eq + Show + ToJson + de::Deserializable + >(errors: &[T]) { + for value in errors.iter() { + let v: T = from_json(value.to_json()).unwrap(); assert_eq!(v, *value); } } #[test] - fn test_decode_null() { - test_parser_err::<()>([ + fn test_parse_null() { + test_parse_err::<()>([ ("n", SyntaxError(InvalidSyntax, 1, 2)), ("nul", SyntaxError(InvalidSyntax, 1, 4)), ("nulla", SyntaxError(TrailingCharacters, 1, 5)), ]); - test_parser_ok([ + test_parse_ok([ ("null", ()), ]); - - test_parser_ok([ - ("null", Null), - ]); - - test_json_deserializer_ok([ - (Null, ()), - ]); } #[test] - fn test_decode_bool() { - test_parser_err::([ + fn test_json_deserialize_null() { + test_json_deserialize_ok([ + (), + ]); + } + + #[test] + fn test_parse_bool() { + test_parse_err::([ ("t", SyntaxError(InvalidSyntax, 1, 2)), ("truz", SyntaxError(InvalidSyntax, 1, 4)), ("f", SyntaxError(InvalidSyntax, 1, 2)), @@ -2935,20 +3101,17 @@ mod tests { ("falsea", SyntaxError(TrailingCharacters, 1, 6)), ]); - test_parser_ok([ + test_parse_ok([ ("true", true), ("false", false), ]); + } - test_parser_ok([ - ("true", Boolean(true)), - ("false", Boolean(false)), - ]); - - - test_json_deserializer_ok([ - (Boolean(true), true), - (Boolean(false), false), + #[test] + fn test_json_deserialize_bool() { + test_json_deserialize_ok([ + true, + false, ]); } @@ -2975,8 +3138,8 @@ mod tests { */ #[test] - fn test_decode_numbers() { - let errors = [ + fn test_parse_numbers() { + test_parse_err::([ ("+", SyntaxError(InvalidSyntax, 1, 1)), (".", SyntaxError(InvalidSyntax, 1, 1)), ("-", SyntaxError(InvalidNumber, 1, 2)), @@ -2985,14 +3148,9 @@ mod tests { ("1e", SyntaxError(InvalidNumber, 1, 3)), ("1e+", SyntaxError(InvalidNumber, 1, 4)), ("1a", SyntaxError(TrailingCharacters, 1, 2)), - ]; + ]); - for &(s, err) in errors.iter() { - let v: Result = from_iter(s.chars()); - assert_eq!(v, Err(err)); - } - - let values = [ + test_parse_ok([ ("3", 3.0), ("3.1", 3.1), ("-1.2", -1.2), @@ -3000,12 +3158,20 @@ mod tests { ("0.4e5", 0.4e5), ("0.4e15", 0.4e15), ("0.4e-01", 0.4e-01), - ]; + ]); + } - for &(s, value) in values.iter() { - let v: Result = from_iter(s.chars()); - assert_eq!(v, Ok(value)); - } + #[test] + fn test_json_deserialize_numbers() { + test_json_deserialize_ok([ + 3.0, + 3.1, + -1.2, + 0.4, + 0.4e5, + 0.4e15, + 0.4e-01, + ]); } /* @@ -3028,33 +3194,39 @@ mod tests { */ #[test] - fn test_decode_str() { - let errors = [ + fn test_parse_str() { + test_parse_err::([ ("\"", SyntaxError(EOFWhileParsingString, 1, 2)), ("\"lol", SyntaxError(EOFWhileParsingString, 1, 5)), ("\"lol\"a", SyntaxError(TrailingCharacters, 1, 6)), - ]; + ]); - for &(s, err) in errors.iter() { - let v: Result = from_iter(s.chars()); - assert_eq!(v, Err(err)); - } + test_parse_ok([ + ("\"\"", "".to_string()), + ("\"foo\"", "foo".to_string()), + ("\"\\\"\"", "\"".to_string()), + ("\"\\b\"", "\x08".to_string()), + ("\"\\n\"", "\n".to_string()), + ("\"\\r\"", "\r".to_string()), + ("\"\\t\"", "\t".to_string()), + ("\"\\u12ab\"", "\u12ab".to_string()), + ("\"\\uAB12\"", "\uAB12".to_string()), + ]); + } - let s = [("\"\"", ""), - ("\"foo\"", "foo"), - ("\"\\\"\"", "\""), - ("\"\\b\"", "\x08"), - ("\"\\n\"", "\n"), - ("\"\\r\"", "\r"), - ("\"\\t\"", "\t"), - ("\"\\u12ab\"", "\u12ab"), - ("\"\\uAB12\"", "\uAB12")]; - - for &(i, o) in s.iter() { - let mut parser = Parser::new(i.chars()); - let v: String = de::Deserializable::deserialize(&mut parser).unwrap(); - assert_eq!(v.as_slice(), o); - } + #[test] + fn test_json_deserialize_str() { + test_json_deserialize_ok([ + "".to_string(), + "foo".to_string(), + "\"".to_string(), + "\x08".to_string(), + "\n".to_string(), + "\r".to_string(), + "\t".to_string(), + "\u12ab".to_string(), + "\uAB12".to_string(), + ]); } /* @@ -3081,44 +3253,56 @@ mod tests { */ #[test] - fn test_decode_list() { - let errors = [ - ("[", SyntaxError(EOFWhileParsingValue, 1, 2)), - ("[ ", SyntaxError(EOFWhileParsingValue, 1, 3)), - ("[1", SyntaxError(EOFWhileParsingList, 1, 3)), - ("[1,", SyntaxError(EOFWhileParsingValue, 1, 4)), - ("[1,]", SyntaxError(InvalidSyntax, 1, 4)), - ("[1 2]", SyntaxError(InvalidSyntax, 1, 4)), + fn test_parse_list() { + test_parse_err::>([ + ("[", SyntaxError(EOFWhileParsingValue, 1, 2)), + ("[ ", SyntaxError(EOFWhileParsingValue, 1, 3)), + ("[1", SyntaxError(EOFWhileParsingList, 1, 3)), + ("[1,", SyntaxError(EOFWhileParsingValue, 1, 4)), + ("[1,]", SyntaxError(InvalidSyntax, 1, 4)), + ("[1 2]", SyntaxError(InvalidSyntax, 1, 4)), ("[]a", SyntaxError(TrailingCharacters, 1, 3)), - ]; - for &(s, err) in errors.iter() { - let v: Result, ParserError> = from_iter(s.chars()); - assert_eq!(v, Err(err)); - } + ]); - let v: Vec<()> = from_iter("[]".chars()).unwrap(); - assert_eq!(v, vec![]); + test_parse_ok([ + ("[]", vec!()), + ("[ ]", vec!()), + ("[null]", vec!(())), + ("[ null ]", vec!(())), + ]); - let v: Vec<()> = from_iter("[ ]".chars()).unwrap(); - assert_eq!(v, vec![]); + test_parse_ok([ + ("[true]", vec!(true)), + ]); - let v: Vec<()> = from_iter("[null]".chars()).unwrap(); - assert_eq!(v, vec![()]); + test_parse_ok([ + ("[3,1]", vec!(3, 1)), + ("[ 3 , 1 ]", vec!(3, 1)), + ]); - let v: Vec<()> = from_iter("[ null ]".chars()).unwrap(); - assert_eq!(v, vec![()]); + test_parse_ok([ + ("[[3], [1, 2]]", vec!(vec!(3), vec!(1, 2))), + ]); + } - let v: Vec = from_iter("[true]".chars()).unwrap(); - assert_eq!(v, vec![true]); + #[test] + fn test_json_deserialize_list() { + test_json_deserialize_ok([ + vec!(), + vec!(()), + ]); - let v: Vec = from_iter("[3,1]".chars()).unwrap(); - assert_eq!(v, vec![3, 1]); + test_json_deserialize_ok([ + vec!(true), + ]); - let v: Vec = from_iter("[ 3 , 1 ]".chars()).unwrap(); - assert_eq!(v, vec![3, 1]); + test_json_deserialize_ok([ + vec!(3, 1), + ]); - let v: Vec> = from_iter("[[3], [1, 2]]".chars()).unwrap(); - assert_eq!(v, vec![vec![3], vec![1, 2]]); + test_json_deserialize_ok([ + vec!(vec!(3), vec!(1, 2)), + ]); } /* @@ -3179,8 +3363,8 @@ mod tests { */ #[test] - fn test_decode_object() { - let errors = [ + fn test_parse_object() { + test_parse_err::>([ ("{", SyntaxError(EOFWhileParsingString, 1, 2)), ("{ ", SyntaxError(EOFWhileParsingString, 1, 3)), ("{1", SyntaxError(KeyMustBeAString, 1, 2)), @@ -3193,82 +3377,101 @@ mod tests { ("{\"a\":1 1", SyntaxError(InvalidSyntax, 1, 8)), ("{\"a\":1,", SyntaxError(EOFWhileParsingString, 1, 8)), ("{}a", SyntaxError(TrailingCharacters, 1, 3)), - ]; + ]); - for &(s, err) in errors.iter() { - let v: Result, ParserError> = from_iter(s.chars()); - assert_eq!(v, Err(err)); - } + test_parse_ok([ + ("{}", treemap!()), + ("{ }", treemap!()), + ( + "{\"a\":3}", + treemap!("a".to_string() => 3) + ), + ( + "{ \"a\" : 3 }", + treemap!("a".to_string() => 3) + ), + ( + "{\"a\":3,\"b\":4}", + treemap!("a".to_string() => 3, "b".to_string() => 4) + ), + ( + "{ \"a\" : 3 , \"b\" : 4 }", + treemap!("a".to_string() => 3, "b".to_string() => 4), + ), + ]); - let v: TreeMap = from_iter("{}".chars()).unwrap(); - let m = TreeMap::new(); - assert!(v == m); - - let v: TreeMap = from_iter("{ }".chars()).unwrap(); - let m = TreeMap::new(); - assert!(v == m); - - let v: TreeMap = from_iter("{\"a\":3}".chars()).unwrap(); - let mut m = TreeMap::new(); - m.insert("a".to_str(), 3); - assert!(v == m); - - let v: TreeMap = from_iter("{\"a\" :3}".chars()).unwrap(); - let mut m = TreeMap::new(); - m.insert("a".to_str(), 3); - assert!(v == m); - - let v: TreeMap = from_iter("{\"a\" : 3}".chars()).unwrap(); - let mut m = TreeMap::new(); - m.insert("a".to_str(), 3); - assert!(v == m); - - let v: TreeMap = from_iter("{\"a\": 3, \"b\": 4}".chars()).unwrap(); - let mut m = TreeMap::new(); - m.insert("a".to_str(), 3); - m.insert("b".to_str(), 4); - assert!(v == m); - - let v: TreeMap = from_iter("{ \"a\": 3, \"b\": 4 }".chars()).unwrap(); - let mut m = TreeMap::new(); - m.insert("a".to_str(), 3); - m.insert("b".to_str(), 4); - assert!(v == m); - - let v: TreeMap> = from_iter("{\"a\": {\"b\": 3, \"c\": 4}}".chars()).unwrap(); - let mut mm = TreeMap::new(); - mm.insert("b".to_str(), 3); - mm.insert("c".to_str(), 4); - let mut m = TreeMap::new(); - m.insert("a".to_str(), mm); - assert!(v == m); + test_parse_ok([ + ( + "{\"a\": {\"b\": 3, \"c\": 4}}", + treemap!("a".to_string() => treemap!("b".to_string() => 3, "c".to_string() => 4)), + ), + ]); } #[test] - fn test_decode_struct() { - let s = "{ - \"inner\": [ - { \"a\": null, \"b\": 2, \"c\": [\"abc\", \"xyz\"] } - ] - }"; - let v: Outer = from_iter(s.chars()).unwrap(); - assert_eq!( - v, + fn test_json_deserialize_object() { + test_json_deserialize_ok([ + treemap!(), + treemap!("a".to_string() => 3), + treemap!("a".to_string() => 3, "b".to_string() => 4), + ]); + + test_json_deserialize_ok([ + treemap!("a".to_string() => treemap!("b".to_string() => 3, "c".to_string() => 4)), + ]); + } + + #[test] + fn test_parse_struct() { + test_parse_ok([ + ( + "{ + \"inner\": [] + }", + Outer { + inner: vec![] + }, + ), + ( + "{ + \"inner\": [ + { \"a\": null, \"b\": 2, \"c\": [\"abc\", \"xyz\"] } + ] + }", + Outer { + inner: vec![ + Inner { a: (), b: 2, c: vec!["abc".to_string(), "xyz".to_string()] } + ] + }, + ) + ]); + } + + #[test] + fn test_json_deserialize_struct() { + test_json_deserialize_ok([ Outer { inner: vec![ Inner { a: (), b: 2, c: vec!["abc".to_string(), "xyz".to_string()] } ] - } - ); + }, + ]); } #[test] - fn test_decode_option() { - let value: Result, ParserError> = from_iter("null".chars()); - assert_eq!(value, Ok(None)); + fn test_parse_option() { + test_parse_ok([ + ("null", None), + ("\"jodhpurs\"", Some("jodhpurs".to_string())), + ]); + } - let value: Result, ParserError> = from_iter("\"jodhpurs\"".chars()); - assert_eq!(value, Ok(Some("jodhpurs".to_string()))); + #[test] + fn test_json_deserialize_option() { + test_json_deserialize_ok([ + None, + Some("jodhpurs".to_string()), + ]); } /*