Skip to content

Commit

Permalink
bench: initial results for jsonlikehelper
Browse files Browse the repository at this point in the history
  • Loading branch information
karatakis committed Dec 2, 2024
1 parent d9a613d commit b1d11cb
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 27 deletions.
155 changes: 134 additions & 21 deletions benches/jaq.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
use jaq_json::Val;
use serde_json::json;
use criterion::{criterion_group, criterion_main, Criterion};
use tailcall_template::mustache::{Mustache, Segment};
use jaq_core::{load, Ctx, Native, RcIter};
use jaq_json::Val;
use load::{Arena, File, Loader};
use serde_json::json;
use tailcall_template::{
self,
jq::jq::JsonLikeHelper,
mustache::{Mustache, Segment},
};

criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);
Expand All @@ -18,10 +22,15 @@ pub fn criterion_benchmark(c: &mut Criterion) {
Segment::Literal("Value: ".to_string()),
Segment::Expression(vec!["key".to_string()]),
]);
c.bench_function("basic_mustache", |b| b.iter(|| bench_mustache(&data, &mustache, &expected)));
c.bench_function("basic_mustache", |b| {
b.iter(|| bench_mustache(&data, &mustache, &expected))
});
}
{
let program = File { code: "\"Value: \" + .key", path: () };
let program = File {
code: "\"Value: \" + .key",
path: (),
};

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

// compile the filter
let filter: jaq_core::Filter<Native<Val>> = jaq_core::Compiler::<_, Native<_>>::default()
.compile(modules)
.unwrap();
let filter: jaq_core::Filter<Native<Val>> =
jaq_core::Compiler::<_, Native<_>>::default()
.compile(modules)
.unwrap();

c.bench_function("basic_jq", |b| b.iter(|| bench_jq(&data, &filter, &expected)));
c.bench_function("basic_jq", |b| {
b.iter(|| bench_jq(&data, &filter, &expected))
});
}
{
let program = File {
code: "\"Value: \" + .key",
path: (),
};

// start out only from core filters,
// which do not include filters in the standard library
// such as `map`, `select` etc.
let loader = Loader::new([]);
let arena = Arena::default();

// parse the filter
let modules = loader.load(&arena, program).unwrap();

// compile the filter
let filter: jaq_core::Filter<Native<JsonLikeHelper<serde_json::Value>>> =
jaq_core::Compiler::<_, Native<_>>::default()
.compile(modules)
.unwrap();

c.bench_function("basic_jsonlike", |b| {
b.iter(|| bench_jsonlike(&data, &filter, &expected))
});
}
}
// COMPLEX SCENARIO
Expand All @@ -51,19 +88,44 @@ pub fn criterion_benchmark(c: &mut Criterion) {
Segment::Literal(", Age: ".to_string()),
Segment::Expression(vec!["age".to_string()]),
]);
c.bench_function("complex_mustache", |b| b.iter(|| bench_mustache(&data, &mustache, &expected)));
c.bench_function("complex_mustache", |b| {
b.iter(|| bench_mustache(&data, &mustache, &expected))
});
}
{
let program = File { code: "\"User: \" + .user + \", Age: \" + (.age | tostring)", path: () };
let loader = Loader::new(jaq_std::defs());
let program = File {
code: "\"User: \" + .user + \", Age: \" + (.age | tostring)",
path: (),
};
let defs = jaq_core::load::parse("def tostring: \"\\(.)\";", |p| p.defs()).unwrap();
let loader = Loader::new(defs);
let arena = Arena::default();
let modules = loader.load(&arena, program).unwrap();
let filter = jaq_core::Compiler::<_, Native<_>>::default()
.with_funs(jaq_std::funs())
.compile(modules)
.unwrap();

c.bench_function("complex_jq", |b| b.iter(|| bench_jq(&data, &filter, &expected)));
c.bench_function("complex_jq", |b| {
b.iter(|| bench_jq(&data, &filter, &expected))
});
}
{
let program = File {
code: "\"User: \" + .user + \", Age: \" + (.age | tostring)",
path: (),
};

let defs = jaq_core::load::parse("def tostring: \"\\(.)\";", |p| p.defs()).unwrap();
let loader = Loader::new(defs);
let arena = Arena::default();
let modules = loader.load(&arena, program).unwrap();
let filter = jaq_core::Compiler::<_, Native<_>>::default()
.compile(modules)
.unwrap();

c.bench_function("complex_jsonlike", |b| {
b.iter(|| bench_jsonlike(&data, &filter, &expected))
});
}
}
// NESTED SCENARIO
Expand All @@ -86,25 +148,57 @@ pub fn criterion_benchmark(c: &mut Criterion) {
Segment::Literal("User: ".to_string()),
Segment::Expression(vec!["user".to_string(), "name".to_string()]),
Segment::Literal(", Age: ".to_string()),
Segment::Expression(vec!["user".to_string(), "details".to_string(), "age".to_string()]),
Segment::Expression(vec![
"user".to_string(),
"details".to_string(),
"age".to_string(),
]),
Segment::Literal(", Location: ".to_string()),
Segment::Expression(vec!["user".to_string(), "details".to_string(), "location".to_string(), "city".to_string()]),
Segment::Expression(vec![
"user".to_string(),
"details".to_string(),
"location".to_string(),
"city".to_string(),
]),
Segment::Literal(", Country: ".to_string()),
Segment::Expression(vec!["user".to_string(), "details".to_string(), "location".to_string(), "country".to_string()]),
Segment::Expression(vec![
"user".to_string(),
"details".to_string(),
"location".to_string(),
"country".to_string(),
]),
]);
c.bench_function("nested_mustache", |b| b.iter(|| bench_mustache(&data, &mustache, &expected)));
c.bench_function("nested_mustache", |b| {
b.iter(|| bench_mustache(&data, &mustache, &expected))
});
}
{
let program = File { code: "\"User: \" + .user.name + \", Age: \" + (.user.details.age | tostring) + \", Location: \" + .user.details.location.city + \", Country: \" + .user.details.location.country", path: () };
let defs = jaq_core::load::parse("def tostring: \"\\(.)\";", |p| p.defs()).unwrap();
let loader = Loader::new(defs);
let arena = Arena::default();
let modules = loader.load(&arena, program).unwrap();
let filter = jaq_core::Compiler::<_, Native<_>>::default()
.compile(modules)
.unwrap();

c.bench_function("nested_jq", |b| {
b.iter(|| bench_jq(&data, &filter, &expected))
});
}
{
let program = File { code: "\"User: \" + .user.name + \", Age: \" + (.user.details.age | tostring) + \", Location: \" + .user.details.location.city + \", Country: \" + .user.details.location.country", path: () };
let loader = Loader::new(jaq_std::defs());
let defs = jaq_core::load::parse("def tostring: \"\\(.)\";", |p| p.defs()).unwrap();
let loader = Loader::new(defs);
let arena = Arena::default();
let modules = loader.load(&arena, program).unwrap();
let filter = jaq_core::Compiler::<_, Native<_>>::default()
.with_funs(jaq_std::funs())
.compile(modules)
.unwrap();

c.bench_function("nested_jq", |b| b.iter(|| bench_jq(&data, &filter, &expected)));
c.bench_function("nested_jsonlike", |b| {
b.iter(|| bench_jsonlike(&data, &filter, &expected))
});
}
}
}
Expand All @@ -123,3 +217,22 @@ fn bench_jq(data: &serde_json::Value, filter: &jaq_core::Filter<Native<Val>>, ex
assert_eq!(out.next(), Some(Ok(Val::from(expected.to_string()))));
assert_eq!(out.next(), None);
}

