changeset 29:09d274a46fa4

Use Lazy combinator in JSON example. Current performance: 60 µs per average long JSON message on 2.00 GHz Intel i5 M460 in release mode.
author Lewin Bormann <lewin@lewin-bormann.info>
date Thu, 06 Jun 2019 22:28:24 +0200
parents f3b758646c58
children 9ef50316b2e7
files examples/json/Cargo.toml examples/json/src/lib.rs
diffstat 2 files changed, 35 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/examples/json/Cargo.toml	Thu Jun 06 22:28:00 2019 +0200
+++ b/examples/json/Cargo.toml	Thu Jun 06 22:28:24 2019 +0200
@@ -7,3 +7,4 @@
 [dependencies]
 rcombinators = { path = "../../" }
 lazy_static = "1.3"
+time-test = "0.1"
--- a/examples/json/src/lib.rs	Thu Jun 06 22:28:00 2019 +0200
+++ b/examples/json/src/lib.rs	Thu Jun 06 22:28:24 2019 +0200
@@ -1,9 +1,6 @@
 //! A simplistic JSON parser library based on the `rcombinators` crate.
 //!
 
-#[macro_use]
-extern crate lazy_static;
-
 use std::collections::HashMap;
 use std::iter::FromIterator;
 
@@ -26,22 +23,18 @@
     }
 }
 
-struct PWrapper<P>(P);
+#[derive(Default)]
+struct ValueParser;
 
-impl<P: Parser<Result=Value>> Parser for PWrapper<P> {
+impl Parser for ValueParser {
     type Result = Value;
-    fn parse(&mut self, st: &mut ParseState<impl Iterator<Item=char>>) -> ParseResult<Self::Result> {
-        self.0.parse(st)
-    }
-}
-
-#[derive(Default)]
-struct ValueParser<P>(Option<P>);
-
-impl<P: Parser<Result=Value>> Parser for ValueParser<P> {
-    type Result = Value;
-    fn parse(&mut self, st: &mut ParseState<impl Iterator<Item=char>>) -> ParseResult<Self::Result> {
-        combinators::Alternative::new((dict(), list(), string(), number())).parse(st)
+    fn parse(
+        &mut self,
+        st: &mut ParseState<impl Iterator<Item = char>>,
+    ) -> ParseResult<Self::Result> {
+        let dict = combinators::Lazy::new(dict);
+        let list = combinators::Lazy::new(list);
+        combinators::Alternative::new((string(), number(), dict, list)).parse(st)
     }
 }
 
@@ -57,12 +50,12 @@
     string
 }
 
-fn list<P: Parser<Result=Value>>(val: Option<PWrapper<P>>) -> impl Parser<Result = Value> {
+fn list() -> impl Parser<Result = Value> {
     let (open, close) = (
         primitives::StringParser::new("["),
         primitives::StringParser::new("]"),
     );
-    let val = val;
+    let val = ValueParser;
     let comma = primitives::StringParser::new(",");
     let separated_element = combinators::Sequence::new((
         primitives::whitespace(),
@@ -89,7 +82,7 @@
         Value::String(s) => Ok(s),
         _ => panic!("unexpected value type in string position"),
     });
-    let value = ValueParser(None);
+    let value = ValueParser;
     let separated_element = combinators::Sequence::new((
         primitives::whitespace(),
         key,
@@ -109,6 +102,9 @@
     dict
 }
 
+#[macro_use]
+extern crate time_test;
+
 #[cfg(test)]
 mod tests {
     use crate::*;
@@ -170,4 +166,22 @@
         ]));
         assert_eq!(Ok(want), ValueParser.parse(&mut ps));
     }
+
+    use std::iter;
+
+    #[test]
+    fn bench_value() {
+        let repeats = 12000;
+        let piece = r#"{"hello": 1.22, "world": [1, 2.3, 4, "five"], "test": "key", "lol": "ey"}"#;
+        let mut s = String::with_capacity(repeats * piece.len());
+        s.extend(iter::repeat(piece).take(repeats));
+        let mut ps = ParseState::new(&s);
+        let mut parser = ValueParser;
+        {
+            time_test!();
+            for _ in 0..repeats {
+                assert!(parser.parse(&mut ps).is_ok());
+            }
+        }
+    }
 }