Skip to content

Commit b1d11cb

Browse files
committed
bench: initial results for jsonlikehelper
1 parent d9a613d commit b1d11cb

File tree

3 files changed

+166
-27
lines changed

3 files changed

+166
-27
lines changed

benches/jaq.rs

Lines changed: 134 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1-
use jaq_json::Val;
2-
use serde_json::json;
31
use criterion::{criterion_group, criterion_main, Criterion};
4-
use tailcall_template::mustache::{Mustache, Segment};
52
use jaq_core::{load, Ctx, Native, RcIter};
3+
use jaq_json::Val;
64
use load::{Arena, File, Loader};
5+
use serde_json::json;
6+
use tailcall_template::{
7+
self,
8+
jq::jq::JsonLikeHelper,
9+
mustache::{Mustache, Segment},
10+
};
711

812
criterion_group!(benches, criterion_benchmark);
913
criterion_main!(benches);
@@ -18,10 +22,15 @@ pub fn criterion_benchmark(c: &mut Criterion) {
1822
Segment::Literal("Value: ".to_string()),
1923
Segment::Expression(vec!["key".to_string()]),
2024
]);
21-
c.bench_function("basic_mustache", |b| b.iter(|| bench_mustache(&data, &mustache, &expected)));
25+
c.bench_function("basic_mustache", |b| {
26+
b.iter(|| bench_mustache(&data, &mustache, &expected))
27+
});
2228
}
2329
{
24-
let program = File { code: "\"Value: \" + .key", path: () };
30+
let program = File {
31+
code: "\"Value: \" + .key",
32+
path: (),
33+
};
2534

2635
// start out only from core filters,
2736
// which do not include filters in the standard library
@@ -33,11 +42,39 @@ pub fn criterion_benchmark(c: &mut Criterion) {
3342
let modules = loader.load(&arena, program).unwrap();
3443

3544
// compile the filter
36-
let filter: jaq_core::Filter<Native<Val>> = jaq_core::Compiler::<_, Native<_>>::default()
37-
.compile(modules)
38-
.unwrap();
45+
let filter: jaq_core::Filter<Native<Val>> =
46+
jaq_core::Compiler::<_, Native<_>>::default()
47+
.compile(modules)
48+
.unwrap();
3949

40-
c.bench_function("basic_jq", |b| b.iter(|| bench_jq(&data, &filter, &expected)));
50+
c.bench_function("basic_jq", |b| {
51+
b.iter(|| bench_jq(&data, &filter, &expected))
52+
});
53+
}
54+
{
55+
let program = File {
56+
code: "\"Value: \" + .key",
57+
path: (),
58+
};
59+
60+
// start out only from core filters,
61+
// which do not include filters in the standard library
62+
// such as `map`, `select` etc.
63+
let loader = Loader::new([]);
64+
let arena = Arena::default();
65+
66+
// parse the filter
67+
let modules = loader.load(&arena, program).unwrap();
68+
69+
// compile the filter
70+
let filter: jaq_core::Filter<Native<JsonLikeHelper<serde_json::Value>>> =
71+
jaq_core::Compiler::<_, Native<_>>::default()
72+
.compile(modules)
73+
.unwrap();
74+
75+
c.bench_function("basic_jsonlike", |b| {
76+
b.iter(|| bench_jsonlike(&data, &filter, &expected))
77+
});
4178
}
4279
}
4380
// COMPLEX SCENARIO
@@ -51,19 +88,44 @@ pub fn criterion_benchmark(c: &mut Criterion) {
5188
Segment::Literal(", Age: ".to_string()),
5289
Segment::Expression(vec!["age".to_string()]),
5390
]);
54-
c.bench_function("complex_mustache", |b| b.iter(|| bench_mustache(&data, &mustache, &expected)));
91+
c.bench_function("complex_mustache", |b| {
92+
b.iter(|| bench_mustache(&data, &mustache, &expected))
93+
});
5594
}
5695
{
57-
let program = File { code: "\"User: \" + .user + \", Age: \" + (.age | tostring)", path: () };
58-
let loader = Loader::new(jaq_std::defs());
96+
let program = File {
97+
code: "\"User: \" + .user + \", Age: \" + (.age | tostring)",
98+
path: (),
99+
};
100+
let defs = jaq_core::load::parse("def tostring: \"\\(.)\";", |p| p.defs()).unwrap();
101+
let loader = Loader::new(defs);
59102
let arena = Arena::default();
60103
let modules = loader.load(&arena, program).unwrap();
61104
let filter = jaq_core::Compiler::<_, Native<_>>::default()
62-
.with_funs(jaq_std::funs())
63105
.compile(modules)
64106
.unwrap();
65107

66-
c.bench_function("complex_jq", |b| b.iter(|| bench_jq(&data, &filter, &expected)));
108+
c.bench_function("complex_jq", |b| {
109+
b.iter(|| bench_jq(&data, &filter, &expected))
110+
});
111+
}
112+
{
113+
let program = File {
114+
code: "\"User: \" + .user + \", Age: \" + (.age | tostring)",
115+
path: (),
116+
};
117+
118+
let defs = jaq_core::load::parse("def tostring: \"\\(.)\";", |p| p.defs()).unwrap();
119+
let loader = Loader::new(defs);
120+
let arena = Arena::default();
121+
let modules = loader.load(&arena, program).unwrap();
122+
let filter = jaq_core::Compiler::<_, Native<_>>::default()
123+
.compile(modules)
124+
.unwrap();
125+
126+
c.bench_function("complex_jsonlike", |b| {
127+
b.iter(|| bench_jsonlike(&data, &filter, &expected))
128+
});
67129
}
68130
}
69131
// NESTED SCENARIO
@@ -86,25 +148,57 @@ pub fn criterion_benchmark(c: &mut Criterion) {
86148
Segment::Literal("User: ".to_string()),
87149
Segment::Expression(vec!["user".to_string(), "name".to_string()]),
88150
Segment::Literal(", Age: ".to_string()),
89-
Segment::Expression(vec!["user".to_string(), "details".to_string(), "age".to_string()]),
151+
Segment::Expression(vec![
152+
"user".to_string(),
153+
"details".to_string(),
154+
"age".to_string(),
155+
]),
90156
Segment::Literal(", Location: ".to_string()),
91-
Segment::Expression(vec!["user".to_string(), "details".to_string(), "location".to_string(), "city".to_string()]),
157+
Segment::Expression(vec![
158+
"user".to_string(),
159+
"details".to_string(),
160+
"location".to_string(),
161+
"city".to_string(),
162+
]),
92163
Segment::Literal(", Country: ".to_string()),
93-
Segment::Expression(vec!["user".to_string(), "details".to_string(), "location".to_string(), "country".to_string()]),
164+
Segment::Expression(vec![
165+
"user".to_string(),
166+
"details".to_string(),
167+
"location".to_string(),
168+
"country".to_string(),
169+
]),
94170
]);
95-
c.bench_function("nested_mustache", |b| b.iter(|| bench_mustache(&data, &mustache, &expected)));
171+
c.bench_function("nested_mustache", |b| {
172+
b.iter(|| bench_mustache(&data, &mustache, &expected))
173+
});
174+
}
175+
{
176+
let program = File { code: "\"User: \" + .user.name + \", Age: \" + (.user.details.age | tostring) + \", Location: \" + .user.details.location.city + \", Country: \" + .user.details.location.country", path: () };
177+
let defs = jaq_core::load::parse("def tostring: \"\\(.)\";", |p| p.defs()).unwrap();
178+
let loader = Loader::new(defs);
179+
let arena = Arena::default();
180+
let modules = loader.load(&arena, program).unwrap();
181+
let filter = jaq_core::Compiler::<_, Native<_>>::default()
182+
.compile(modules)
183+
.unwrap();
184+
185+
c.bench_function("nested_jq", |b| {
186+
b.iter(|| bench_jq(&data, &filter, &expected))
187+
});
96188
}
97189
{
98190
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());
191+
let defs = jaq_core::load::parse("def tostring: \"\\(.)\";", |p| p.defs()).unwrap();
192+
let loader = Loader::new(defs);
100193
let arena = Arena::default();
101194
let modules = loader.load(&arena, program).unwrap();
102195
let filter = jaq_core::Compiler::<_, Native<_>>::default()
103-
.with_funs(jaq_std::funs())
104196
.compile(modules)
105197
.unwrap();
106198