fn bench_jsonlike(
data: &serde_json::Value,
filter: &jaq_core::Filter<Native<JsonLikeHelper<serde_json::Value>>>,
expected: &str,
) {
let inputs = RcIter::new(core::iter::empty());

// iterator over the output values
let mut out = filter.run((Ctx::new([], &inputs), JsonLikeHelper(data.clone())));

assert_eq!(
out.next(),
Some(Ok(JsonLikeHelper(serde_json::Value::String(
expected.to_string()
))))
);
assert_eq!(out.next(), None);
}
36 changes: 31 additions & 5 deletions tailcall-template/src/jq/jq.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use std::ops::Deref;
use std::{borrow::Cow, ops::Deref};

use jaq_core::ValR;

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

#[derive(Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq)]
pub struct JsonLikeHelper<
A: for<'a> JsonLike<'a> + std::fmt::Display + std::clone::Clone + std::cmp::PartialEq + 'static,
>(pub A);
Expand Down Expand Up @@ -384,7 +384,7 @@ where
A: for<'a> JsonLike<'a> + std::fmt::Display + std::clone::Clone + std::cmp::PartialEq + 'static,
{
fn from(value: String) -> Self {
todo!()
JsonLikeHelper(JsonLike::string(Cow::Owned(value)))
}
}

Expand All @@ -402,8 +402,34 @@ where
A: for<'a> JsonLike<'a> + std::fmt::Display + std::clone::Clone + std::cmp::PartialEq + 'static,
{
type Output = ValR<Self>;
fn add(self, rhs: Self) -> Self::Output {
todo!()
fn add(mut self, rhs: Self) -> Self::Output {
if self.0.is_null() && rhs.0.is_null() {
return Ok(self);
}

if let (Some(l), Some(r)) = (self.0.as_f64(), &rhs.0.as_f64()) {
return Ok(JsonLikeHelper(A::number_f64(l + r)));
}

if let (Some(l), Some(r)) = (self.0.as_str(), &rhs.0.as_str()) {
let mut result = String::from(l);
result.push_str(r);
return Ok(JsonLikeHelper(A::string(result.into())));
}

if let (Some(l), Some(r)) = (self.0.as_array_mut(), &rhs.0.as_array()) {
l.extend(r.iter().cloned());
return Ok(self);
}

if let (Some(l), Some(r)) = (self.0.as_object_mut(), &rhs.0.as_object()) {
for (k, v) in r.iter() {
l.insert_key(k, v.clone());
}
return Ok(self);
}

Err(jaq_core::Error::str("Cannot add values of different types"))
}
}

Expand Down
2 changes: 1 addition & 1 deletion tailcall-template/src/jq/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1 @@
mod jq;
pub mod jq;

0 comments on commit b1d11cb

Please sign in to comment.