schemurai 2.2.2 → 2.3.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 163dbc9593611cce4f28183766bd5e17a08387a54883c17a502a198eb010ad36
4
- data.tar.gz: aa3d5f90db227194179023b31043cf36b4597e4af5f1e2209b2846e9c36f9044
3
+ metadata.gz: 181bce310181bba515fd0b38021092300deda955ce8ef5cefb6b9e077a51995b
4
+ data.tar.gz: 506c85192a973967b9787637fb96c24d564ebf83bba7e02124f8fccf3de9de55
5
5
  SHA512:
6
- metadata.gz: 5f5ba215dde91e1bf364ff6ebbbebb7ea40b284e3908cfcb578d48aad2174c34e5cf6d9fd121947bb54f8b2cf0fad626e629ed94d6b4a52ab41ba84ad7dfbc55
7
- data.tar.gz: 4efa97250aad095e414eb230310ae580bbd029b834aa11322cab8da0b19df7a1fb6703240ee0439fd4abe788fcfa47c918ac92806bef174d38d0110bb35cc934
6
+ metadata.gz: b6b8663cd944bd3c439892a0ebbbaea1fbce229eabe208094e89f1999cc102b60a6b04a2626caafa2dc480a18e76c4c76aca75433f2509d84ab75f1766e14e0c
7
+ data.tar.gz: 4a80f08e3f35eb1edfab8d106d2967c4fdc686741b5e731f4bc7dc5c5946095a6e69272cc8257ad1d762746b78df73e932a9470a0815969c25ff54274e62631b
data/README.md CHANGED
@@ -5,13 +5,18 @@
5
5
  [![lint / rubocop](https://github.com/oakcask/schemurai/actions/workflows/lint--rubocop.yaml/badge.svg)](https://github.com/oakcask/schemurai/actions/workflows/lint--rubocop.yaml)
6
6
  [![lint / rbs](https://github.com/oakcask/schemurai/actions/workflows/lint--rbs.yaml/badge.svg)](https://github.com/oakcask/schemurai/actions/workflows/lint--rbs.yaml)
7
7
 
8
- A small, light-weight-dependency JSON Schema validator for Ruby supporting Draft 7,
9
- Draft 2019-09, and Draft 2020-12. It covers the required cases in the official
10
- JSON-Schema-Test-Suite, as well as the applicable optional tests for numeric
8
+ A JSON Schema validator for Ruby with reusable compiled schemas and detailed
9
+ validation errors. It supports Draft 7, Draft 2019-09, and Draft 2020-12 and
10
+ covers the required cases in the official JSON-Schema-Test-Suite, as well as
11
+ the applicable optional tests for numeric
11
12
  precision, ECMA-262 regular expressions, content validation, anchors, and dynamic
12
13
  references. The dialect is selected from the schema's `$schema` URI; schemas that
13
14
  omit `$schema` use Draft 7 for compatibility.
14
15
 
16
+ Choose the default Ruby evaluator, the Ruby VM backend, or the optional
17
+ experimental Rust native backend. See [backend selection](#backend-selection)
18
+ for setup and requirements.
19
+
15
20
  Schemurai ships RBS declarations for its public API in `sig/schemurai.rbs`.
16
21
 
17
22
  ```ruby
@@ -218,6 +223,12 @@ validator is retained.
218
223
  `Schemurai.backend`, `SchemaRegistry#backend`, and `Validator#backend` expose
219
224
  the actual backend. Pass `backend: :ruby` to force the Ruby oracle or
220
225
  `backend: :vm` to ahead-of-time compile schemas for the validator virtual machine.
226
+ Pass `backend: :native` to use the experimental Rust VM extension. Building the
227
+ native extension requires a C toolchain, Ruby development headers, and Rust
228
+ 1.93 or newer. If cargo is absent, gem installation skips the optional native
229
+ extension and Ruby/VM remain available; explicitly selecting `:native` then
230
+ raises `LoadError`. Native execution borrows Ruby values directly; its current coverage and
231
+ remaining VM delegation are documented below.
221
232
  Schema graph construction remains shared Ruby infrastructure. Environment-based selection
222
233
  is documented in [`docs/backend-selection.md`](docs/backend-selection.md).
223
234
 
@@ -0,0 +1,99 @@
1
+ # This file is automatically @generated by Cargo.
2
+ # It is not intended for manual editing.
3
+ version = 4
4
+
5
+ [[package]]
6
+ name = "aho-corasick"
7
+ version = "1.1.5"
8
+ source = "registry+https://github.com/rust-lang/crates.io-index"
9
+ checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba"
10
+ dependencies = [
11
+ "memchr",
12
+ ]
13
+
14
+ [[package]]
15
+ name = "base64-simd"
16
+ version = "0.8.0"
17
+ source = "registry+https://github.com/rust-lang/crates.io-index"
18
+ checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195"
19
+ dependencies = [
20
+ "outref",
21
+ "vsimd",
22
+ ]
23
+
24
+ [[package]]
25
+ name = "base64-turbo"
26
+ version = "0.5.0"
27
+ source = "registry+https://github.com/rust-lang/crates.io-index"
28
+ checksum = "865a269d8d8fc97f16122eae7a74e7e9dffa2df68d5f067cb1f494e9984528db"
29
+ dependencies = [
30
+ "cpufeatures",
31
+ ]
32
+
33
+ [[package]]
34
+ name = "cpufeatures"
35
+ version = "0.3.1"
36
+ source = "registry+https://github.com/rust-lang/crates.io-index"
37
+ checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566"
38
+ dependencies = [
39
+ "libc",
40
+ ]
41
+
42
+ [[package]]
43
+ name = "libc"
44
+ version = "0.2.190"
45
+ source = "registry+https://github.com/rust-lang/crates.io-index"
46
+ checksum = "ce5d3ddc6d3fa000eb1536d85e147bfe31aacaba692ed6a876f95cb7c855be78"
47
+
48
+ [[package]]
49
+ name = "memchr"
50
+ version = "2.8.3"
51
+ source = "registry+https://github.com/rust-lang/crates.io-index"
52
+ checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
53
+
54
+ [[package]]
55
+ name = "outref"
56
+ version = "0.5.2"
57
+ source = "registry+https://github.com/rust-lang/crates.io-index"
58
+ checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e"
59
+
60
+ [[package]]
61
+ name = "regex-automata"
62
+ version = "0.4.18"
63
+ source = "registry+https://github.com/rust-lang/crates.io-index"
64
+ checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2"
65
+ dependencies = [
66
+ "aho-corasick",
67
+ "memchr",
68
+ "regex-syntax",
69
+ ]
70
+
71
+ [[package]]
72
+ name = "regex-syntax"
73
+ version = "0.8.11"
74
+ source = "registry+https://github.com/rust-lang/crates.io-index"
75
+ checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
76
+
77
+ [[package]]
78
+ name = "ryu"
79
+ version = "1.0.23"
80
+ source = "registry+https://github.com/rust-lang/crates.io-index"
81
+ checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
82
+
83
+ [[package]]
84
+ name = "schemurai-native"
85
+ version = "2.3.0"
86
+ dependencies = [
87
+ "base64-simd",
88
+ "base64-turbo",
89
+ "memchr",
90
+ "regex-automata",
91
+ "regex-syntax",
92
+ "ryu",
93
+ ]
94
+
95
+ [[package]]
96
+ name = "vsimd"
97
+ version = "0.8.0"
98
+ source = "registry+https://github.com/rust-lang/crates.io-index"
99
+ checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64"
@@ -0,0 +1,21 @@
1
+ [package]
2
+ name = "schemurai-native"
3
+ version = "2.3.0"
4
+ edition = "2024"
5
+ rust-version = "1.93"
6
+ publish = false
7
+
8
+ [dependencies]
9
+ base64-simd = "0.8.0"
10
+ base64-turbo = "0.5.0"
11
+ memchr = "2.8.3"
12
+ regex-automata = "0.4.18"
13
+ regex-syntax = "0.8.11"
14
+ ryu = "1.0.23"
15
+
16
+ [lib]
17
+ crate-type = ["staticlib"]
18
+
19
+ [profile.release]
20
+ lto = true
21
+ codegen-units = 1
@@ -0,0 +1,35 @@
1
+ use std::{env, fs, path::PathBuf};
2
+
3
+ fn main() {
4
+ println!("cargo:rerun-if-changed=protocol.def");
5
+ let definitions = fs::read_to_string("protocol.def").expect("read native protocol");
6
+ let mut output = String::new();
7
+ for line in definitions.lines() {
8
+ let (fields, opcode) = if let Some(fields) = line.strip_prefix("SN_OPCODE(") {
9
+ (fields, true)
10
+ } else if let Some(fields) = line.strip_prefix("SN_CONSTANT(") {
11
+ (fields, false)
12
+ } else {
13
+ continue;
14
+ };
15
+ let fields: Vec<_> = fields
16
+ .strip_suffix(')')
17
+ .expect("protocol closing parenthesis")
18
+ .split(',')
19
+ .map(str::trim)
20
+ .collect();
21
+ assert_eq!(fields.len(), if opcode { 3 } else { 2 });
22
+ let name = fields[0];
23
+ assert!(
24
+ name.bytes()
25
+ .all(|c| c.is_ascii_uppercase() || c.is_ascii_digit() || c == b'_')
26
+ );
27
+ let value: i32 = fields[if opcode { 2 } else { 1 }]
28
+ .parse()
29
+ .expect("protocol integer value");
30
+ let prefix = if opcode { "OP_" } else { "" };
31
+ output.push_str(&format!("pub const {prefix}{name}: i32 = {value};\n"));
32
+ }
33
+ let directory = PathBuf::from(env::var_os("OUT_DIR").expect("Cargo output directory"));
34
+ fs::write(directory.join("protocol.rs"), output).expect("write native protocol constants");
35
+ }
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mkmf"
4
+
5
+ unless find_executable("cargo")
6
+ warn "cargo was not found; skipping the optional native backend (Ruby and VM remain available)"
7
+ File.write("Makefile", dummy_makefile(".").join)
8
+ exit
9
+ end
10
+ unless enable_config("portable-hash-walk", false)
11
+ if have_func("rb_hash_stlike_foreach", ["ruby.h", "ruby/st.h"])
12
+ # CRuby 3.4/4.0 identity Hashes always use ST storage. Check the private
13
+ # storage flag against a fresh interpreter before enabling the read hint.
14
+ ar_proof = !CROSS_COMPILING && try_run(<<~C)
15
+ #include <ruby.h>
16
+ #include <ruby/version.h>
17
+ #if (RUBY_API_VERSION_MAJOR == 3 && RUBY_API_VERSION_MINOR == 4) || \
18
+ (RUBY_API_VERSION_MAJOR == 4 && RUBY_API_VERSION_MINOR == 0)
19
+ int main(int argc, char **argv) {
20
+ ruby_sysinit(&argc, &argv);
21
+ RUBY_INIT_STACK;
22
+ ruby_init();
23
+ int status = 0;
24
+ ID identity = rb_intern_const("compare_by_identity");
25
+ for (int n = 0; n <= 8; n++) {
26
+ VALUE h = rb_hash_new();
27
+ VALUE id = rb_funcall(rb_hash_new(), identity, 0);
28
+ for (int i = 0; i < n; i++) {
29
+ rb_hash_aset(h, INT2FIX(i), INT2FIX(i));
30
+ rb_hash_aset(id, INT2FIX(i), INT2FIX(i));
31
+ }
32
+ VALUE hashes[] = {h, rb_obj_freeze(rb_hash_dup(h)),
33
+ rb_funcall(rb_hash_dup(h), identity, 0), id};
34
+ for (int i = 0; i < 4; i++) {
35
+ int st = RB_FL_TEST_RAW(hashes[i], RUBY_FL_USER3) != 0;
36
+ if (st != (i >= 2)) status = 1;
37
+ }
38
+ RB_GC_GUARD(h);
39
+ RB_GC_GUARD(id);
40
+ }
41
+ return ruby_cleanup(status);
42
+ }
43
+ #else
44
+ int main(void) { return 1; }
45
+ #endif
46
+ C
47
+ $defs << "-DSCHEMURAI_AR_HASH_PROOF" if ar_proof # rubocop:disable Style/GlobalVars -- mkmf build configuration.
48
+ end
49
+ end
50
+ $LOCAL_LIBS << " $(srcdir)/target/release/libschemurai_native.a" # rubocop:disable Style/GlobalVars -- mkmf build configuration.
51
+ $LOCAL_LIBS << " -lpthread -ldl -lm" unless /mswin|mingw/ =~ RUBY_PLATFORM # rubocop:disable Style/GlobalVars -- mkmf build configuration.
52
+ create_makefile("schemurai_native")
53
+ File.open("Makefile", "a") do |file|
54
+ file.puts <<~MAKE
55
+
56
+ $(TARGET_SO): $(srcdir)/target/release/libschemurai_native.a
57
+
58
+ glue.o: $(srcdir)/protocol.h $(srcdir)/protocol.def
59
+
60
+ $(srcdir)/target/release/libschemurai_native.a: $(srcdir)/Cargo.toml $(srcdir)/Cargo.lock $(srcdir)/build.rs $(srcdir)/protocol.def $(wildcard $(srcdir)/src/*.rs)
61
+ \tcargo build --manifest-path $(srcdir)/Cargo.toml --release --locked
62
+ MAKE
63
+ end