dry-validation-rust 0.1.0.pre5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +74 -0
- data/LICENSE +21 -0
- data/NOTICE.md +28 -0
- data/README.md +459 -0
- data/docs/ARCHITECTURE.md +256 -0
- data/docs/COMPATIBILITY.md +198 -0
- data/docs/FEASIBILITY.md +207 -0
- data/docs/SUPPORT_MATRIX.md +66 -0
- data/docs/VERIFICATION.md +128 -0
- data/dry-validation-rust.gemspec +58 -0
- data/ext/dry_validation_rust/Cargo.lock +809 -0
- data/ext/dry_validation_rust/Cargo.toml +44 -0
- data/ext/dry_validation_rust/benches/coercion.rs +77 -0
- data/ext/dry_validation_rust/benches/full_schema.rs +189 -0
- data/ext/dry_validation_rust/benches/plan_compile.rs +37 -0
- data/ext/dry_validation_rust/benches/predicates.rs +105 -0
- data/ext/dry_validation_rust/extconf.rb +29 -0
- data/ext/dry_validation_rust/src/coercion.rs +515 -0
- data/ext/dry_validation_rust/src/engine.rs +416 -0
- data/ext/dry_validation_rust/src/error.rs +82 -0
- data/ext/dry_validation_rust/src/extract_primitive.rs +23 -0
- data/ext/dry_validation_rust/src/generated_predicates.rs +33 -0
- data/ext/dry_validation_rust/src/lib.rs +228 -0
- data/ext/dry_validation_rust/src/plan.rs +611 -0
- data/ext/dry_validation_rust/src/predicates.rs +449 -0
- data/ext/dry_validation_rust/src/ruby_bridge.rs +78 -0
- data/lib/dry/schema.rb +6 -0
- data/lib/dry/validation/rust/block_keyword_parameters.rb +20 -0
- data/lib/dry/validation/rust/config.rb +74 -0
- data/lib/dry/validation/rust/contract/result.rb +180 -0
- data/lib/dry/validation/rust/contract/values.rb +73 -0
- data/lib/dry/validation/rust/contract.rb +400 -0
- data/lib/dry/validation/rust/errors.rb +14 -0
- data/lib/dry/validation/rust/evaluator.rb +295 -0
- data/lib/dry/validation/rust/failures.rb +57 -0
- data/lib/dry/validation/rust/generated_predicates.rb +14 -0
- data/lib/dry/validation/rust/macros.rb +45 -0
- data/lib/dry/validation/rust/message.rb +41 -0
- data/lib/dry/validation/rust/message_backend.rb +115 -0
- data/lib/dry/validation/rust/message_set.rb +159 -0
- data/lib/dry/validation/rust/native.rb +25 -0
- data/lib/dry/validation/rust/path.rb +65 -0
- data/lib/dry/validation/rust/path_trie.rb +57 -0
- data/lib/dry/validation/rust/result.rb +3 -0
- data/lib/dry/validation/rust/rule.rb +62 -0
- data/lib/dry/validation/rust/schema/dsl.rb +76 -0
- data/lib/dry/validation/rust/schema/field_builder.rb +156 -0
- data/lib/dry/validation/rust/schema/field_definition.rb +99 -0
- data/lib/dry/validation/rust/schema/predicate_block.rb +56 -0
- data/lib/dry/validation/rust/schema/processor_hooks.rb +46 -0
- data/lib/dry/validation/rust/schema/result.rb +67 -0
- data/lib/dry/validation/rust/schema/ruby_type_processor.rb +44 -0
- data/lib/dry/validation/rust/schema.rb +323 -0
- data/lib/dry/validation/rust/values.rb +3 -0
- data/lib/dry/validation/rust/version.rb +10 -0
- data/lib/dry/validation/rust.rb +55 -0
- data/lib/dry/validation.rb +66 -0
- data/lib/dry-schema.rb +3 -0
- data/lib/dry-validation.rb +3 -0
- data/lib/dry_validation_rust.rb +3 -0
- data/predicates.yml +67 -0
- data/rust-toolchain.toml +9 -0
- metadata +260 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "dry_validation_rust_native"
|
|
3
|
+
version = "0.1.0-pre.5"
|
|
4
|
+
edition = "2021"
|
|
5
|
+
rust-version = "1.75"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
publish = false
|
|
8
|
+
|
|
9
|
+
[lib]
|
|
10
|
+
name = "native"
|
|
11
|
+
crate-type = ["cdylib", "rlib"]
|
|
12
|
+
|
|
13
|
+
[dependencies]
|
|
14
|
+
bigdecimal = "0.4"
|
|
15
|
+
chrono = { version = "0.4", default-features = false, features = ["alloc", "std"] }
|
|
16
|
+
magnus = { version = "~0.8.2", default-features = false }
|
|
17
|
+
rb-sys = { version = "~0.9.124", default-features = false, features = ["stable-api-compiled-fallback"] }
|
|
18
|
+
serde = { version = "1", features = ["derive"] }
|
|
19
|
+
serde_json = { version = "1", features = ["unbounded_depth"] }
|
|
20
|
+
|
|
21
|
+
[dev-dependencies]
|
|
22
|
+
criterion = "0.5.1"
|
|
23
|
+
magnus = { version = "~0.8.2", default-features = false, features = ["embed"] }
|
|
24
|
+
|
|
25
|
+
[[bench]]
|
|
26
|
+
name = "plan_compile"
|
|
27
|
+
harness = false
|
|
28
|
+
|
|
29
|
+
[[bench]]
|
|
30
|
+
name = "coercion"
|
|
31
|
+
harness = false
|
|
32
|
+
|
|
33
|
+
[[bench]]
|
|
34
|
+
name = "predicates"
|
|
35
|
+
harness = false
|
|
36
|
+
|
|
37
|
+
[[bench]]
|
|
38
|
+
name = "full_schema"
|
|
39
|
+
harness = false
|
|
40
|
+
|
|
41
|
+
[profile.release]
|
|
42
|
+
codegen-units = 1
|
|
43
|
+
lto = "thin"
|
|
44
|
+
strip = "debuginfo"
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
use criterion::{black_box, Criterion};
|
|
2
|
+
use magnus::{Error, Ruby};
|
|
3
|
+
use native::benchmark::CoercionRuntime;
|
|
4
|
+
|
|
5
|
+
fn bench_coercion(
|
|
6
|
+
criterion: &mut Criterion,
|
|
7
|
+
runtime: &CoercionRuntime,
|
|
8
|
+
ruby: &Ruby,
|
|
9
|
+
group_name: &str,
|
|
10
|
+
kind: &str,
|
|
11
|
+
inputs: &[&str],
|
|
12
|
+
) {
|
|
13
|
+
let mut group = criterion.benchmark_group(group_name);
|
|
14
|
+
for input in inputs {
|
|
15
|
+
group.bench_function(*input, |bencher| {
|
|
16
|
+
bencher.iter(|| {
|
|
17
|
+
runtime
|
|
18
|
+
.coerce(ruby, black_box(kind), black_box(input))
|
|
19
|
+
.expect("benchmark coercion inputs must not raise Ruby errors")
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
group.finish();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
fn run(ruby: &Ruby) -> Result<(), Error> {
|
|
27
|
+
let runtime = CoercionRuntime::new(ruby)?;
|
|
28
|
+
let mut criterion = Criterion::default().configure_from_args();
|
|
29
|
+
|
|
30
|
+
bench_coercion(
|
|
31
|
+
&mut criterion,
|
|
32
|
+
&runtime,
|
|
33
|
+
ruby,
|
|
34
|
+
"integer_coercion",
|
|
35
|
+
"integer",
|
|
36
|
+
&["42", "-99", "1_000", "0xFF"],
|
|
37
|
+
);
|
|
38
|
+
bench_coercion(
|
|
39
|
+
&mut criterion,
|
|
40
|
+
&runtime,
|
|
41
|
+
ruby,
|
|
42
|
+
"float_coercion",
|
|
43
|
+
"float",
|
|
44
|
+
&["3.14", "-2.5e10", "Infinity"],
|
|
45
|
+
);
|
|
46
|
+
bench_coercion(
|
|
47
|
+
&mut criterion,
|
|
48
|
+
&runtime,
|
|
49
|
+
ruby,
|
|
50
|
+
"bool_coercion",
|
|
51
|
+
"bool",
|
|
52
|
+
&["true", "false", "1", "0", "yes", "no"],
|
|
53
|
+
);
|
|
54
|
+
bench_coercion(
|
|
55
|
+
&mut criterion,
|
|
56
|
+
&runtime,
|
|
57
|
+
ruby,
|
|
58
|
+
"date_coercion",
|
|
59
|
+
"date",
|
|
60
|
+
&["2024-01-01", "2024-01-01T12:00:00Z"],
|
|
61
|
+
);
|
|
62
|
+
bench_coercion(
|
|
63
|
+
&mut criterion,
|
|
64
|
+
&runtime,
|
|
65
|
+
ruby,
|
|
66
|
+
"decimal_coercion",
|
|
67
|
+
"decimal",
|
|
68
|
+
&["123.456", "0.0000001"],
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
criterion.final_summary();
|
|
72
|
+
Ok(())
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
fn main() {
|
|
76
|
+
Ruby::init(run).expect("embedded Ruby benchmark setup must succeed");
|
|
77
|
+
}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
use criterion::{black_box, Criterion};
|
|
2
|
+
use magnus::{gc, Error, RHash, Ruby, Value};
|
|
3
|
+
use native::benchmark::FullSchemaRuntime;
|
|
4
|
+
|
|
5
|
+
fn field(name: &str, kind: &str, filled: bool, predicate: Option<(&str, i64)>) -> String {
|
|
6
|
+
let predicates = predicate.map_or_else(
|
|
7
|
+
|| "[]".to_owned(),
|
|
8
|
+
|(name, argument)| format!(r#"[{{"name":"{name}","argument":{argument}}}]"#),
|
|
9
|
+
);
|
|
10
|
+
format!(
|
|
11
|
+
r#"{{"name":"{name}","required":true,"nullable":false,"filled":{filled},"type":"{kind}","member":null,"children":[],"predicates":{predicates}}}"#
|
|
12
|
+
)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
fn plan(fields: Vec<String>) -> String {
|
|
16
|
+
format!(
|
|
17
|
+
r#"{{"engine_version":1,"mode":"params","validate_keys":true,"fields":[{}]}}"#,
|
|
18
|
+
fields.join(",")
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
fn flat_plan(field_count: usize) -> String {
|
|
23
|
+
plan(
|
|
24
|
+
(0..field_count)
|
|
25
|
+
.map(|index| field(&format!("field_{index}"), "integer", false, Some(("gt", 0))))
|
|
26
|
+
.collect(),
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
fn nested_plan(depth: usize) -> String {
|
|
31
|
+
let mut child = field("value", "integer", false, Some(("gt", 0)));
|
|
32
|
+
for index in (0..depth).rev() {
|
|
33
|
+
child = format!(
|
|
34
|
+
r#"{{"name":"level_{index}","required":true,"nullable":false,"filled":false,"type":"hash","member":null,"children":[{child}],"predicates":[]}}"#
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
plan(vec![child])
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
fn array_plan() -> String {
|
|
41
|
+
let member_children = [
|
|
42
|
+
field("id", "integer", false, Some(("gt", 0))),
|
|
43
|
+
field("name", "string", true, None),
|
|
44
|
+
field("age", "integer", false, Some(("gteq", 18))),
|
|
45
|
+
field("active", "bool", false, None),
|
|
46
|
+
field("role", "string", true, None),
|
|
47
|
+
]
|
|
48
|
+
.join(",");
|
|
49
|
+
plan(vec![format!(
|
|
50
|
+
r#"{{"name":"items","required":true,"nullable":false,"filled":false,"type":"array","member":{{"name":null,"required":true,"nullable":false,"filled":false,"type":"hash","member":null,"children":[{member_children}],"predicates":[]}},"children":[],"predicates":[]}}"#
|
|
51
|
+
)])
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
fn flat_payload(ruby: &Ruby, field_count: usize, invalid: bool) -> Result<RHash, Error> {
|
|
55
|
+
let payload = ruby.hash_new_capa(field_count);
|
|
56
|
+
for index in 0..field_count {
|
|
57
|
+
let value = if invalid { "invalid" } else { "1" };
|
|
58
|
+
payload.aset(format!("field_{index}"), value)?;
|
|
59
|
+
}
|
|
60
|
+
Ok(payload)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
fn nested_payload(ruby: &Ruby, depth: usize) -> Result<RHash, Error> {
|
|
64
|
+
let mut payload = ruby.hash_from_iter([("value", "1")]);
|
|
65
|
+
for index in (0..depth).rev() {
|
|
66
|
+
payload = ruby.hash_from_iter([(format!("level_{index}"), payload)]);
|
|
67
|
+
}
|
|
68
|
+
Ok(payload)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
fn array_payload(ruby: &Ruby, invalid: bool) -> Result<RHash, Error> {
|
|
72
|
+
let items = ruby.ary_new_capa(100);
|
|
73
|
+
for index in 0..100 {
|
|
74
|
+
let item = ruby.hash_new_capa(5);
|
|
75
|
+
let invalid_item = invalid && index == 0;
|
|
76
|
+
item.aset("id", if invalid_item { "invalid" } else { "1" })?;
|
|
77
|
+
item.aset("name", if invalid_item { "" } else { "person" })?;
|
|
78
|
+
item.aset("age", if invalid_item { "invalid" } else { "30" })?;
|
|
79
|
+
item.aset("active", "true")?;
|
|
80
|
+
item.aset("role", "member")?;
|
|
81
|
+
items.push(item)?;
|
|
82
|
+
}
|
|
83
|
+
Ok(ruby.hash_from_iter([("items", items)]))
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
fn bench_case(
|
|
87
|
+
criterion: &mut Criterion,
|
|
88
|
+
ruby: &Ruby,
|
|
89
|
+
name: &str,
|
|
90
|
+
plan_json: String,
|
|
91
|
+
inputs: Vec<(RHash, usize)>,
|
|
92
|
+
) -> Result<(), Error> {
|
|
93
|
+
let runtime = FullSchemaRuntime::new(ruby, plan_json)?;
|
|
94
|
+
for (input, expected_errors) in &inputs {
|
|
95
|
+
gc::register_mark_object(*input);
|
|
96
|
+
assert_eq!(
|
|
97
|
+
runtime.error_count(ruby, *input)?,
|
|
98
|
+
*expected_errors,
|
|
99
|
+
"{name} setup"
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
let mut input_index = 0;
|
|
104
|
+
criterion.bench_function(name, |bencher| {
|
|
105
|
+
bencher.iter(|| {
|
|
106
|
+
let input = inputs[input_index % inputs.len()].0;
|
|
107
|
+
input_index += 1;
|
|
108
|
+
runtime
|
|
109
|
+
.call(black_box(input))
|
|
110
|
+
.expect("pre-built benchmark inputs must not raise Ruby errors")
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
Ok(())
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
fn run(ruby: &Ruby) -> Result<(), Error> {
|
|
117
|
+
ruby.eval::<Value>(
|
|
118
|
+
"module Dry; module Validation; module Rust; module Native; class SchemaResult; end; end; end; end; end",
|
|
119
|
+
)?;
|
|
120
|
+
let mut criterion = Criterion::default().configure_from_args();
|
|
121
|
+
bench_case(
|
|
122
|
+
&mut criterion,
|
|
123
|
+
ruby,
|
|
124
|
+
"full_schema/small_form",
|
|
125
|
+
flat_plan(5),
|
|
126
|
+
vec![(flat_payload(ruby, 5, false)?, 0)],
|
|
127
|
+
)?;
|
|
128
|
+
bench_case(
|
|
129
|
+
&mut criterion,
|
|
130
|
+
ruby,
|
|
131
|
+
"full_schema/medium_form",
|
|
132
|
+
flat_plan(25),
|
|
133
|
+
vec![
|
|
134
|
+
(flat_payload(ruby, 25, false)?, 0),
|
|
135
|
+
(flat_payload(ruby, 25, false)?, 0),
|
|
136
|
+
(flat_payload(ruby, 25, false)?, 0),
|
|
137
|
+
(flat_payload(ruby, 25, false)?, 0),
|
|
138
|
+
(flat_payload(ruby, 25, true)?, 25),
|
|
139
|
+
],
|
|
140
|
+
)?;
|
|
141
|
+
bench_case(
|
|
142
|
+
&mut criterion,
|
|
143
|
+
ruby,
|
|
144
|
+
"full_schema/large_form",
|
|
145
|
+
flat_plan(100),
|
|
146
|
+
vec![
|
|
147
|
+
(flat_payload(ruby, 100, false)?, 0),
|
|
148
|
+
(flat_payload(ruby, 100, true)?, 100),
|
|
149
|
+
],
|
|
150
|
+
)?;
|
|
151
|
+
bench_case(
|
|
152
|
+
&mut criterion,
|
|
153
|
+
ruby,
|
|
154
|
+
"full_schema/nested_object",
|
|
155
|
+
nested_plan(10),
|
|
156
|
+
vec![(nested_payload(ruby, 10)?, 0)],
|
|
157
|
+
)?;
|
|
158
|
+
bench_case(
|
|
159
|
+
&mut criterion,
|
|
160
|
+
ruby,
|
|
161
|
+
"full_schema/array_of_objects",
|
|
162
|
+
array_plan(),
|
|
163
|
+
vec![
|
|
164
|
+
(array_payload(ruby, false)?, 0),
|
|
165
|
+
(array_payload(ruby, false)?, 0),
|
|
166
|
+
(array_payload(ruby, false)?, 0),
|
|
167
|
+
(array_payload(ruby, false)?, 0),
|
|
168
|
+
(array_payload(ruby, false)?, 0),
|
|
169
|
+
(array_payload(ruby, false)?, 0),
|
|
170
|
+
(array_payload(ruby, false)?, 0),
|
|
171
|
+
(array_payload(ruby, false)?, 0),
|
|
172
|
+
(array_payload(ruby, false)?, 0),
|
|
173
|
+
(array_payload(ruby, true)?, 3),
|
|
174
|
+
],
|
|
175
|
+
)?;
|
|
176
|
+
bench_case(
|
|
177
|
+
&mut criterion,
|
|
178
|
+
ruby,
|
|
179
|
+
"full_schema/all_invalid",
|
|
180
|
+
flat_plan(20),
|
|
181
|
+
vec![(flat_payload(ruby, 20, true)?, 20)],
|
|
182
|
+
)?;
|
|
183
|
+
criterion.final_summary();
|
|
184
|
+
Ok(())
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
fn main() {
|
|
188
|
+
Ruby::init(run).expect("embedded Ruby benchmark setup must succeed");
|
|
189
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
|
2
|
+
|
|
3
|
+
fn plan_json(field_count: usize) -> String {
|
|
4
|
+
let fields = (0..field_count)
|
|
5
|
+
.map(|index| {
|
|
6
|
+
format!(
|
|
7
|
+
r#"{{"name":"field_{index}","required":true,"nullable":false,"filled":false,"type":"string","member":null,"children":[],"predicates":[{{"name":"min_size","argument":1}}]}}"#
|
|
8
|
+
)
|
|
9
|
+
})
|
|
10
|
+
.collect::<Vec<_>>()
|
|
11
|
+
.join(",");
|
|
12
|
+
|
|
13
|
+
format!(r#"{{"engine_version":1,"mode":"params","validate_keys":true,"fields":[{fields}]}}"#)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
fn bench_plan_compile(c: &mut Criterion, name: &str, field_count: usize) {
|
|
17
|
+
let plan = plan_json(field_count);
|
|
18
|
+
|
|
19
|
+
c.bench_function(name, |bencher| {
|
|
20
|
+
bencher.iter(|| black_box(native::fuzzing::parse_plan(black_box(&plan))));
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
fn small_schema(c: &mut Criterion) {
|
|
25
|
+
bench_plan_compile(c, "small_schema", 5);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
fn medium_schema(c: &mut Criterion) {
|
|
29
|
+
bench_plan_compile(c, "medium_schema", 50);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
fn large_schema(c: &mut Criterion) {
|
|
33
|
+
bench_plan_compile(c, "large_schema", 200);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
criterion_group!(plan_compile, small_schema, medium_schema, large_schema);
|
|
37
|
+
criterion_main!(plan_compile);
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
use criterion::{black_box, Criterion};
|
|
2
|
+
use magnus::{prelude::*, Error, Ruby, Value};
|
|
3
|
+
use native::benchmark::{PredicateCase, PredicateRuntime};
|
|
4
|
+
|
|
5
|
+
fn bench_predicate(
|
|
6
|
+
criterion: &mut Criterion,
|
|
7
|
+
ruby: &Ruby,
|
|
8
|
+
runtime: &PredicateRuntime,
|
|
9
|
+
group_name: &str,
|
|
10
|
+
case_name: &str,
|
|
11
|
+
predicate_case: PredicateCase,
|
|
12
|
+
value: Value,
|
|
13
|
+
) {
|
|
14
|
+
let mut group = criterion.benchmark_group(group_name);
|
|
15
|
+
group.bench_function(case_name, |bencher| {
|
|
16
|
+
bencher.iter(|| {
|
|
17
|
+
runtime
|
|
18
|
+
.evaluate(ruby, predicate_case, black_box(value))
|
|
19
|
+
.expect("benchmark predicate inputs must not raise Ruby errors")
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
group.finish();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
fn run(ruby: &Ruby) -> Result<(), Error> {
|
|
26
|
+
let runtime = PredicateRuntime::new();
|
|
27
|
+
let mut criterion = Criterion::default().configure_from_args();
|
|
28
|
+
let integer = ruby.integer_from_i64(19).as_value();
|
|
29
|
+
let even_integer = ruby.integer_from_i64(20).as_value();
|
|
30
|
+
let float = ruby.float_from_f64(1.5).as_value();
|
|
31
|
+
let string = ruby.str_new("abc").as_value();
|
|
32
|
+
let array = ruby.ary_from_iter([1, 2, 3]).as_value();
|
|
33
|
+
let hash = ruby
|
|
34
|
+
.hash_from_iter([("one", 1), ("two", 2), ("three", 3)])
|
|
35
|
+
.as_value();
|
|
36
|
+
|
|
37
|
+
for (name, predicate_case, value) in [
|
|
38
|
+
("gt_integer", PredicateCase::GtInteger, integer),
|
|
39
|
+
("gteq_integer", PredicateCase::GteqInteger, integer),
|
|
40
|
+
("lt_integer", PredicateCase::LtInteger, integer),
|
|
41
|
+
("lteq_integer", PredicateCase::LteqInteger, integer),
|
|
42
|
+
("gt_float", PredicateCase::GtFloat, float),
|
|
43
|
+
("gteq_float", PredicateCase::GteqFloat, float),
|
|
44
|
+
("lt_float", PredicateCase::LtFloat, float),
|
|
45
|
+
("lteq_float", PredicateCase::LteqFloat, float),
|
|
46
|
+
] {
|
|
47
|
+
bench_predicate(
|
|
48
|
+
&mut criterion,
|
|
49
|
+
ruby,
|
|
50
|
+
&runtime,
|
|
51
|
+
"comparison",
|
|
52
|
+
name,
|
|
53
|
+
predicate_case,
|
|
54
|
+
value,
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
for (name, predicate_case, value) in [
|
|
59
|
+
("size_string", PredicateCase::Size, string),
|
|
60
|
+
("min_size_string", PredicateCase::MinSize, string),
|
|
61
|
+
("max_size_string", PredicateCase::MaxSize, string),
|
|
62
|
+
("size_array", PredicateCase::Size, array),
|
|
63
|
+
("min_size_array", PredicateCase::MinSize, array),
|
|
64
|
+
("max_size_array", PredicateCase::MaxSize, array),
|
|
65
|
+
("size_hash", PredicateCase::Size, hash),
|
|
66
|
+
("min_size_hash", PredicateCase::MinSize, hash),
|
|
67
|
+
("max_size_hash", PredicateCase::MaxSize, hash),
|
|
68
|
+
] {
|
|
69
|
+
bench_predicate(
|
|
70
|
+
&mut criterion,
|
|
71
|
+
ruby,
|
|
72
|
+
&runtime,
|
|
73
|
+
"size",
|
|
74
|
+
name,
|
|
75
|
+
predicate_case,
|
|
76
|
+
value,
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
bench_predicate(
|
|
81
|
+
&mut criterion,
|
|
82
|
+
ruby,
|
|
83
|
+
&runtime,
|
|
84
|
+
"parity",
|
|
85
|
+
"odd_integer",
|
|
86
|
+
PredicateCase::Odd,
|
|
87
|
+
integer,
|
|
88
|
+
);
|
|
89
|
+
bench_predicate(
|
|
90
|
+
&mut criterion,
|
|
91
|
+
ruby,
|
|
92
|
+
&runtime,
|
|
93
|
+
"parity",
|
|
94
|
+
"even_integer",
|
|
95
|
+
PredicateCase::Even,
|
|
96
|
+
even_integer,
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
criterion.final_summary();
|
|
100
|
+
Ok(())
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
fn main() {
|
|
104
|
+
Ruby::init(run).expect("embedded Ruby benchmark setup must succeed");
|
|
105
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'mkmf'
|
|
4
|
+
|
|
5
|
+
begin
|
|
6
|
+
require 'rb_sys/mkmf'
|
|
7
|
+
rescue LoadError
|
|
8
|
+
local_rb_sys = ENV.fetch('RB_SYS_GEM_LIB', nil)
|
|
9
|
+
if local_rb_sys && File.directory?(local_rb_sys)
|
|
10
|
+
$LOAD_PATH.unshift(local_rb_sys)
|
|
11
|
+
require 'rb_sys/mkmf'
|
|
12
|
+
else
|
|
13
|
+
abort 'rb_sys is required to build dry-validation-rust (gem install rb_sys)'
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
create_rust_makefile('dry_validation_rust/native') do |config|
|
|
18
|
+
config.profile = ENV.fetch('RB_SYS_CARGO_PROFILE', 'release').to_sym
|
|
19
|
+
config.ext_dir = '.'
|
|
20
|
+
config.env = {
|
|
21
|
+
'BINDGEN_EXTRA_CLANG_ARGS' => '-include stdbool.h'
|
|
22
|
+
}
|
|
23
|
+
config.extra_rustup_targets = %w[
|
|
24
|
+
aarch64-unknown-linux-gnu
|
|
25
|
+
x86_64-apple-darwin
|
|
26
|
+
aarch64-apple-darwin
|
|
27
|
+
]
|
|
28
|
+
config.use_stable_api_compiled_fallback = true
|
|
29
|
+
end
|