107-
c.bench_function("nested_jq", |b| b.iter(|| bench_jq(&data, &filter, &expected)));
199+
c.bench_function("nested_jsonlike", |b| {
200+
b.iter(|| bench_jsonlike(&data, &filter, &expected))
201+
});
108202
}
109203
}
110204
}
@@ -123,3 +217,22 @@ fn bench_jq(data: &serde_json::Value, filter: &jaq_core::Filter<Native<Val>>, ex
123217
assert_eq!(out.next(), Some(Ok(Val::from(expected.to_string()))));
124218
assert_eq!(out.next(), None);
125219
}
220+
221+
fn bench_jsonlike(
222+
data: &serde_json::Value,
223+
filter: &jaq_core::Filter<Native<JsonLikeHelper<serde_json::Value>>>,
224+
expected: &str,
225+
) {
226+
let inputs = RcIter::new(core::iter::empty());
227+
228+
// iterator over the output values
229+
let mut out = filter.run((Ctx::new([], &inputs), JsonLikeHelper(data.clone())));
230+
231+
assert_eq!(
232+
out.next(),
233+
Some(Ok(JsonLikeHelper(serde_json::Value::String(
234+
expected.to_string()
235+
))))
236+
);
237+
assert_eq!(out.next(), None);
238+
}

