Skip to content

Commit c59044e

Browse files
committed
feat: add benches for jq
1 parent 5cbe15c commit c59044e

File tree

3 files changed

+237
-2
lines changed

3 files changed

+237
-2
lines changed

Cargo.lock

Lines changed: 96 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,32 @@ indexmap = "2.6.0"
1111
serde_json_borrow = "0.7.1"
1212
nom = "8.0.0-alpha2"
1313
anyhow = "1.0.93"
14+
jaq-core = { version = "2" }
15+
jaq-std = { version = "2" }
16+
jaq-json = { version = "1.0.0", features = ["serde_json"]}
17+
18+
[dependencies]
19+
serde_json = { workspace = true }
20+
tailcall-template = { path = "./tailcall-template" }
21+
jaq-core = { workspace = true }
22+
jaq-std = { workspace = true }
23+
jaq-json = { workspace = true }
1424

1525
[dev-dependencies]
1626
gh-workflow = "0.4.1"
1727
pest = "2.7.14"
1828
pest_derive = {version = "2.7.14"}
1929
criterion = "0.5.1"
20-
serde_json = "1.0.133"
21-
nom = "8.0.0-alpha2"
30+
serde_json = { workspace = true }
31+
nom = { workspace = true }
2232

2333
[workspace]
2434
members = ["tailcall-template"]
2535

2636
[[bench]]
2737
name = "json_benches"
2838
harness = false
39+
40+
[[bench]]
41+
name = "jaq"
42+
harness = false

benches/jaq.rs

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
use jaq_json::Val;
2+
use serde_json::json;
3+
use criterion::{criterion_group, criterion_main, Criterion};
4+
use tailcall_template::mustache::{Mustache, Segment};
5+
use jaq_core::{load, Ctx, Native, RcIter};
6+
use load::{Arena, File, Loader};
7+
8+
criterion_group!(benches, criterion_benchmark);
9+
criterion_main!(benches);
10+
11+
pub fn criterion_benchmark(c: &mut Criterion) {
12+
// BASIC SCENARIO
13+
{
14+
let data = json!({"key": "42"});
15+
let expected = "Value: 42".to_string();
16+
{
17+
let mustache = Mustache::from(vec![
18+
Segment::Literal("Value: ".to_string()),
19+
Segment::Expression(vec!["key".to_string()]),
20+
]);
21+
c.bench_function("basic_mustache", |b| b.iter(|| bench_mustache(&data, &mustache, &expected)));
22+
}
23+
{
24+
let program = File { code: "\"Value: \" + .key", path: () };
25+
26+
// start out only from core filters,
27+
// which do not include filters in the standard library
28+
// such as `map`, `select` etc.
29+
let loader = Loader::new([]);
30+
let arena = Arena::default();
31+
32+
// parse the filter
33+
let modules = loader.load(&arena, program).unwrap();
34+
35+
// compile the filter
36+
let filter: jaq_core::Filter<Native<Val>> = jaq_core::Compiler::<_, Native<_>>::default()
37+
.compile(modules)
38+
.unwrap();
39+
40+
c.bench_function("basic_jq", |b| b.iter(|| bench_jq(&data, &filter, &expected)));
41+
}
42+
}
43+
// COMPLEX SCENARIO
44+
{
45+
let data = json!({"user": "Alice", "age": 30});
46+
let expected = "User: Alice, Age: 30".to_string();
47+
{
48+
let mustache = Mustache::from(vec![
49+
Segment::Literal("User: ".to_string()),
50+
Segment::Expression(vec!["user".to_string()]),
51+
Segment::Literal(", Age: ".to_string()),
52+
Segment::Expression(vec!["age".to_string()]),
53+
]);
54+
c.bench_function("complex_mustache", |b| b.iter(|| bench_mustache(&data, &mustache, &expected)));
55+
}
56+
{
57+
let program = File { code: "\"User: \" + .user + \", Age: \" + (.age | tostring)", path: () };
58+
let loader = Loader::new(jaq_std::defs());
59+
let arena = Arena::default();
60+
let modules = loader.load(&arena, program).unwrap();
61+
let filter = jaq_core::Compiler::<_, Native<_>>::default()
62+
.with_funs(jaq_std::funs())
63+
.compile(modules)
64+
.unwrap();
65+
66+
c.bench_function("complex_jq", |b| b.iter(|| bench_jq(&data, &filter, &expected)));
67+
}
68+
}
69+
// NESTED SCENARIO
70+
{
71+
let data = json!({
72+
"user": {
73+
"name": "Alice",
74+
"details": {
75+
"age": 30,
76+
"location": {
77+
"city": "Wonderland",
78+
"country": "Fantasy"
79+
}
80+
}
81+
}
82+
});
83+
let expected = "User: Alice, Age: 30, Location: Wonderland, Country: Fantasy".to_string();
84+
{
85+
let mustache = Mustache::from(vec![
86+
Segment::Literal("User: ".to_string()),
87+
Segment::Expression(vec!["user".to_string(), "name".to_string()]),
88+
Segment::Literal(", Age: ".to_string()),
89+
Segment::Expression(vec!["user".to_string(), "details".to_string(), "age".to_string()]),
90+
Segment::Literal(", Location: ".to_string()),
91+
Segment::Expression(vec!["user".to_string(), "details".to_string(), "location".to_string(), "city".to_string()]),
92+
Segment::Literal(", Country: ".to_string()),
93+
Segment::Expression(vec!["user".to_string(), "details".to_string(), "location".to_string(), "country".to_string()]),
94+
]);
95+
c.bench_function("nested_mustache", |b| b.iter(|| bench_mustache(&data, &mustache, &expected)));
96+
}
97+
{
98+
let program = File { code: "\"User: \" + .user.name + \", Age: \" + (.user.details.age | tostring) + \", Location: \" + .user.details.location.city + \", Country: \" + .user.details.location.country", path: () };
99+
let loader = Loader::new(jaq_std::defs());
100+
let arena = Arena::default();
101+
let modules = loader.load(&arena, program).unwrap();
102+
let filter = jaq_core::Compiler::<_, Native<_>>::default()
103+
.with_funs(jaq_std::funs())
104+
.compile(modules)
105+
.unwrap();
106+
107+
c.bench_function("nested_jq", |b| b.iter(|| bench_jq(&data, &filter, &expected)));
108+
}
109+
}
110+
}
111+
112+
fn bench_mustache(data: &serde_json::Value, mustache: &Mustache, expected: &str) {
113+
let result = mustache.render(data);
114+
assert_eq!(result, expected.to_string());
115+
}
116+
117+
fn bench_jq(data: &serde_json::Value, filter: &jaq_core::Filter<Native<Val>>, expected: &str) {
118+
let inputs = RcIter::new(core::iter::empty());
119+
120+
// iterator over the output values
121+
let mut out = filter.run((Ctx::new([], &inputs), Val::from(data.clone())));
122+
123+
assert_eq!(out.next(), Some(Ok(Val::from(expected.to_string()))));
124+
assert_eq!(out.next(), None);
125+
}

0 commit comments

Comments
 (0)