diff --git a/src/lib.rs b/src/lib.rs index 882fecf..6ea7f3b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,8 +6,11 @@ use std::collections::HashMap; use std::iter::FromIterator; use std::{char, u16}; +pub type JSONResult = Result; +pub type JSONMap = HashMap; + /// The type of JSON value -#[derive(Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq)] pub enum JSONValue { /// Object Literal Object(HashMap), @@ -92,7 +95,7 @@ impl JSON { } /// Parse a `JSONValue` from the current JSON string - fn parse_value(&mut self) -> Result { + fn parse_value(&mut self) -> JSONResult { self.skip_whitespace(); // Go through the parser methods, until you find @@ -123,7 +126,7 @@ impl JSON { self.skip_whitespace(); - let mut result: HashMap = HashMap::new(); + let mut result: JSONMap = HashMap::new(); let mut initial = true; @@ -206,7 +209,10 @@ impl JSON { // All the escape sequences... if self.chars[self.i] == '\\' { let ch = self.chars[self.i + 1]; - if ['"', '\\', '/'].contains(&ch) { + if ch == '"' { + result.push_str("\""); + self.increment(1); + } else if ['\\', '/'].contains(&ch) { let escaped = ch.escape_default().next().unwrap_or(ch); result.push(escaped); @@ -359,16 +365,11 @@ impl JSON { return Err(ParseError::ExpectedToken(msg)); } - self.skip(); + self.increment(1); Ok(()) } - /// Skip a character - fn skip(&mut self) { - self.increment(1); - } - /// Do a checked increment of the internal pointer index fn increment(&mut self, amount: usize) { let current = self.i; @@ -380,7 +381,7 @@ impl JSON { } /// Convert a `&str` containing JSON into a `Result` - pub fn parse(json: &str) -> Result { + pub fn parse(json: &str) -> JSONResult { JSON::new(json).parse_value() } } @@ -388,6 +389,23 @@ impl JSON { #[cfg(test)] mod tests { use super::*; + use super::JSONValue::{Object, Array, Number, True, False, Null}; + + impl JSONValue { + fn unwrap_object(self) -> JSONMap { + match self { + JSONValue::Object(o) => o, + _ => panic!("Tried to unwrap a non-object"), + } + } + + fn unwrap_array(self) -> Vec { + match self { + JSONValue::Array(a) => a, + _ => panic!("Tried to unwrap a non-array") + } + } + } #[test] fn parse_keyword() { @@ -395,7 +413,7 @@ mod tests { assert_eq!(res, Ok(None)); let res = JSON::new("true").parse_keyword("true", JSONValue::True); - assert_eq!(res, Ok(Some(JSONValue::True))); + assert_eq!(res, Ok(Some(True))); } #[test] @@ -417,7 +435,7 @@ mod tests { #[test] fn parse_empty_array() { let res = JSON::new("[]").parse_value(); - assert_eq!(res, Ok(JSONValue::Array(vec![]))); + assert_eq!(res, Ok(Array(vec![]))); } #[test] @@ -429,13 +447,13 @@ mod tests { assert_eq!(res, Ok(None)); let res = JSON::new("3.14159").parse_number(); - assert_eq!(res, Ok(Some(JSONValue::Number(3.14159f64)))); + assert_eq!(res, Ok(Some(Number(3.14159f64)))); let res = JSON::new("3e4").parse_number(); - assert_eq!(res, Ok(Some(JSONValue::Number(3e4f64)))); + assert_eq!(res, Ok(Some(Number(3e4f64)))); let res = JSON::new("1.234,").parse_number(); - assert_eq!(res, Ok(Some(JSONValue::Number(1.234f64)))); + assert_eq!(res, Ok(Some(Number(1.234f64)))); } #[test] @@ -444,10 +462,10 @@ mod tests { assert_eq!( result, - Ok(JSONValue::Array(vec![ - JSONValue::True, - JSONValue::False, - JSONValue::Null + Ok(Array(vec![ + True, + False, + Null ])) ); } @@ -456,7 +474,7 @@ mod tests { fn parse_object() { let result = JSON::new(r#"{"foo": "bar"}"#).parse_object(); - let mut hash_map: HashMap = HashMap::new(); + let mut hash_map: JSONMap = HashMap::new(); hash_map.insert(String::from("foo"), JSONValue::String(String::from("bar"))); assert_eq!(result, Ok(Some(JSONValue::Object(hash_map)))); @@ -466,17 +484,17 @@ mod tests { fn parse_json_types() { // Boolean / Null let res = JSON::parse("true"); - assert_eq!(res, Ok(JSONValue::True)); + assert_eq!(res, Ok(True)); let res = JSON::parse("false"); - assert_eq!(res, Ok(JSONValue::False)); + assert_eq!(res, Ok(False)); let res = JSON::parse("null"); - assert_eq!(res, Ok(JSONValue::Null)); + assert_eq!(res, Ok(Null)); // Number let res = JSON::parse("9.38083151965"); assert_eq!( res, - Ok(JSONValue::Number(9.38083151965)), + Ok(Number(9.38083151965)), "Failed to parse number" ); @@ -492,10 +510,10 @@ mod tests { let res = JSON::parse("[1, 2, 3]"); assert_eq!( res, - Ok(JSONValue::Array(vec![ - JSONValue::Number(1f64), - JSONValue::Number(2f64), - JSONValue::Number(3f64) + Ok(Array(vec![ + Number(1f64), + Number(2f64), + Number(3f64) ])) ); @@ -503,24 +521,57 @@ mod tests { let result = JSON::parse("[{}]"); assert_eq!( result, - Ok(JSONValue::Array(vec![JSONValue::Object(HashMap::new())])) + Ok(JSONValue::Array(vec![Object(HashMap::new())])) ); } #[test] fn parse_nested_object() { let res = JSON::parse(r#"{"a": {"b": []}}"#); - assert!(res.is_ok(), format!("{:#?}", res)); + let mut outermap: JSONMap = HashMap::new(); + let mut innermap: JSONMap = HashMap::new(); + + innermap.insert(String::from("b"), Array(vec![])); + outermap.insert(String::from("a"), Object(innermap)); + + let expected = Ok(Object(outermap)); + + assert_eq!(res, expected); } #[test] - fn can_parse_arbitrary_json() { + fn parse_object_with_number_values() { let result = JSON::parse(r#"[{ "a": 9.38083151965, "b": 4e3 }]"#); - assert!( - result.is_ok(), - format!("Failed on just number values: {:#?}", result) - ); + let mut map: JSONMap = HashMap::new(); + map.insert(String::from("a"), Number(9.38083151965f64)); + map.insert(String::from("b"), Number(4e3f64)); + let expected = Ok(Array(vec![Object(map)])); + + assert_eq!(result, expected, "Failed on just number values: {:#?}", result); + } + + #[test] + fn parse_weird_character_array() { + let result = JSON::parse(r#"["\"", "\\", "/", "\b", "\f", "\n", "\r", "\t", "\u0001", "\uface"]"#); + let expected = Ok(Array(vec![ + JSONValue::String(String::from("\"")), + JSONValue::String(String::from("\\")), + JSONValue::String(String::from("/")), + JSONValue::String(String::from("\u{8}")), + JSONValue::String(String::from("\x0C")), + JSONValue::String(String::from("\n")), + JSONValue::String(String::from("\r")), + JSONValue::String(String::from("\t")), + JSONValue::String(String::from("\u{1}")), + JSONValue::String(String::from("\u{face}")), + ])); + + assert_eq!(result, expected); + } + + #[test] + fn parse_full_json_example() { let result = JSON::parse( r#"[{ "a": 9.38083151965, @@ -537,6 +588,44 @@ r#"[{ "i": ["\"", "\\", "/", "\b", "\f", "\n", "\r", "\t", "\u0001", "\uface"] }]"#, ); + + let mut map: JSONMap = HashMap::new(); + let mut emap: JSONMap = HashMap::new(); + let mut fmap: JSONMap = HashMap::new(); + let mut gmap: JSONMap = HashMap::new(); + + gmap.insert(String::from("h"), Null); + + fmap.insert(String::from("g"), Object(gmap)); + + emap.insert(String::from("f"), Object(fmap)); + + map.insert(String::from("a"), Number(9.38083151965f64)); + map.insert(String::from("b"), Number(4e3f64)); + map.insert(String::from("c"), Array(vec![Number(1f64), Number(2f64), Number(3f64)])); + map.insert(String::from("d"), JSONValue::String(String::from("foo"))); + map.insert(String::from("e"), Object(emap)); + + let i = vec![ + JSONValue::String(String::from("\"")), + JSONValue::String(String::from("\\")), + JSONValue::String(String::from("/")), + JSONValue::String(String::from("\u{8}")), + JSONValue::String(String::from("\x0C")), + JSONValue::String(String::from("\n")), + JSONValue::String(String::from("\r")), + JSONValue::String(String::from("\t")), + JSONValue::String(String::from("\u{1}")), + JSONValue::String(String::from("\u{face}")), + ]; + + map.insert(String::from("i"), Array(i)); + assert!(result.is_ok(), format!("{:#?}", result)); + let result_map = result.unwrap().unwrap_array()[0].clone().unwrap_object(); + + for (k, v) in &map { + assert_eq!(result_map.get(k).unwrap(), v, "HashMap Entry Differs: {:#?}, {:#?}", result_map.get(k).unwrap(), v); + } } }