tailcall-template/src/jq/jq.rs

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
use std::ops::Deref;
1+
use std::{borrow::Cow, ops::Deref};
22

33
use jaq_core::ValR;
44

55
use crate::jsonlike::{JsonLike, JsonObjectLike};
66

7-
#[derive(Clone, PartialEq)]
7+
#[derive(Debug, Clone, PartialEq)]
88
pub struct JsonLikeHelper<
99
A: for<'a> JsonLike<'a> + std::fmt::Display + std::clone::Clone + std::cmp::PartialEq + 'static,
1010
>(pub A);
@@ -384,7 +384,7 @@ where
384384
A: for<'a> JsonLike<'a> + std::fmt::Display + std::clone::Clone + std::cmp::PartialEq + 'static,
385385
{
386386
fn from(value: String) -> Self {
387-
todo!()
387+
JsonLikeHelper(JsonLike::string(Cow::Owned(value)))
388388
}
389389
}
390390

@@ -402,8 +402,34 @@ where
402402
A: for<'a> JsonLike<'a> + std::fmt::Display + std::clone::Clone + std::cmp::PartialEq + 'static,
403403
{
404404
type Output = ValR<Self>;
405-
fn add(self, rhs: Self) -> Self::Output {
406-
todo!()
405+
fn add(mut self, rhs: Self) -> Self::Output {
406+
if self.0.is_null() && rhs.0.is_null() {
407+
return Ok(self);
408+
}
409+
410+
if let (Some(l), Some(r)) = (self.0.as_f64(), &rhs.0.as_f64()) {
411+
return Ok(JsonLikeHelper(A::number_f64(l + r)));
412+
}
413+
414+
if let (Some(l), Some(r)) = (self.0.as_str(), &rhs.0.as_str()) {
415+
let mut result = String::from(l);
416+
result.push_str(r);
417+
return Ok(JsonLikeHelper(A::string(result.into())));
418+
}
419+
420+
if let (Some(l), Some(r)) = (self.0.as_array_mut(), &rhs.0.as_array()) {
421+
l.extend(r.iter().cloned());
422+
return Ok(self);
423+
}
424+
425+
if let (Some(l), Some(r)) = (self.0.as_object_mut(), &rhs.0.as_object()) {
426+
for (k, v) in r.iter() {
427+
l.insert_key(k, v.clone());
428+
}
429+
return Ok(self);
430+
}
431+
432+
Err(jaq_core::Error::str("Cannot add values of different types"))
407433
}
408434
}
409435

tailcall-template/src/jq/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
mod jq;
1+
pub mod jq;

0 commit comments

Comments
 (0)