From bf58f7999f3d066bb8749dd40a5b833bf4d3c414 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 27 May 2014 07:36:57 -0700 Subject: [PATCH] Get deserializing json objects into structs working --- de.rs | 87 +++++++++++++++++++++++++++++++ json.rs | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 237 insertions(+), 6 deletions(-) diff --git a/de.rs b/de.rs index 0fd21db9..ea2b1d6b 100644 --- a/de.rs +++ b/de.rs @@ -479,6 +479,93 @@ deserialize_tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, } ////////////////////////////////////////////////////////////////////////////// +pub fn ignore>(d: &mut D) -> Result<(), E> { + let token = match d.next() { + Some(Ok(token)) => token, + Some(Err(err)) => { return Err(err); } + None => { return Err(d.end_of_stream_error()); } + }; + + ignore_token(d, token) +} + +pub fn ignore_token>(d: &mut D, token: Token) -> Result<(), E> { + match token { + Null => Ok(()), + Bool(_) => Ok(()), + Uint(_) => Ok(()), + U8(_) => Ok(()), + U16(_) => Ok(()), + U32(_) => Ok(()), + U64(_) => Ok(()), + Int(_) => Ok(()), + I8(_) => Ok(()), + I16(_) => Ok(()), + I32(_) => Ok(()), + I64(_) => Ok(()), + F32(_) => Ok(()), + F64(_) => Ok(()), + Char(_) => Ok(()), + Str(_) => Ok(()), + String(_) => Ok(()), + Option(true) => { ignore(d) } + Option(false) => { Ok(()) } + + EnumStart(_, _) => { + loop { + match try!(d.expect_token()) { + End => { return Ok(()); } + token => { try!(ignore_token(d, token)); } + } + } + } + + StructStart(_) => { + loop { + match try!(d.expect_token()) { + End => { return Ok(()); } + Str(_) | String(_) => { try!(ignore(d)); } + token => { return Err(d.syntax_error()); } + } + } + } + + TupleStart(_) => { + loop { + match try!(d.expect_token()) { + End => { return Ok(()); } + token => { try!(ignore_token(d, token)); } + } + } + } + + SeqStart(_) => { + loop { + match try!(d.expect_token()) { + End => { return Ok(()); } + token => { try!(ignore_token(d, token)); } + } + } + } + + MapStart(_) => { + loop { + match try!(d.expect_token()) { + End => { return Ok(()); } + token => { + try!(ignore_token(d, token)); + try!(ignore(d)); + } + } + } + } + + End => Err(d.syntax_error()), + } +} + +////////////////////////////////////////////////////////////////////////////// + #[cfg(test)] mod tests { use collections::HashMap; diff --git a/json.rs b/json.rs index 89b6ed94..a3ee1aa5 100644 --- a/json.rs +++ b/json.rs @@ -1460,6 +1460,7 @@ impl> Parser { fn parse_list_start(&mut self) -> Result { self.parse_whitespace(); + if self.ch_is(']') { self.bump(); Ok(de::End) @@ -1471,6 +1472,7 @@ impl> Parser { fn parse_list_comma_or_end(&mut self) -> Result { self.parse_whitespace(); + if self.ch_is(',') { self.bump(); self.state.push(ParseListCommaOrEnd); @@ -1487,6 +1489,7 @@ impl> Parser { fn parse_object_start(&mut self) -> Result { self.parse_whitespace(); + if self.ch_is('}') { self.bump(); Ok(de::End) @@ -1497,6 +1500,7 @@ impl> Parser { fn parse_object_comma_or_end(&mut self) -> Result { self.parse_whitespace(); + if self.ch_is(',') { self.bump(); self.parse_object_key() @@ -1512,6 +1516,7 @@ impl> Parser { fn parse_object_key(&mut self) -> Result { self.parse_whitespace(); + self.state.push(ParseObjectValue); if self.eof() { @@ -1529,6 +1534,7 @@ impl> Parser { fn parse_object_value(&mut self) -> Result { self.parse_whitespace(); + if self.ch_is(':') { self.bump(); self.state.push(ParseObjectCommaOrEnd); @@ -2244,13 +2250,33 @@ mod tests { use std::io; use collections::TreeMap; - /* #[deriving(Eq, Show)] enum Animal { Dog, Frog(String, int) } + impl> de::Deserializable for Animal { + #[inline] + fn deserialize_token(d: &mut D, token: de::Token) -> Result { + match try!(d.expect_enum_start(token, "Animal", ["Dog", "Frog"])) { + 0 => { + try!(d.expect_end()); + Ok(Dog) + } + 1 => { + let x0 = try!(de::Deserializable::deserialize(d)); + let x1 = try!(de::Deserializable::deserialize(d)); + + try!(d.expect_end()); + + Ok(Frog(x0, x1)) + } + _ => Err(d.syntax_error()), + } + } + } + #[deriving(Eq, Show)] struct Inner { a: (), @@ -2258,11 +2284,130 @@ mod tests { c: Vec, } + impl> de::Deserializable for Inner { + #[inline] + fn deserialize_token(d: &mut D, token: de::Token) -> Result { + match token { + de::StructStart(name) => { + if name != "Inner" { + return Err(d.syntax_error()); + } + + let a = try!(d.expect_struct_field("a")); + let b = try!(d.expect_struct_field("b")); + let c = try!(d.expect_struct_field("c")); + try!(d.expect_end()); + Ok(Inner { a: a, b: b, c: c }) + } + de::MapStart(_) => { + let mut a = None; + let mut b = None; + let mut c = None; + + loop { + match try!(d.expect_token()) { + de::End => { break; } + de::Str(name) => { + match name { + "a" => { + a = Some(try!(de::Deserializable::deserialize(d))); + } + "b" => { + b = Some(try!(de::Deserializable::deserialize(d))); + } + "c" => { + c = Some(try!(de::Deserializable::deserialize(d))); + } + _ => { } + } + } + de::String(ref name) => { + match name.as_slice() { + "a" => { + a = Some(try!(de::Deserializable::deserialize(d))); + } + "b" => { + b = Some(try!(de::Deserializable::deserialize(d))); + } + "c" => { + c = Some(try!(de::Deserializable::deserialize(d))); + } + _ => { } + } + } + _ => { return Err(d.syntax_error()); } + } + } + + match (a, b, c) { + (Some(a), Some(b), Some(c)) => { + Ok(Inner { a: a, b: b, c: c }) + } + _ => Err(d.syntax_error()), + } + } + _ => Err(d.syntax_error()), + } + } + } + #[deriving(Eq, Show)] struct Outer { inner: Vec, } + impl> de::Deserializable for Outer { + #[inline] + fn deserialize_token(d: &mut D, token: de::Token) -> Result { + match token { + de::StructStart(name) => { + if name != "Outer" { + return Err(d.syntax_error()); + } + + let inner = try!(d.expect_struct_field("inner")); + try!(d.expect_end()); + Ok(Outer { inner: inner }) + } + de::MapStart(_) => { + let mut inner = None; + + loop { + match try!(d.expect_token()) { + de::End => { break; } + de::Str(name) => { + match name { + "inner" => { + inner = Some(try!(de::Deserializable::deserialize(d))); + } + _ => { } + } + } + de::String(ref name) => { + match name.as_slice() { + "inner" => { + inner = Some(try!(de::Deserializable::deserialize(d))); + } + _ => { } + } + } + _ => { return Err(d.syntax_error()); } + } + } + + match inner { + Some(inner) => { + Ok(Outer { inner: inner }) + } + _ => Err(d.syntax_error()), + } + } + _ => Err(d.syntax_error()), + } + } + } + + /* fn mk_object(items: &[(String, Json)]) -> Json { let mut d = box TreeMap::new(); @@ -2840,26 +2985,25 @@ mod tests { assert!(v == m); } - /* #[test] fn test_decode_struct() { let s = "{ \"inner\": [ - { \"a\": null, \"b\": 2, \"c\": [\"abc\", \"xyz\"] } ] }"; - let mut decoder = Decoder::new(from_str(s).unwrap()); - let v: Outer = Decodable::decode(&mut decoder).unwrap(); + //{ \"a\": null, \"b\": 2, \"c\": [\"abc\", \"xyz\"] } + let v: Outer = from_iter(s.chars()).unwrap(); assert_eq!( v, Outer { inner: vec![ - Inner { a: (), b: 2, c: vec!["abc".to_strbuf(), "xyz".to_strbuf()] } + //Inner { a: (), b: 2, c: vec!["abc".to_strbuf(), "xyz".to_strbuf()] } ] } ); } + /* #[test] fn test_decode_option() { let mut decoder = Decoder::new(from_str("null").unwrap());