schemurai 3.0.1 → 3.0.2
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 +6 -4
- data/ext/schemurai_native/Cargo.lock +48 -1
- data/ext/schemurai_native/Cargo.toml +3 -1
- data/ext/schemurai_native/extconf.rb +1 -1
- data/ext/schemurai_native/glue.c +1679 -62
- data/ext/schemurai_native/protocol.def +45 -0
- data/ext/schemurai_native/src/budget.rs +49 -0
- data/ext/schemurai_native/src/container.rs +460 -0
- data/ext/schemurai_native/src/content.rs +56 -27
- data/ext/schemurai_native/src/diagnostics/array.rs +392 -0
- data/ext/schemurai_native/src/diagnostics/object.rs +218 -0
- data/ext/schemurai_native/src/diagnostics.rs +1087 -307
- data/ext/schemurai_native/src/enumeration.rs +6 -1
- data/ext/schemurai_native/src/evaluation.rs +49 -20
- data/ext/schemurai_native/src/format.rs +8 -6
- data/ext/schemurai_native/src/graph.rs +37 -0
- data/ext/schemurai_native/src/instance_graph.rs +90 -0
- data/ext/schemurai_native/src/lib.rs +910 -237
- data/ext/schemurai_native/src/memo.rs +11 -38
- data/ext/schemurai_native/src/number/arbitrary.rs +154 -0
- data/ext/schemurai_native/src/number.rs +250 -59
- data/ext/schemurai_native/src/pattern.rs +113 -101
- data/ext/schemurai_native/src/pointer.rs +97 -0
- data/ext/schemurai_native/src/runtime/properties.rs +162 -0
- data/ext/schemurai_native/src/runtime/reports.rs +266 -0
- data/ext/schemurai_native/src/runtime/scopes.rs +430 -0
- data/ext/schemurai_native/src/runtime.rs +1020 -0
- data/ext/schemurai_native/src/scope.rs +60 -16
- data/ext/schemurai_native/src/string.rs +68 -0
- data/ext/schemurai_native/src/tracking.rs +244 -174
- data/lib/schemurai/container_checks/array_diagnostics.rb +119 -0
- data/lib/schemurai/container_checks/object_diagnostics.rb +152 -0
- data/lib/schemurai/container_checks.rb +534 -0
- data/lib/schemurai/decimal.rb +11 -0
- data/lib/schemurai/dialect.rb +0 -12
- data/lib/schemurai/ecma_regexp.rb +46 -0
- data/lib/schemurai/evaluation_pool.rb +66 -0
- data/lib/schemurai/evaluator.rb +9 -48
- data/lib/schemurai/json_pointer.rb +11 -0
- data/lib/schemurai/native/diagnostics.rb +4 -3
- data/lib/schemurai/native/evaluator.rb +38 -10
- data/lib/schemurai/native/null_numeric.rb +23 -0
- data/lib/schemurai/number_checks.rb +128 -0
- data/lib/schemurai/string_checks.rb +166 -0
- data/lib/schemurai/type_checks.rb +59 -0
- data/lib/schemurai/value_equality.rb +72 -0
- data/lib/schemurai/version.rb +1 -1
- data/lib/schemurai/vm/compiler.rb +18 -26
- data/lib/schemurai/vm/evaluator.rb +87 -545
- data/lib/schemurai/vm/limited_evaluator.rb +7 -22
- metadata +24 -2
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
//! Object paths and opaque evaluated-property sets for C-owned report collectors.
|
|
2
|
+
use super::*;
|
|
3
|
+
|
|
4
|
+
/// # Safety
|
|
5
|
+
/// Report and segments are live and rooted by C. Keyword is a library UTF-8
|
|
6
|
+
/// segment; flags omit the instance (1), include a schema name (2), and export
|
|
7
|
+
/// child annotations (4). C owns the returned seed.
|
|
8
|
+
#[unsafe(no_mangle)]
|
|
9
|
+
pub unsafe extern "C" fn sn_object_report_child(
|
|
10
|
+
report: *const Report,
|
|
11
|
+
instance: Value,
|
|
12
|
+
keyword: *const u8,
|
|
13
|
+
len: usize,
|
|
14
|
+
child: Value,
|
|
15
|
+
flags: i32,
|
|
16
|
+
) -> *mut Report {
|
|
17
|
+
let mut seed = unsafe { &*report }.continuation(flags & 4 != 0);
|
|
18
|
+
if !seed.silent {
|
|
19
|
+
if flags & 1 == 0 {
|
|
20
|
+
seed.instance_path.text.push('/');
|
|
21
|
+
seed.instance_path
|
|
22
|
+
.names
|
|
23
|
+
.push((seed.instance_path.text.len(), instance));
|
|
24
|
+
}
|
|
25
|
+
seed.schema_path.push_str("/");
|
|
26
|
+
seed.schema_path.push_str(
|
|
27
|
+
std::str::from_utf8(unsafe { byte_view(keyword, len) }).expect("object keyword"),
|
|
28
|
+
);
|
|
29
|
+
if flags & 2 != 0 {
|
|
30
|
+
seed.schema_path.text.push('/');
|
|
31
|
+
seed.schema_path
|
|
32
|
+
.names
|
|
33
|
+
.push((seed.schema_path.text.len(), child));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
Box::into_raw(Box::new(seed))
|
|
37
|
+
}
|
|
38
|
+
/// # Safety
|
|
39
|
+
/// Report and engine are live and rooted, node owns an Object instruction, and
|
|
40
|
+
/// frame is retained by C. Keyword is a library object diagnostic ID.
|
|
41
|
+
#[unsafe(no_mangle)]
|
|
42
|
+
pub unsafe extern "C" fn sn_object_report_error(
|
|
43
|
+
report: *const Report,
|
|
44
|
+
engine: *const Engine,
|
|
45
|
+
node: usize,
|
|
46
|
+
instance: Value,
|
|
47
|
+
keyword: i32,
|
|
48
|
+
frame: Value,
|
|
49
|
+
) -> *mut Report {
|
|
50
|
+
let keyword = match keyword {
|
|
51
|
+
0 => "type",
|
|
52
|
+
1 => "maxProperties",
|
|
53
|
+
2 => "minProperties",
|
|
54
|
+
3 => "required",
|
|
55
|
+
4 => "dependencies",
|
|
56
|
+
5 => "dependentRequired",
|
|
57
|
+
_ => unreachable!(),
|
|
58
|
+
};
|
|
59
|
+
Box::into_raw(Box::new(unsafe { &*report }.container_error(
|
|
60
|
+
unsafe { &*engine },
|
|
61
|
+
node,
|
|
62
|
+
instance,
|
|
63
|
+
keyword,
|
|
64
|
+
frame,
|
|
65
|
+
true,
|
|
66
|
+
)))
|
|
67
|
+
}
|
|
68
|
+
/// # Safety
|
|
69
|
+
/// Report is exclusively borrowed and locations is readable. C roots all Ruby
|
|
70
|
+
/// handles before entering this mutation and the collector guards marking.
|
|
71
|
+
#[unsafe(no_mangle)]
|
|
72
|
+
pub unsafe extern "C" fn sn_container_report_finish(
|
|
73
|
+
report: *mut Report,
|
|
74
|
+
valid: i32,
|
|
75
|
+
locations: *const tracking::RuntimeLocations,
|
|
76
|
+
) {
|
|
77
|
+
let report = unsafe { &mut *report };
|
|
78
|
+
report.container_prior = None;
|
|
79
|
+
let mut evaluation = Tracked::new(if valid != 0 { Valid } else { Invalid });
|
|
80
|
+
if valid != 0 {
|
|
81
|
+
let locations = unsafe { *locations };
|
|
82
|
+
if locations.buffer != unsafe { sn_nil() } {
|
|
83
|
+
evaluation.set_runtime(locations);
|
|
84
|
+
}
|
|
85
|
+
} else {
|
|
86
|
+
report.failed = true;
|
|
87
|
+
}
|
|
88
|
+
report.evaluation = Some(evaluation);
|
|
89
|
+
}
|
|
90
|
+
/// # Safety
|
|
91
|
+
/// Report/engine are live and rooted. C owns the returned immutable snapshot,
|
|
92
|
+
/// marks it while using it and frees it with sn_property_locations_free.
|
|
93
|
+
#[unsafe(no_mangle)]
|
|
94
|
+
pub unsafe extern "C" fn sn_object_report_properties(
|
|
95
|
+
report: *const Report,
|
|
96
|
+
engine: *const Engine,
|
|
97
|
+
prior: i32,
|
|
98
|
+
) -> *mut tracking::PropertyLocations {
|
|
99
|
+
let report = unsafe { &*report };
|
|
100
|
+
let evaluation = if prior != 0 {
|
|
101
|
+
&report.container_prior
|
|
102
|
+
} else {
|
|
103
|
+
&report.evaluation
|
|
104
|
+
};
|
|
105
|
+
let locations = evaluation.as_ref().map_or_else(
|
|
106
|
+
|| tracking::PropertyLocations {
|
|
107
|
+
set: None,
|
|
108
|
+
keys: vec![],
|
|
109
|
+
},
|
|
110
|
+
|evaluation| tracking::PropertyLocations::new(unsafe { &*engine }, evaluation),
|
|
111
|
+
);
|
|
112
|
+
Box::into_raw(Box::new(locations))
|
|
113
|
+
}
|
|
114
|
+
/// # Safety
|
|
115
|
+
/// Locations is a live immutable C-owned snapshot and count is writable.
|
|
116
|
+
#[unsafe(no_mangle)]
|
|
117
|
+
pub unsafe extern "C" fn sn_property_locations_set(
|
|
118
|
+
locations: *const tracking::PropertyLocations,
|
|
119
|
+
count: *mut usize,
|
|
120
|
+
) -> Value {
|
|
121
|
+
let locations = unsafe { &*locations };
|
|
122
|
+
unsafe {
|
|
123
|
+
*count = locations.keys.len();
|
|
124
|
+
}
|
|
125
|
+
locations.set.unwrap_or_else(|| unsafe { sn_nil() })
|
|
126
|
+
}
|
|
127
|
+
/// # Safety
|
|
128
|
+
/// Locations is live and index is in bounds.
|
|
129
|
+
#[unsafe(no_mangle)]
|
|
130
|
+
pub unsafe extern "C" fn sn_property_locations_key(
|
|
131
|
+
locations: *const tracking::PropertyLocations,
|
|
132
|
+
index: usize,
|
|
133
|
+
) -> Value {
|
|
134
|
+
unsafe { &*locations }.keys[index]
|
|
135
|
+
}
|
|
136
|
+
/// # Safety
|
|
137
|
+
/// Locations is live and immutable, called from C's GC mark callback.
|
|
138
|
+
#[unsafe(no_mangle)]
|
|
139
|
+
pub unsafe extern "C" fn sn_property_locations_mark(locations: *const tracking::PropertyLocations) {
|
|
140
|
+
unsafe { &*locations }.mark();
|
|
141
|
+
}
|
|
142
|
+
/// # Safety
|
|
143
|
+
/// Locations is live and immutable, called from C's memory size callback.
|
|
144
|
+
#[unsafe(no_mangle)]
|
|
145
|
+
pub unsafe extern "C" fn sn_property_locations_size(
|
|
146
|
+
locations: *const tracking::PropertyLocations,
|
|
147
|
+
) -> usize {
|
|
148
|
+
std::mem::size_of::<tracking::PropertyLocations>() + unsafe { &*locations }.memory_usage()
|
|
149
|
+
}
|
|
150
|
+
/// # Safety
|
|
151
|
+
/// Locations is an owned snapshot, freed exactly once by its C TypedData holder.
|
|
152
|
+
#[unsafe(no_mangle)]
|
|
153
|
+
pub unsafe extern "C" fn sn_property_locations_free(locations: *mut tracking::PropertyLocations) {
|
|
154
|
+
drop(unsafe { Box::from_raw(locations) });
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
#[cfg(test)]
|
|
158
|
+
mod tests {
|
|
159
|
+
use super::*;
|
|
160
|
+
#[test]
|
|
161
|
+
fn silent_child_failure_marks_the_live_collection_without_reserving_an_error() {
|
|
162
|
+
let mut report = Report {
|
|
163
|
+
silent: true,
|
|
164
|
+
..Report::default()
|
|
165
|
+
};
|
|
166
|
+
unsafe {
|
|
167
|
+
sn_report_child_validity(&mut report, 1);
|
|
168
|
+
}
|
|
169
|
+
assert!(!report.failed);
|
|
170
|
+
unsafe {
|
|
171
|
+
sn_report_child_validity(&mut report, 0);
|
|
172
|
+
}
|
|
173
|
+
assert!(report.failed);
|
|
174
|
+
assert_eq!(report.attempts, 0);
|
|
175
|
+
assert!(report.errors.is_empty());
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
#[test]
|
|
179
|
+
fn child_adoption_exports_child_properties_without_overwriting_parent_locations() {
|
|
180
|
+
let mut parent = Report::default().container_continuation(true, &Tracked::new(Valid));
|
|
181
|
+
parent
|
|
182
|
+
.evaluation
|
|
183
|
+
.as_mut()
|
|
184
|
+
.unwrap()
|
|
185
|
+
.set_runtime(tracking::RuntimeLocations {
|
|
186
|
+
buffer: 11,
|
|
187
|
+
properties: 13,
|
|
188
|
+
items: 15,
|
|
189
|
+
});
|
|
190
|
+
let mut completed = parent.continuation(true);
|
|
191
|
+
let mut child = Tracked::new(Valid);
|
|
192
|
+
child.set_runtime(tracking::RuntimeLocations {
|
|
193
|
+
buffer: 17,
|
|
194
|
+
properties: 19,
|
|
195
|
+
items: 21,
|
|
196
|
+
});
|
|
197
|
+
completed.evaluation = Some(child);
|
|
198
|
+
let child = parent.adopt(completed);
|
|
199
|
+
assert_eq!(child.properties_set(), Some(19));
|
|
200
|
+
assert_eq!(child.property_count(), 0);
|
|
201
|
+
assert_eq!(child.items_set(), Some(21));
|
|
202
|
+
assert_eq!(
|
|
203
|
+
parent.evaluation.as_ref().unwrap().properties_set(),
|
|
204
|
+
Some(13)
|
|
205
|
+
);
|
|
206
|
+
assert_eq!(parent.evaluation.as_ref().unwrap().property_count(), 0);
|
|
207
|
+
let empty = Tracked::new(Valid);
|
|
208
|
+
assert_eq!(empty.properties_set(), None);
|
|
209
|
+
assert_eq!(empty.property_count(), 0);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/// # Safety
|
|
214
|
+
/// Report is the idle current collection and C guards this exclusive mutation.
|
|
215
|
+
#[unsafe(no_mangle)]
|
|
216
|
+
pub unsafe extern "C" fn sn_report_child_validity(report: *mut Report, valid: i32) {
|
|
217
|
+
unsafe { &mut *report }.failed |= valid == 0;
|
|
218
|
+
}
|