diff --git a/.gitignore b/.gitignore
index 3ecef18..9a5318b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,3 +22,5 @@ cef.log
/website_dev
screenshots/
+
+zaplib/examples/benchmark_json/data.json
diff --git a/Cargo.lock b/Cargo.lock
index b2b1486..e904221 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -320,6 +320,15 @@ version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
+[[package]]
+name = "benchmark_json_zaplib"
+version = "0.0.1"
+dependencies = [
+ "serde",
+ "serde_json",
+ "zaplib",
+]
+
[[package]]
name = "bigedit_http"
version = "0.0.1"
diff --git a/Cargo.toml b/Cargo.toml
index 34982bd..efebdf8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -3,6 +3,7 @@ resolver = "2"
members = [
"zaplib/cargo-zaplib",
"zaplib/ci",
+ "zaplib/examples/benchmark_json/zaplib",
"zaplib/examples/example_bigedit",
"zaplib/examples/example_bigedit/http",
"zaplib/examples/example_bigedit/hub",
diff --git a/zaplib/examples/benchmark_json/generate_json.rb b/zaplib/examples/benchmark_json/generate_json.rb
new file mode 100644
index 0000000..e7d90e3
--- /dev/null
+++ b/zaplib/examples/benchmark_json/generate_json.rb
@@ -0,0 +1,23 @@
+# https://github.com/kostya/benchmarks/blob/1dd7deb29a813d1095e6062c25ad92bd81ce0273/json/generate_json.rb
+
+# frozen_string_literal: true
+
+require 'json'
+
+x = []
+
+524_288.times do
+ h = {
+ 'x' => rand * -10e-30,
+ 'y' => rand * 10e30,
+ 'z' => rand,
+ 'name' => "#{('a'..'z').to_a.sample(6).join} #{rand(10_000)}",
+ 'opts' => { '1' => [1, true] }
+ }
+ x << h
+end
+
+File.write(
+ 'data.json',
+ JSON.pretty_generate('coordinates' => x, 'info' => 'some info')
+)
diff --git a/zaplib/examples/benchmark_json/index.html b/zaplib/examples/benchmark_json/index.html
new file mode 100644
index 0000000..7163608
--- /dev/null
+++ b/zaplib/examples/benchmark_json/index.html
@@ -0,0 +1,82 @@
+
+
+
+
+
+ Zaplib (rust/wasm) vs JS: 100mb JSON parsing
+
+ This benchmark was adapted from kostya/benchmarks to work for JS (web) vs Zaplib (rust/wasm).
+
+
+ To re-generate the json file locally, run the generate_json.rb
file in this directory.
+
+
+ It would be interesting augment the Rust benchmark with a simd-powered parsing library, but I wasn't able to get one to compile on my M1 mac... yet!
+
+
+ You may notice that the Zaplib benchmark runs about 2x slower (about the same time as the JS) if the devtools are open. We don't exactly know why this is – likely it's a debug or profiling mode that gets enabled.
+
+
+
+ Language |
+ Parsing Time (ms) |
+ Compute Time (ms |
+
+
+ JavaScript (JSON.parse ) |
+ |
+ |
+
+
+ Zaplib Rust Wasm (w/ Serde) |
+ |
+ |
+
+
+
+
+
+
diff --git a/zaplib/examples/benchmark_json/js/index.js b/zaplib/examples/benchmark_json/js/index.js
new file mode 100644
index 0000000..279c3c0
--- /dev/null
+++ b/zaplib/examples/benchmark_json/js/index.js
@@ -0,0 +1,40 @@
+// Based on https://github.com/kostya/benchmarks/blob/1dd7deb29a813d1095e6062c25ad92bd81ce0273/json/test.js
+
+'use strict';
+
+function calc(jobj) {
+ const coordinates = jobj['coordinates'];
+ const len = coordinates.length;
+ let x = 0;
+ let y = 0;
+ let z = 0;
+
+ for (let i = 0; i < coordinates.length; i++) {
+ const coord = coordinates[i];
+ x += coord['x'];
+ y += coord['y'];
+ z += coord['z'];
+ }
+
+ return {
+ x: x / len,
+ y: y / len,
+ z: z / len
+ };
+}
+
+const textP = fetch('/zaplib/examples/benchmark_json/data.json').then(response => response.text());
+
+const benchmarkJS = async function() {
+ const text = await textP;
+
+ const startP = performance.now()
+ const jobj = JSON.parse(text);
+ const endP = performance.now();
+
+ const start = performance.now()
+ const results = calc(jobj);
+ const end = performance.now();
+
+ return [endP-startP, end - start];
+}
diff --git a/zaplib/examples/benchmark_json/zaplib/Cargo.toml b/zaplib/examples/benchmark_json/zaplib/Cargo.toml
new file mode 100644
index 0000000..8428edd
--- /dev/null
+++ b/zaplib/examples/benchmark_json/zaplib/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "benchmark_json_zaplib"
+version = "0.0.1"
+edition = "2021"
+publish = false
+
+[dependencies]
+zaplib = { path = "../../../main" }
+serde_json = "1.0.79"
+serde = { version = "1.0.136", features = ["derive"] }
diff --git a/zaplib/examples/benchmark_json/zaplib/src/main.rs b/zaplib/examples/benchmark_json/zaplib/src/main.rs
new file mode 100644
index 0000000..a76a9cf
--- /dev/null
+++ b/zaplib/examples/benchmark_json/zaplib/src/main.rs
@@ -0,0 +1,53 @@
+// Based on https://github.com/kostya/benchmarks/blob/1dd7deb29a813d1095e6062c25ad92bd81ce0273/json/json.rs/src/json_struct.rs
+
+use serde::Deserialize;
+use std::io::Read;
+use zaplib::*;
+
+#[derive(Deserialize, PartialEq)]
+struct Coordinate {
+ x: f64,
+ y: f64,
+ z: f64,
+}
+
+#[derive(Deserialize)]
+struct TestStruct {
+ coordinates: Vec,
+}
+
+fn calc(jobj: TestStruct) -> Coordinate {
+ let len = jobj.coordinates.len() as f64;
+ let mut x = 0_f64;
+ let mut y = 0_f64;
+ let mut z = 0_f64;
+
+ for coord in &jobj.coordinates {
+ x += coord.x;
+ y += coord.y;
+ z += coord.z;
+ }
+
+ Coordinate { x: x / len, y: y / len, z: z / len }
+}
+
+fn call_rust(_name: String, _params: Vec) -> Vec {
+ let mut file = UniversalFile::open("zaplib/examples/benchmark_json/data.json").unwrap();
+ let mut s = String::new();
+ let ret = file.read_to_string(&mut s);
+ if ret.is_err() {
+ panic!("Failed to read file");
+ }
+
+ let start_p = Instant::now();
+ let jobj = serde_json::from_str::(&s).unwrap();
+ let end_p: UniversalInstant = Instant::now();
+
+ let start = Instant::now();
+ calc(jobj);
+ let end: UniversalInstant = Instant::now();
+
+ vec![vec![end_p.duration_since(start_p).as_millis() as u32, end.duration_since(start).as_millis() as u32].into_param()]
+}
+
+register_call_rust!(call_rust);