schemurai 2.2.3 → 3.0.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 +4 -4
- data/README.md +81 -7
- data/ext/schemurai_native/Cargo.lock +99 -0
- data/ext/schemurai_native/Cargo.toml +21 -0
- data/ext/schemurai_native/build.rs +35 -0
- data/ext/schemurai_native/extconf.rb +63 -0
- data/ext/schemurai_native/glue.c +780 -0
- data/ext/schemurai_native/protocol.def +63 -0
- data/ext/schemurai_native/protocol.h +10 -0
- data/ext/schemurai_native/src/budget.rs +101 -0
- data/ext/schemurai_native/src/content.rs +574 -0
- data/ext/schemurai_native/src/diagnostics.rs +1135 -0
- data/ext/schemurai_native/src/enumeration.rs +154 -0
- data/ext/schemurai_native/src/evaluation.rs +219 -0
- data/ext/schemurai_native/src/format.rs +357 -0
- data/ext/schemurai_native/src/graph.rs +50 -0
- data/ext/schemurai_native/src/instance_graph.rs +84 -0
- data/ext/schemurai_native/src/lib.rs +3139 -0
- data/ext/schemurai_native/src/memo.rs +1149 -0
- data/ext/schemurai_native/src/memo_scope.rs +240 -0
- data/ext/schemurai_native/src/number.rs +1054 -0
- data/ext/schemurai_native/src/pattern.rs +431 -0
- data/ext/schemurai_native/src/scope.rs +420 -0
- data/ext/schemurai_native/src/structural.rs +86 -0
- data/ext/schemurai_native/src/tracking.rs +687 -0
- data/lib/schemurai/backend.rb +3 -1
- data/lib/schemurai/evaluator.rb +45 -3
- data/lib/schemurai/limit_budget.rb +78 -0
- data/lib/schemurai/limit_exceeded.rb +18 -0
- data/lib/schemurai/limited_evaluator.rb +100 -0
- data/lib/schemurai/native/diagnostics.rb +52 -0
- data/lib/schemurai/native/evaluator.rb +59 -0
- data/lib/schemurai/schema_domain.rb +12 -7
- data/lib/schemurai/schema_graph.rb +10 -1
- data/lib/schemurai/unique_items.rb +2 -0
- data/lib/schemurai/version.rb +1 -1
- data/lib/schemurai/vm/compiler.rb +7 -3
- data/lib/schemurai/vm/evaluator.rb +50 -3
- data/lib/schemurai/vm/limited_evaluator.rb +97 -0
- data/lib/schemurai.rb +81 -33
- data/sig/schemurai.rbs +21 -13
- metadata +36 -6
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/* Shared C/Rust/Ruby native protocol. Keep wire values stable. */
|
|
2
|
+
SN_OPCODE(BOOLEAN, boolean, 0)
|
|
3
|
+
SN_OPCODE(TYPE_NULL, type_null, 1)
|
|
4
|
+
SN_OPCODE(TYPE_BOOLEAN, type_boolean, 2)
|
|
5
|
+
SN_OPCODE(TYPE_OBJECT, type_object, 3)
|
|
6
|
+
SN_OPCODE(TYPE_ARRAY, type_array, 4)
|
|
7
|
+
SN_OPCODE(TYPE_NUMBER, type_number, 5)
|
|
8
|
+
SN_OPCODE(TYPE_INTEGER, type_integer, 6)
|
|
9
|
+
SN_OPCODE(TYPE_STRING, type_string, 7)
|
|
10
|
+
SN_OPCODE(TYPES, types, 8)
|
|
11
|
+
SN_OPCODE(CONST, const, 9)
|
|
12
|
+
SN_OPCODE(ENUM, enum, 10)
|
|
13
|
+
SN_OPCODE(ALL_OF, allOf, 11)
|
|
14
|
+
SN_OPCODE(ANY_OF, anyOf, 12)
|
|
15
|
+
SN_OPCODE(ONE_OF, oneOf, 13)
|
|
16
|
+
SN_OPCODE(NOT, not, 14)
|
|
17
|
+
SN_OPCODE(CONDITIONAL, conditional, 15)
|
|
18
|
+
SN_OPCODE(NUMBER, number, 16)
|
|
19
|
+
SN_OPCODE(TYPED_NUMBER, typed_number, 17)
|
|
20
|
+
SN_OPCODE(TYPED_INTEGER, typed_integer, 18)
|
|
21
|
+
SN_OPCODE(STRING, string, 19)
|
|
22
|
+
SN_OPCODE(TYPED_STRING, typed_string, 20)
|
|
23
|
+
SN_OPCODE(ARRAY, array, 21)
|
|
24
|
+
SN_OPCODE(TYPED_ARRAY, typed_array, 22)
|
|
25
|
+
SN_OPCODE(OBJECT, object, 23)
|
|
26
|
+
SN_OPCODE(TYPED_OBJECT, typed_object, 24)
|
|
27
|
+
SN_OPCODE(REF, ref, 25)
|
|
28
|
+
SN_OPCODE(RECURSIVE_REF, recursive_ref, 26)
|
|
29
|
+
SN_OPCODE(DYNAMIC_REF, dynamic_ref, 27)
|
|
30
|
+
|
|
31
|
+
/* Match VM::TypeRules and VM::NumberRules bit masks. */
|
|
32
|
+
SN_CONSTANT(TYPE_NULL, 1)
|
|
33
|
+
SN_CONSTANT(TYPE_BOOLEAN, 2)
|
|
34
|
+
SN_CONSTANT(TYPE_OBJECT, 4)
|
|
35
|
+
SN_CONSTANT(TYPE_ARRAY, 8)
|
|
36
|
+
SN_CONSTANT(TYPE_NUMBER, 16)
|
|
37
|
+
SN_CONSTANT(TYPE_INTEGER, 32)
|
|
38
|
+
SN_CONSTANT(TYPE_STRING, 64)
|
|
39
|
+
SN_CONSTANT(TYPE_INTEGRAL_NUMBER, 48)
|
|
40
|
+
SN_CONSTANT(TYPE_UNSUPPORTED, 128)
|
|
41
|
+
SN_CONSTANT(MAXIMUM, 1)
|
|
42
|
+
SN_CONSTANT(MINIMUM, 2)
|
|
43
|
+
SN_CONSTANT(EXCLUSIVE_MAXIMUM, 4)
|
|
44
|
+
SN_CONSTANT(EXCLUSIVE_MINIMUM, 8)
|
|
45
|
+
SN_CONSTANT(MULTIPLE_OF, 16)
|
|
46
|
+
SN_CONSTANT(TRACKS_EVALUATION, 1)
|
|
47
|
+
SN_CONSTANT(TRACKS_DYNAMIC_SCOPE, 2)
|
|
48
|
+
|
|
49
|
+
/* Adapter results; comparison/packing reserves 3 beyond ordinary -2..2. */
|
|
50
|
+
SN_CONSTANT(VERDICT_INVALID, 0)
|
|
51
|
+
SN_CONSTANT(VERDICT_VALID, 1)
|
|
52
|
+
SN_CONSTANT(VERDICT_UNSUPPORTED, 2)
|
|
53
|
+
SN_CONSTANT(ADAPTER_UNSUPPORTED, 3)
|
|
54
|
+
SN_CONSTANT(STATUS_PANIC, -1)
|
|
55
|
+
SN_CONSTANT(STATUS_EXCEPTION, -2)
|
|
56
|
+
SN_CONSTANT(OPCODE_UNKNOWN, -1)
|
|
57
|
+
SN_CONSTANT(SMALL_HASH_ORDINARY, 16)
|
|
58
|
+
SN_CONSTANT(SMALL_HASH_COUNT_MASK, 15)
|
|
59
|
+
SN_CONSTANT(SMALL_HASH_TOO_LARGE, -2)
|
|
60
|
+
SN_CONSTANT(ENCODING_OTHER, 0)
|
|
61
|
+
SN_CONSTANT(ENCODING_UTF8, 1)
|
|
62
|
+
SN_CONSTANT(ENCODING_ASCII, 2)
|
|
63
|
+
SN_CONSTANT(ENCODING_SEVEN_BIT, 3)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#ifndef SCHEMURAI_PROTOCOL_H
|
|
2
|
+
#define SCHEMURAI_PROTOCOL_H
|
|
3
|
+
enum {
|
|
4
|
+
#define SN_OPCODE(name, symbol, value) SN_OP_##name = value,
|
|
5
|
+
#define SN_CONSTANT(name, value) SN_##name = value,
|
|
6
|
+
#include "protocol.def"
|
|
7
|
+
#undef SN_OPCODE
|
|
8
|
+
#undef SN_CONSTANT
|
|
9
|
+
};
|
|
10
|
+
#endif
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
//! Invocation-local native limits. Exhaustion is terminal, not VM delegation.
|
|
2
|
+
use std::cell::Cell;
|
|
3
|
+
use std::time::{Duration, Instant};
|
|
4
|
+
|
|
5
|
+
#[repr(C)]
|
|
6
|
+
#[derive(Clone, Copy, Default)]
|
|
7
|
+
pub struct Limits {
|
|
8
|
+
pub max_errors: usize,
|
|
9
|
+
pub enabled: u32,
|
|
10
|
+
pub timeout: f64,
|
|
11
|
+
}
|
|
12
|
+
#[repr(C)]
|
|
13
|
+
#[derive(Default)]
|
|
14
|
+
pub struct Outcome {
|
|
15
|
+
pub kind: u32,
|
|
16
|
+
pub attempted: usize,
|
|
17
|
+
}
|
|
18
|
+
#[derive(Default)]
|
|
19
|
+
pub(super) struct Budget {
|
|
20
|
+
pub limits: Limits,
|
|
21
|
+
pub hit: Cell<(u32, usize)>,
|
|
22
|
+
deadline: Option<Instant>,
|
|
23
|
+
checks: Cell<usize>,
|
|
24
|
+
}
|
|
25
|
+
impl Budget {
|
|
26
|
+
pub fn new(limits: Limits) -> Self {
|
|
27
|
+
Self {
|
|
28
|
+
limits,
|
|
29
|
+
deadline: if limits.enabled & 2 != 0 {
|
|
30
|
+
Duration::try_from_secs_f64(limits.timeout.max(0.0))
|
|
31
|
+
.ok()
|
|
32
|
+
.and_then(|duration| Instant::now().checked_add(duration))
|
|
33
|
+
} else {
|
|
34
|
+
None
|
|
35
|
+
},
|
|
36
|
+
..Self::default()
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
pub fn timed(&self) -> bool {
|
|
40
|
+
self.limits.enabled & 2 != 0
|
|
41
|
+
}
|
|
42
|
+
pub fn check_deadline(&self) -> bool {
|
|
43
|
+
if self.hit.get().0 != 0 {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
if self
|
|
47
|
+
.deadline
|
|
48
|
+
.is_some_and(|deadline| Instant::now() >= deadline)
|
|
49
|
+
{
|
|
50
|
+
self.hit.set((2, 0));
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
true
|
|
54
|
+
}
|
|
55
|
+
pub fn checkpoint(&self) -> bool {
|
|
56
|
+
if !self.timed() {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
let checks = self.checks.get().wrapping_add(1);
|
|
60
|
+
self.checks.set(checks);
|
|
61
|
+
if checks & 255 == 0 {
|
|
62
|
+
self.check_deadline()
|
|
63
|
+
} else {
|
|
64
|
+
self.hit.get().0 == 0
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
#[cfg(test)]
|
|
70
|
+
mod tests {
|
|
71
|
+
use super::*;
|
|
72
|
+
|
|
73
|
+
#[test]
|
|
74
|
+
fn deadline_is_sampled_and_exhaustion_is_sticky() {
|
|
75
|
+
let mut budget = Budget::new(Limits {
|
|
76
|
+
timeout: 10.0,
|
|
77
|
+
enabled: 2,
|
|
78
|
+
..Limits::default()
|
|
79
|
+
});
|
|
80
|
+
assert!(budget.check_deadline());
|
|
81
|
+
budget.deadline = Some(Instant::now() - Duration::from_secs(1));
|
|
82
|
+
for _ in 0..255 {
|
|
83
|
+
assert!(budget.checkpoint());
|
|
84
|
+
}
|
|
85
|
+
assert!(!budget.checkpoint());
|
|
86
|
+
assert_eq!(budget.hit.get(), (2, 0));
|
|
87
|
+
assert!(!budget.checkpoint());
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
#[test]
|
|
91
|
+
fn huge_finite_deadlines_do_not_panic() {
|
|
92
|
+
assert!(
|
|
93
|
+
Budget::new(Limits {
|
|
94
|
+
timeout: f64::MAX,
|
|
95
|
+
enabled: 2,
|
|
96
|
+
..Limits::default()
|
|
97
|
+
})
|
|
98
|
+
.check_deadline()
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
}
|