jsonschema-rs/jsonschema/benches/jsonschema.rs

582 lines
17 KiB
Rust

use criterion::{black_box, criterion_group, criterion_main, Criterion};
use jsonschema::JSONSchema;
use jsonschema_valid::schemas;
use serde_json::{from_str, json, Value};
use std::{fs::File, io::Read, path::Path};
use valico::json_schema;
fn read_json(filepath: &str) -> Value {
let path = Path::new(filepath);
let mut file = File::open(&path).unwrap();
let mut content = String::new();
file.read_to_string(&mut content).ok().unwrap();
let data: Value = from_str(&content).unwrap();
data
}
fn strip_characters(original: &str) -> String {
original
.chars()
.filter(|&c| !"{}:\" ,[]".contains(c))
.collect()
}
macro_rules! bench {
(
name = $name:tt;
schema = $schema:tt;
valid = $( $valid:tt ),* $(,)*;
invalid = $( $invalid:tt ),* $(,)*;
) => {
paste::item! {
#[allow(dead_code)]
fn [<bench_ $name>](c: &mut Criterion) {
let schema = json!($schema);
let validator = JSONSchema::compile(&schema).unwrap();
let suffix = strip_characters(stringify!($schema));
c.bench_function(format!("jsonschema-rs {} compile {}", $name, suffix).as_str(), |b| b.iter(|| JSONSchema::compile(&schema).unwrap()));
$(
let instance = black_box(json!($valid));
assert!(validator.is_valid(&instance));
let suffix = strip_characters(stringify!($valid));
c.bench_function(format!("jsonschema-rs {} is_valid valid {}", $name, suffix).as_str(), |b| b.iter(|| validator.is_valid(&instance)));
c.bench_function(format!("jsonschema-rs {} validate valid {}", $name, suffix).as_str(), |b| b.iter(|| validator.validate(&instance).ok()));
)*
$(
let instance = black_box(json!($invalid));
assert!(!validator.is_valid(&instance));
let suffix = strip_characters(stringify!($invalid));
c.bench_function(format!("jsonschema-rs {} is_valid invalid {}", $name, suffix).as_str(), |b| b.iter(|| validator.is_valid(&instance)));
c.bench_function(format!("jsonschema-rs {} validate invalid {}", $name, suffix).as_str(), |b| b.iter(|| {
let _: Vec<_> = validator.validate(&instance).unwrap_err().collect();
}));
)*
}
}
};
(
name = $name:tt;
schema = $schema:tt;
invalid = $( $invalid:tt ),* $(,)*;
) => {
paste::item! {
fn [<bench_ $name>](c: &mut Criterion) {
let schema = json!($schema);
let validator = JSONSchema::compile(&schema).unwrap();
let suffix = strip_characters(stringify!($schema));
c.bench_function(format!("jsonschema-rs {} compile {}", $name, suffix).as_str(), |b| b.iter(|| JSONSchema::compile(&schema).unwrap()));
$(
let instance = black_box(json!($invalid));
assert!(!validator.is_valid(&instance));
let suffix = strip_characters(stringify!($invalid));
c.bench_function(format!("jsonschema-rs {} is_valid invalid {}", $name, suffix).as_str(), |b| b.iter(|| validator.is_valid(&instance)));
c.bench_function(format!("jsonschema-rs {} validate invalid {}", $name, suffix).as_str(), |b| b.iter(|| {
let _: Vec<_> = validator.validate(&instance).unwrap_err().collect();
}));
)*
}
}
};
}
#[allow(dead_code)]
fn big_schema(c: &mut Criterion) {
let schema = black_box(read_json("benches/canada_schema.json"));
let instance = black_box(read_json("benches/canada.json"));
// jsonschema
let validator = JSONSchema::compile(&schema).unwrap();
c.bench_function("compare jsonschema-rs big schema compile", |b| {
b.iter(|| JSONSchema::compile(&schema).unwrap())
});
c.bench_function("compare jsonschema-rs big schema is_valid", |b| {
b.iter(|| validator.is_valid(&instance))
});
c.bench_function("compare jsonschema-rs big schema validate", |b| {
b.iter(|| validator.validate(&instance).ok())
});
// jsonschema_valid
let cfg = jsonschema_valid::Config::from_schema(&schema, Some(schemas::Draft::Draft7)).unwrap();
c.bench_function("compare jsonschema_valid big schema compile", |b| {
b.iter(|| {
jsonschema_valid::Config::from_schema(&schema, Some(schemas::Draft::Draft7)).unwrap()
})
});
c.bench_function("compare jsonschema_valid big schema validate", |b| {
b.iter(|| jsonschema_valid::validate(&cfg, &instance))
});
// valico
let mut scope = json_schema::Scope::new();
let compiled = scope.compile_and_return(schema.clone(), false).unwrap();
c.bench_function("compare valico big schema compile", |b| {
b.iter(|| {
let mut scope = json_schema::Scope::new();
scope.compile_and_return(schema.clone(), false).unwrap();
})
});
c.bench_function("compare valico big schema validate", |b| {
b.iter(|| compiled.validate(&instance).is_valid())
});
}
#[allow(dead_code)]
fn small_schema(c: &mut Criterion) {
let schema = read_json("benches/small_schema.json");
let valid =
black_box(json!([9, "hello", [1, "a", true], {"a": "a", "b": "b", "d": "d"}, 42, 3]));
let invalid =
black_box(json!([10, "world", [1, "a", true], {"a": "a", "b": "b", "c": "xy"}, "str", 5]));
// jsonschema
let validator = JSONSchema::compile(&schema).unwrap();
c.bench_function("compare jsonschema-rs small schema compile", |b| {
b.iter(|| JSONSchema::compile(&schema).unwrap())
});
c.bench_function("compare jsonschema-rs small schema is_valid valid", |b| {
b.iter(|| validator.is_valid(&valid))
});
c.bench_function("compare jsonschema-rs small schema validate valid", |b| {
b.iter(|| validator.validate(&valid).ok())
});
c.bench_function("compare jsonschema-rs small schema is_valid invalid", |b| {
b.iter(|| validator.is_valid(&invalid))
});
c.bench_function("compare jsonschema-rs small schema validate invalid", |b| {
b.iter(|| {
let _: Vec<_> = validator.validate(&invalid).unwrap_err().collect();
})
});
// jsonschema_valid
let cfg = jsonschema_valid::Config::from_schema(&schema, Some(schemas::Draft::Draft7)).unwrap();
c.bench_function("compare jsonschema_valid small schema compile", |b| {
b.iter(|| {
jsonschema_valid::Config::from_schema(&schema, Some(schemas::Draft::Draft7)).unwrap()
})
});
c.bench_function(
"compare jsonschema_valid small schema validate valid",
|b| b.iter(|| jsonschema_valid::validate(&cfg, &valid)),
);
c.bench_function(
"compare jsonschema_valid small schema validate invalid",
|b| b.iter(|| jsonschema_valid::validate(&cfg, &invalid).ok()),
);
// valico
let mut scope = json_schema::Scope::new();
let compiled = scope.compile_and_return(schema.clone(), false).unwrap();
c.bench_function("compare valico small schema compile", |b| {
b.iter(|| {
let mut scope = json_schema::Scope::new();
scope.compile_and_return(schema.clone(), false).unwrap();
})
});
c.bench_function("compare valico small schema validate valid", |b| {
b.iter(|| compiled.validate(&valid).is_valid())
});
c.bench_function("compare valico small schema validate invalid", |b| {
b.iter(|| compiled.validate(&invalid).is_valid())
});
}
bench!(
name = "additional_items_boolean";
schema = {"items": [{}, {}, {}], "additionalItems": false};
valid = [1, 2, 3];
invalid = [1, 2, 3, 4];
);
bench!(
name = "additional_items_object";
schema = {"items": [{}, {}, {}], "additionalItems": {"type": "string"}};
valid = [1, 2, 3, "foo"];
invalid = [1, 2, 3, 4];
);
bench!(
name = "additional_properties_single";
schema = {"additionalProperties": {"type": "string"}};
valid = {"foo": "bar"};
invalid = {"foo": 1};
);
bench!(
name = "additional_properties_and_properties";
schema = {"additionalProperties": {"type": "string"}, "properties": {"foo": {}}};
valid = {"foo": 1};
invalid = {"foo": 1, "bar": true};
);
bench!(
name = "additional_properties_and_pattern_properties";
schema = {"additionalProperties": {"type": "string"}, "patternProperties": {"f.*o": {"type": "integer"}}};
valid = {"foo": 1};
invalid = {"foo": 1, "bar": true};
);
bench!(
name = "additional_properties_and_properties_and_pattern_properties";
schema = {"additionalProperties": {"type": "string"}, "properties": {"foo": {}}, "patternProperties": {"f.*a": {"type": "integer"}}};
valid = {"foo": null, "fza": 2};
invalid = {"foo": null, "fzo": 2, "bar": true};
);
bench!(
name = "additional_properties_false";
schema = {"additionalProperties": false};
valid = {};
invalid = {"foo": 1};
);
bench!(
name = "additional_properties_false_and_properties";
schema = {"additionalProperties": false, "properties": {"foo": {}}};
valid = {"foo": 1};
invalid = {"foo": 1, "bar": 2};
);
bench!(
name = "additional_properties_false_and_pattern_properties";
schema = {"additionalProperties": false, "patternProperties": {"f.*o": {"type": "integer"}}};
valid = {"foo": 1};
invalid = {"foo": 1, "bar": 2};
);
bench!(
name = "additional_properties_false_and_properties_and_pattern_properties";
schema = {"additionalProperties": false, "properties": {"foo": {}}, "patternProperties": {"f.*o": {"type": "integer"}}};
valid = {"foo": 1};
invalid = {"foo": 1, "fz0": 2, "bar": 2};
);
bench!(
name = "all_of";
schema = {"allOf": [{"type": "integer"}, {"minimum": 2}]};
valid = 4;
invalid = 1;
);
bench!(
name = "any_of";
schema = {"anyOf": [{"type": "integer"}, {"minimum": 2}]};
valid = 1;
invalid = 1.5;
);
bench!(
name = "any_of_multiple_types";
schema = {"anyOf": [{"type": "integer"}, {"type": "string"}]};
valid = "foo";
invalid = null;
);
bench!(
name = "boolean_false";
schema = false;
invalid = 1;
);
bench!(
name = "const";
schema = {"const": 1};
valid = 1;
invalid = "foo";
);
bench!(
name = "contains";
schema = {"contains": {"minimum": 5}};
valid = [5];
invalid = [1];
);
bench!(
name = "enum";
schema = {"enum": [1, 2, 3, 4]};
valid = 4;
invalid = 5, "6";
);
bench!(
name = "exclusive_maximum";
schema = {"exclusiveMaximum": 3};
valid = 2;
invalid = 3;
);
bench!(
name = "exclusive_minimum";
schema = {"exclusiveMinimum": 3};
valid = 4;
invalid = 3;
);
bench!(
name = "format_date";
schema = {"format": "date"};
valid = "1963-06-19";
invalid = "06/19/1963";
);
bench!(
name = "format_datetime";
schema = {"format": "date-time"};
valid = "1963-06-19T08:30:06.283185Z";
invalid = "1990-02-31T15:59:60.123-08:00";
);
bench!(
name = "format_email";
schema = {"format": "email"};
valid = "test@test.com";
invalid = "foo";
);
bench!(
name = "format_hostname";
schema = {"format": "hostname"};
valid = "www.example.com";
invalid = "not_a_valid_host_name";
);
bench!(
name = "format_ipv4";
schema = {"format": "ipv4"};
valid = "127.0.0.1";
invalid = "127.0.0.999", "foobar", "2001:0db8:85a3:0000:0000:8a2e:0370:7334";
);
bench!(
name = "format_ipv6";
schema = {"format": "ipv6"};
valid = "2001:0db8:85a3:0000:0000:8a2e:0370:7334";
invalid = "127.0.0.1", "foobar";
);
bench!(
name = "format_iri";
schema = {"format": "iri"};
valid = "http://ƒøø.ßår/?∂éœ=πîx#πîüx";
invalid = "/abc";
);
bench!(
name = "format_iri_reference";
schema = {"format": "iri-reference"};
valid = "http://ƒøø.ßår/?∂éœ=πîx#πîüx";
invalid = "#ƒräg\\mênt";
);
bench!(
name = "format_json_pointer";
schema = {"format": "json-pointer"};
valid = "/foo/bar~0/baz~1/%a";
invalid = "/foo/bar~";
);
bench!(
name = "format_regex";
schema = {"format": "regex"};
valid = r#"([abc])+\s+$"#;
invalid = "^(abc]";
);
bench!(
name = "format_relative_json_pointer";
schema = {"format": "relative-json-pointer"};
valid = "1";
invalid = "/foo/bar";
);
bench!(
name = "format_time";
schema = {"format": "time"};
valid = "08:30:06.283185Z";
invalid = "01:01:01,1111";
);
bench!(
name = "format_uri_reference";
schema = {"format": "uri-reference"};
valid = "http://foo.bar/?baz=qux#quux";
invalid = "#frag\\ment";
);
bench!(
name = "format_uri_template";
schema = {"format": "uri-template"};
valid = "http://example.com/dictionary/{term:1}/{term}";
invalid = "http://example.com/dictionary/{term:1}/{term";
);
bench!(
name = "items";
schema = {"items": {"type": "integer"}};
valid = [1, 2, 3];
invalid = [1, 2, "x"];
);
bench!(
name = "maximum";
schema = {"maximum": 3};
valid = 3;
invalid = 5;
);
bench!(
name = "max_items";
schema = {"maxItems": 1};
valid = [1];
invalid = [1, 2];
);
bench!(
name = "max_length";
schema = {"maxLength": 3};
valid = "foo";
invalid = "foob";
);
bench!(
name = "max_properties";
schema = {"maxProperties": 1};
valid = {"a": 1};
invalid = {"a": 1, "b": 1};
);
bench!(
name = "minimum";
schema = {"minimum": 3};
valid = 5;
invalid = 1;
);
bench!(
name = "min_items";
schema = {"minItems": 2};
valid = [1, 2];
invalid = [1];
);
bench!(
name = "min_length";
schema = {"minLength": 3};
valid = "123";
invalid = "12";
);
bench!(
name = "min_properties";
schema = {"minProperties": 2};
valid = {"a": 1, "b": 2};
invalid = {"a": 1};
);
bench!(
name = "multiple_of_integer";
schema = {"multipleOf": 5};
valid = 125;
invalid = 212, 212.4;
);
bench!(
name = "multiple_of_number";
schema = {"multipleOf": 2.5};
valid = 127.5;
invalid = 112.2;
);
bench!(
name = "not";
schema = {"not": {"type": "null"}};
valid = 1;
invalid = null;
);
bench!(
name = "one_of";
schema = {"oneOf": [{"type": "integer"}, {"minimum": 2}]};
valid = 1;
invalid = 3;
);
bench!(
name = "pattern";
schema = {"pattern": "A[0-9]{2}Z"};
valid = "A11Z";
invalid = "A119";
);
bench!(
name = "pattern_properties";
schema = {"patternProperties": {"f.*o": {"type": "integer"}}};
valid = {"foo": 1};
invalid = {"foo": "bar", "fooooo": 2};
);
bench!(
name = "properties";
schema = {"properties": {"foo": {"type": "string"}}};
valid = {"foo": "bar"};
invalid = {"foo": 1};
);
bench!(
name = "property_names";
schema = {"propertyNames": {"maxLength": 3}};
valid = {"ABC": 1};
invalid = {"ABCD": 1};
);
bench!(
name = "ref";
schema = {"items": [{"type": "integer"},{"$ref": "#/items/0"}]};
valid = [1, 2];
invalid = [1, "b"];
);
bench!(
name = "required";
schema = {"required": ["a"]};
valid = {"a": 1};
invalid = {};
);
bench!(
name = "type_integer";
schema = {"type": "integer"};
valid = 1, 1.0;
invalid = 1.4, "foo";
);
bench!(
name = "type_string";
schema = {"type": "string"};
valid = "foo";
invalid = 1;
);
bench!(
name = "type_multiple";
schema = {"type": ["integer", "string"]};
valid = "foo";
invalid = [];
);
bench!(
name = "unique_items";
schema = {"uniqueItems": true};
valid = [1, 2, 3, 4, 5];
invalid = [1, 2, 3, 4, 5, 1];
);
criterion_group!(
keywords,
bench_additional_items_boolean,
bench_additional_items_object,
bench_additional_properties_single,
bench_additional_properties_and_properties,
bench_additional_properties_and_pattern_properties,
bench_additional_properties_and_properties_and_pattern_properties,
bench_additional_properties_false,
bench_additional_properties_false_and_properties,
bench_additional_properties_false_and_pattern_properties,
bench_additional_properties_false_and_properties_and_pattern_properties,
bench_all_of,
bench_any_of,
bench_any_of_multiple_types,
bench_boolean_false,
bench_const,
bench_contains,
bench_enum,
bench_exclusive_maximum,
bench_exclusive_minimum,
bench_format_date,
bench_format_datetime,
bench_format_email,
bench_format_hostname,
bench_format_ipv4,
bench_format_ipv6,
bench_format_iri,
bench_format_iri_reference,
bench_format_json_pointer,
bench_format_regex,
bench_format_relative_json_pointer,
bench_format_time,
bench_format_uri_reference,
bench_format_uri_template,
bench_items,
bench_maximum,
bench_max_items,
bench_max_length,
bench_max_properties,
bench_minimum,
bench_min_items,
bench_min_length,
bench_min_properties,
bench_multiple_of_integer,
bench_multiple_of_number,
bench_not,
bench_one_of,
bench_pattern,
bench_pattern_properties,
bench_properties,
bench_property_names,
bench_ref,
bench_required,
bench_type_integer,
bench_type_string,
bench_type_multiple,
bench_unique_items,
);
criterion_group!(arbitrary, big_schema, small_schema);
criterion_main!(arbitrary, keywords);