schemurai 3.0.0 → 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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -4
  3. data/ext/schemurai_native/Cargo.lock +55 -1
  4. data/ext/schemurai_native/Cargo.toml +4 -1
  5. data/ext/schemurai_native/extconf.rb +1 -1
  6. data/ext/schemurai_native/glue.c +1679 -62
  7. data/ext/schemurai_native/protocol.def +45 -0
  8. data/ext/schemurai_native/src/budget.rs +49 -0
  9. data/ext/schemurai_native/src/container.rs +460 -0
  10. data/ext/schemurai_native/src/content.rs +74 -27
  11. data/ext/schemurai_native/src/diagnostics/array.rs +392 -0
  12. data/ext/schemurai_native/src/diagnostics/object.rs +218 -0
  13. data/ext/schemurai_native/src/diagnostics.rs +1087 -307
  14. data/ext/schemurai_native/src/enumeration.rs +6 -1
  15. data/ext/schemurai_native/src/evaluation.rs +49 -20
  16. data/ext/schemurai_native/src/format.rs +126 -14
  17. data/ext/schemurai_native/src/graph.rs +37 -0
  18. data/ext/schemurai_native/src/instance_graph.rs +90 -0
  19. data/ext/schemurai_native/src/integer_scan.rs +132 -0
  20. data/ext/schemurai_native/src/lib.rs +917 -238
  21. data/ext/schemurai_native/src/memo.rs +11 -38
  22. data/ext/schemurai_native/src/number/arbitrary.rs +154 -0
  23. data/ext/schemurai_native/src/number.rs +250 -59
  24. data/ext/schemurai_native/src/pattern.rs +147 -109
  25. data/ext/schemurai_native/src/pointer.rs +97 -0
  26. data/ext/schemurai_native/src/runtime/properties.rs +162 -0
  27. data/ext/schemurai_native/src/runtime/reports.rs +266 -0
  28. data/ext/schemurai_native/src/runtime/scopes.rs +430 -0
  29. data/ext/schemurai_native/src/runtime.rs +1020 -0
  30. data/ext/schemurai_native/src/scope.rs +60 -16
  31. data/ext/schemurai_native/src/string.rs +68 -0
  32. data/ext/schemurai_native/src/tracking.rs +244 -174
  33. data/lib/schemurai/container_checks/array_diagnostics.rb +119 -0
  34. data/lib/schemurai/container_checks/object_diagnostics.rb +152 -0
  35. data/lib/schemurai/container_checks.rb +534 -0
  36. data/lib/schemurai/decimal.rb +11 -0
  37. data/lib/schemurai/dialect.rb +0 -12
  38. data/lib/schemurai/ecma_regexp.rb +46 -0
  39. data/lib/schemurai/evaluation_pool.rb +66 -0
  40. data/lib/schemurai/evaluator.rb +9 -48
  41. data/lib/schemurai/json_pointer.rb +11 -0
  42. data/lib/schemurai/native/diagnostics.rb +4 -3
  43. data/lib/schemurai/native/evaluator.rb +38 -10
  44. data/lib/schemurai/native/null_numeric.rb +23 -0
  45. data/lib/schemurai/number_checks.rb +128 -0
  46. data/lib/schemurai/string_checks.rb +166 -0
  47. data/lib/schemurai/type_checks.rb +59 -0
  48. data/lib/schemurai/value_equality.rb +72 -0
  49. data/lib/schemurai/version.rb +1 -1
  50. data/lib/schemurai/vm/compiler.rb +18 -26
  51. data/lib/schemurai/vm/evaluator.rb +87 -545
  52. data/lib/schemurai/vm/limited_evaluator.rb +7 -22
  53. metadata +25 -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
+ }