From e4070abd40ce8210572e19f60aef7752175fd06f Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Tue, 11 Feb 2020 10:57:48 -0500 Subject: [PATCH] Less clever, lazy evaluation of parser method chain --- src/lib.rs | 102 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 59 insertions(+), 43 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0ff2169..8fb7796 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -79,38 +79,37 @@ impl JSON { } /// Parse a `JSONValue` from the current JSON string - /// - /// This is probably an abuse of iterators...but it's still much better than the alternative - /// of nested matches. - /// - /// In order to determine the type of JSON value, each parse method is tried, until one - /// matches, or a parse error happens. - /// - /// * `Option`s implement IntoIterator, which returns an iterator of 0 or 1 items: the - /// transferred (not borrowed) Some() value. - /// * The `chain` method of iterators allows you to link iterators together, - /// to act as one iterator - /// * The first result from the iterator is the first parse method with a non-empty value, - /// and should be the value wanted fn parse_value(&mut self) -> Result { self.skip_whitespace(); - let mut value = self - .parse_string()? - .into_iter() - .chain(self.parse_number()?.into_iter()) - .chain(self.parse_object()?.into_iter()) - .chain(self.parse_array()?.into_iter()) - .chain(self.parse_keyword("true", JSONValue::True)?.into_iter()) - .chain(self.parse_keyword("false", JSONValue::False)?.into_iter()) - .chain(self.parse_keyword("null", JSONValue::Null)?.into_iter()); - - match value.next() { - Some(val) => Ok(val), - None => Err(ParseError::UnexpectedEndOfInput(String::from( + return if let Some(string) = self.parse_string()? { + Ok(string) + } else if let Some(number) = self.parse_number()? { + Ok(number) + } else if let Some(object) = self.parse_object()? { + Ok(object) + } else if let Some(array) = self.parse_array()? { + Ok(array) + } else if let Some(t) = self.parse_keyword("true", JSONValue::True)? { + Ok(t) + } else if let Some(f) = self.parse_keyword("false", JSONValue::False)? { + Ok(f) + } else if let Some(n) = self.parse_keyword("null", JSONValue::Null)? { + Ok(n) + } else { + Err(ParseError::UnexpectedEndOfInput(String::from( "Doesn't seem to be valid JSON", - ))), - } + ))) + }; + + // Eagerly evaluated simpler alternative to the original option iterator chain + // let value = self.parse_string()? + // .or(self.parse_number()?) + // .or(self.parse_object()?) + // .or(self.parse_array()?) + // .or(self.parse_keyword("true", JSONValue::True)?) + // .or(self.parse_keyword("false", JSONValue::False)?) + // .or(self.parse_keyword("null", JSONValue::Null)?); } /// See if there's a `JSONValue::Object` next in the JSON @@ -255,7 +254,7 @@ impl JSON { let start = self.i; // If it doesn't start with 0-9 or a minus sign, it's probably not a number - if ! (self.chars[start].is_ascii_digit() || self.chars[start] == '-') { + if !(self.chars[start].is_ascii_digit() || self.chars[start] == '-') { return Ok(None); } @@ -297,11 +296,7 @@ impl JSON { // If there are numeric digits attempt to parse the digits as a number if n > start { - let mut end = if n < self.chars.len() { - n - } else { - max - }; + let mut end = if n < self.chars.len() { n } else { max }; // Hack to remove non-number characters if !self.chars[end].is_ascii_digit() { @@ -313,8 +308,8 @@ impl JSON { match str.parse::() { Ok(number) => { self.increment(str.len()); - return Ok(Some(JSONValue::Number(number))) - }, + return Ok(Some(JSONValue::Number(number))); + } Err(e) => Err(ParseError::ExpectedDigit(format!("'{}', {:#?}", str, e))), } } else { @@ -488,19 +483,37 @@ mod tests { // Number let res = JSON::parse("9.38083151965"); - assert_eq!(res, Ok(JSONValue::Number(9.38083151965)), "Failed to parse number"); + assert_eq!( + res, + Ok(JSONValue::Number(9.38083151965)), + "Failed to parse number" + ); // String let res = JSON::parse(r#""/^$/""#); - assert_eq!(res, Ok(JSONValue::String(String::from("/^$/"))), "Failed to parse string"); + assert_eq!( + res, + Ok(JSONValue::String(String::from("/^$/"))), + "Failed to parse string" + ); // Number array let res = JSON::parse("[1, 2, 3]"); - assert_eq!(res, Ok(JSONValue::Array(vec![JSONValue::Number(1f64), JSONValue::Number(2f64), JSONValue::Number(3f64)]))); + assert_eq!( + res, + Ok(JSONValue::Array(vec![ + JSONValue::Number(1f64), + JSONValue::Number(2f64), + JSONValue::Number(3f64) + ])) + ); // Object array let result = JSON::parse("[{}]"); - assert_eq!(result, Ok(JSONValue::Array(vec![JSONValue::Object(HashMap::new())]))); + assert_eq!( + result, + Ok(JSONValue::Array(vec![JSONValue::Object(HashMap::new())])) + ); } #[test] @@ -512,8 +525,10 @@ mod tests { #[test] fn can_parse_arbitrary_json() { let result = JSON::parse(r#"[{ "a": 9.38083151965, "b": 4e3 }]"#); - assert!(result.is_ok(), format!("Failed on just number values: {:#?}", result)); - + assert!( + result.is_ok(), + format!("Failed on just number values: {:#?}", result) + ); let result = JSON::parse( r#"[{ @@ -529,7 +544,8 @@ mod tests { } }, "i": ["\"", "\\", "/", "\b", "\f", "\n", "\r", "\t", "\u0001", "\uface"] -}]"#); +}]"#, + ); assert!(result.is_ok(), format!("{:#?}", result)); } }