yeptris 0.6.58.1-arm-linux-eabihf → 0.6.59.1-arm-linux-eabihf

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.
data/lib/yeptris.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  module Yeptris
4
4
  # The gem's version lives in the parent namespace's file — the last
5
5
  # internal require (yeptris/version) retired with it.
6
- VERSION = "0.6.58.1".freeze
6
+ VERSION = "0.6.59.1".freeze
7
7
 
8
8
  # Informational notices are OPT-IN (yeptris-ruby#217): consumers
9
9
  # embed yeptris inside CLIs that assert clean stderr, and a
@@ -54,6 +54,7 @@ module Yeptris
54
54
  autoload :ValueML, "yeptris/valueml"
55
55
  autoload :Psych, "yeptris/psych"
56
56
  autoload :Schema, "yeptris/schema"
57
+ autoload :Validation, "yeptris/validation"
57
58
  autoload :CBOR, "yeptris/cbor"
58
59
  end
59
60
 
data/libyeptris.so CHANGED
Binary file
@@ -3,7 +3,7 @@
3
3
  cmake_minimum_required(VERSION 3.20)
4
4
 
5
5
  project(yeptris
6
- VERSION 0.6.58
6
+ VERSION 0.6.59
7
7
  DESCRIPTION "Ultra-fast YAML 1.2 parser, emitter and streamer in C"
8
8
  LANGUAGES C CXX
9
9
  )
@@ -45,6 +45,7 @@ set(YEPTRIS_SOURCES
45
45
  yeptris/schema.c
46
46
  yeptris/validate/regexp.c
47
47
  yeptris/validate/validate.c
48
+ yeptris/validate/compile.c
48
49
  yeptris/validate/jsonschema.c
49
50
  yeptris/tape.c
50
51
  yeptris/plan.c
@@ -76,6 +76,14 @@ typedef enum {
76
76
  YEPTRIS_DIAG_LIMIT = 26, /* report truncated (the sentinel
77
77
  * rides the LAST slot; more
78
78
  * diagnostics were dropped) */
79
+ /* the 2020-12 sweep (#885 item 2) */
80
+ YEPTRIS_DIAG_MULTIPLE_OF = 27,
81
+ YEPTRIS_DIAG_MIN_PROPERTIES = 28,
82
+ YEPTRIS_DIAG_MAX_PROPERTIES = 29,
83
+ YEPTRIS_DIAG_CONTAINS = 30,
84
+ YEPTRIS_DIAG_MIN_CONTAINS = 31,
85
+ YEPTRIS_DIAG_MAX_CONTAINS = 32,
86
+ YEPTRIS_DIAG_DEPENDENT_REQUIRED = 33,
79
87
  } YeptrisDiagCode;
80
88
 
81
89
  /* Bounded diagnostic text; always NUL-terminated (over-long paths and
@@ -127,13 +135,17 @@ YEPTRIS_API YeptrisStatus yeptris_validate(const char* buf, size_t len, YeptrisS
127
135
  YEPTRIS_API YeptrisStatus yeptris_validate_document(YeptrisDocument doc, YeptrisSchema schema,
128
136
  yeptris_validate_report** out);
129
137
 
130
- /* JSON Schema draft 2020-12 subset (#882 slice 2). `schema` is parsed
131
- * with the same engine (JSON is YAML flow); document 0 of the stream
132
- * is the schema. Keyword subset: type, enum, const, pattern, minimum/
133
- * maximum/exclusiveMinimum/exclusiveMaximum (numeric, 2020-12 form),
134
- * minLength/maxLength (code points), minItems/maxItems, uniqueItems,
135
- * items (+ prefixItems; the draft-07 array form rides as prefixItems),
136
- * properties, required, additionalProperties (bool or schema),
138
+ /* JSON Schema draft 2020-12 subset (#882 slice 2; #885 item 2). `schema`
139
+ * is parsed with the same engine (JSON is YAML flow); document 0 of the
140
+ * stream is the schema. Keyword subset: type, enum, const, pattern,
141
+ * minimum/maximum/exclusiveMinimum/exclusiveMaximum (numeric, 2020-12
142
+ * form), multipleOf (libm-free quotient test), minLength/maxLength
143
+ * (code points), minItems/maxItems, uniqueItems, contains (+ the
144
+ * minContains/maxContains qualifiers), items (+ prefixItems; the
145
+ * draft-07 array form rides as prefixItems), properties, required,
146
+ * patternProperties, propertyNames, minProperties/maxProperties,
147
+ * additionalProperties (bool or schema; excludes patternProperties
148
+ * matches), dependentRequired, dependentSchemas, if/then/else,
137
149
  * allOf/anyOf/oneOf/not, $ref (LOCAL "#/..." pointers only — $defs and
138
150
  * definitions both resolve). Boolean schemas (`true`/`false`) apply.
139
151
  * Unknown keywords and known keywords with unreadable values are
@@ -150,6 +162,37 @@ YEPTRIS_API YeptrisStatus yeptris_json_schema_validate(const char* schema, size_
150
162
  const char* buf, size_t len,
151
163
  yeptris_validate_report** out);
152
164
 
165
+ /* The COMPILED SCHEMA — the leptris-XSD economy (#885 item 3): parse
166
+ * the schema ONCE, validate MANY instance streams against the retained
167
+ * model. The handle owns everything it reads: the schema bytes (copied
168
+ * — the retained DOM's views borrow them), the parsed document, and
169
+ * the pattern kernel's compiled programs (the XSD content-model
170
+ * analog: `(a+)+$` compiles once here, not once per validated string
171
+ * the way the one-shot face pays). yeptris_schema_compile returns NULL
172
+ * on failure; yeptris_last_error() carries the why (bad arguments,
173
+ * bytes that hold no document, a schema that does not parse,
174
+ * allocation failure).
175
+ *
176
+ * yeptris_schema_validate keeps yeptris_json_schema_validate's exact
177
+ * status/report contract; diagnostics enumerate every miss across
178
+ * every document of the instance stream. yeptris_schema_free releases
179
+ * the handle and everything it owns in ONE call (no refcounting) —
180
+ * afterwards the handle is DEAD: passing it anywhere is undefined,
181
+ * exactly like a freed document. NULL is accepted (a no-op).
182
+ *
183
+ * Thread law: one schema handle per thread, like documents — the
184
+ * handle is immutable after compile (the pattern programs are built at
185
+ * compile time), so read-only sharing across threads is safe; reports
186
+ * are per-call and caller-owned. */
187
+ typedef struct yeptris_schema yeptris_schema;
188
+
189
+ YEPTRIS_API yeptris_schema* yeptris_schema_compile(const char* bytes, size_t n);
190
+
191
+ YEPTRIS_API YeptrisStatus yeptris_schema_validate(yeptris_schema* s, const char* buf, size_t len,
192
+ yeptris_validate_report** out);
193
+
194
+ YEPTRIS_API void yeptris_schema_free(yeptris_schema* s);
195
+
153
196
  #ifdef __cplusplus
154
197
  }
155
198
  #endif
@@ -236,10 +236,15 @@ static YeptrisDocument parse_impl(const char* buf, size_t len, const YeptrisPars
236
236
  goto fail;
237
237
  }
238
238
 
239
+ /* a NULL/0-byte stream is a valid empty input: parse it through a
240
+ * non-null base so the BOM arithmetic never computes NULL+0
241
+ * (clang's UBSan flags the zero-offset-null form; gcc's does not —
242
+ * the schema-econ BadInputs pin surfaced it on the macOS arm64 leg) */
243
+ const char* src = buf != NULL ? buf : "";
239
244
  const yep_allocator* sys = yep_system_allocator();
240
245
 
241
246
  /* Encoding front-end: BOM sniff; borrow UTF-8, transcode the rest. */
242
- const char* data = buf;
247
+ const char* data = src;
243
248
  size_t data_len = len;
244
249
  unsigned char* transcoded = NULL;
245
250
  size_t transcoded_len = 0;
@@ -256,8 +261,8 @@ static YeptrisDocument parse_impl(const char* buf, size_t len, const YeptrisPars
256
261
  goto engine_enter;
257
262
  }
258
263
 
259
- size_t bom = yep_bom_sniff((const unsigned char*)buf, len, &enc);
260
- data = buf + bom;
264
+ size_t bom = yep_bom_sniff((const unsigned char*)src, len, &enc);
265
+ data = src + bom;
261
266
  data_len = len - bom;
262
267
 
263
268
  if (enc == YEP_ENC_UTF16LE || enc == YEP_ENC_UTF16BE || enc == YEP_ENC_UTF32LE ||
@@ -0,0 +1,270 @@
1
+ /* compile.c — the compiled-schema economy (#885 item 3).
2
+ *
3
+ * The leptris-XSD shape (~/src/leptris/leptris/src/leptris/xsd/):
4
+ * parse the schema ONCE, retain the DOM and the derived state, validate
5
+ * many instance streams against the retained model. The handle owns
6
+ * everything it reads — the schema bytes (copied: the DOM's scalar
7
+ * views borrow them), the parsed document (its DOM, pools and finish
8
+ * pool die with yeptris_document_free), and the compiled pattern
9
+ * programs (the XSD content-model analog: `(a+)+$` compiles once at
10
+ * compile time, not once per validated string). One free call releases
11
+ * it all — no refcounting, the document-ownership law.
12
+ *
13
+ * The pattern programs are populated EAGERLY by a DFS over the schema
14
+ * tree (`pattern` values and `patternProperties` keys — the kernel's
15
+ * only two consumers), so the handle is immutable after compile and
16
+ * `yeptris_schema_validate` is a pure reader: one schema handle per
17
+ * thread like documents; read-only sharing across threads is safe.
18
+ * An invalid pattern is simply not retained — every use then recompiles
19
+ * to the one-shot's -1 (ignored keyword), never a guess.
20
+ *
21
+ * The one-shot face (yeptris_json_schema_validate) routes through the
22
+ * same compile+validate machinery internally: identical parse, walk
23
+ * and report code paths, so its observable statuses and byte-for-byte
24
+ * verdicts are preserved (the 1298-case suite port is the referee).
25
+ */
26
+
27
+ #include <string.h>
28
+
29
+ #include <yeptris/dom.h>
30
+ #include <yeptris/validate.h>
31
+
32
+ #include "../common/error.h"
33
+ #include "../doc.h"
34
+ #include "../memory/allocator.h"
35
+ #include "../tape_in.h"
36
+ #include "internal.h"
37
+
38
+ /* The compiled schema. Opaque at the face (validate.h); everything it
39
+ * reads dies with it. */
40
+ struct yeptris_schema {
41
+ char* bytes; /* owned: the schema bytes (the DOM's input views borrow them) */
42
+ yeptris_document* doc; /* owned: the parsed schema document */
43
+ const yep_dom* dom; /* borrowed from doc (yep_doc_dom) */
44
+ uint32_t sroot; /* the schema document's root (docs[0]) */
45
+ yep_re_cache* cache; /* owned: pattern source -> compiled NFA; immutable after compile */
46
+ };
47
+
48
+ /* ---- the pattern collection (compile-time, eager) ----------------------- */
49
+
50
+ static int collect_patterns(yep_re_cache* t, const yep_dom* d, uint32_t id, int depth);
51
+
52
+ /* Collects every pattern source of one mapping pair set. 0 ok, -1 OOM. */
53
+ static int collect_map(yep_re_cache* t, const yep_dom* d, uint32_t map_id, int depth) {
54
+ const yep_dnode* m = yep_dom_node(d, map_id);
55
+ uint32_t k = m->first_child;
56
+ while (k != UINT32_MAX) {
57
+ uint32_t v = yep_dom_node(d, k) ? yep_dom_node(d, k)->next_sibling : UINT32_MAX;
58
+ const yep_dnode* kn = yep_dom_node(d, k);
59
+ const yep_dnode* vn = v != UINT32_MAX ? yep_dom_node(d, v) : NULL;
60
+ if (kn != NULL && kn->kind == YEP_DOM_SCALAR) {
61
+ yep_view kv = yep_dom_view(d, kn->value);
62
+ /* the keyword names, matched by bytes like the walk's kw_get */
63
+ if (kv.len == 7 && memcmp(kv.p, "pattern", 7) == 0) {
64
+ /* "pattern": the value is the pattern source (a string
65
+ * scalar, schema_word's exact read) */
66
+ if (vn != NULL && vn->kind == YEP_DOM_SCALAR &&
67
+ yep_validate_scalar_tag(vn) == YEPTRIS_TAG_STR) {
68
+ yep_view vv = yep_dom_view(d, vn->value);
69
+ if (vv.p != NULL && yep_re_cache_add(t, vv.p, vv.len) < 0) {
70
+ return -1;
71
+ }
72
+ }
73
+ } else if (kv.len == 17 && memcmp(kv.p, "patternProperties", 17) == 0) {
74
+ /* "patternProperties": its KEYS are the pattern sources */
75
+ if (vn != NULL && vn->kind == YEP_DOM_MAPPING) {
76
+ uint32_t pk = vn->first_child;
77
+ while (pk != UINT32_MAX) {
78
+ uint32_t pv =
79
+ yep_dom_node(d, pk) ? yep_dom_node(d, pk)->next_sibling : UINT32_MAX;
80
+ const yep_dnode* pkn = yep_dom_node(d, pk);
81
+ if (pkn != NULL && pkn->kind == YEP_DOM_SCALAR &&
82
+ yep_validate_scalar_tag(pkn) == YEPTRIS_TAG_STR) {
83
+ yep_view pw = yep_dom_view(d, pkn->value);
84
+ if (pw.p != NULL && yep_re_cache_add(t, pw.p, pw.len) < 0) {
85
+ return -1;
86
+ }
87
+ }
88
+ pk = pv;
89
+ }
90
+ }
91
+ }
92
+ }
93
+ /* the rest of the schema rides the values (keys are scalars —
94
+ * nothing under them; the walk reaches nodes the same way) */
95
+ if (v != UINT32_MAX && collect_patterns(t, d, v, depth + 1) != 0) {
96
+ return -1;
97
+ }
98
+ k = v != UINT32_MAX && yep_dom_node(d, v) ? yep_dom_node(d, v)->next_sibling : UINT32_MAX;
99
+ }
100
+ return 0;
101
+ }
102
+
103
+ /* Depth-bounded DFS gathering every pattern the walk can reach. 0 ok,
104
+ * -1 OOM. Aliases are skipped: the walk sees an alias node as opaque
105
+ * (never a mapping), so no reachable pattern hides behind one. */
106
+ static int collect_patterns(yep_re_cache* t, const yep_dom* d, uint32_t id, int depth) {
107
+ if (depth > YEP_DOM_MAX_DEPTH) {
108
+ return 0; /* the walk's own guard: deeper nodes are unreachable to it too */
109
+ }
110
+ const yep_dnode* n = yep_dom_node(d, id);
111
+ if (n == NULL) {
112
+ return 0;
113
+ }
114
+ if (n->kind == YEP_DOM_MAPPING) {
115
+ return collect_map(t, d, id, depth);
116
+ }
117
+ if (n->kind == YEP_DOM_SEQUENCE) {
118
+ uint32_t ch = n->first_child;
119
+ while (ch != UINT32_MAX) {
120
+ uint32_t next = yep_dom_node(d, ch) ? yep_dom_node(d, ch)->next_sibling : UINT32_MAX;
121
+ if (collect_patterns(t, d, ch, depth + 1) != 0) {
122
+ return -1;
123
+ }
124
+ ch = next;
125
+ }
126
+ }
127
+ return 0;
128
+ }
129
+
130
+ /* ---- the seam with the explicit status (internal.h) --------------------- */
131
+
132
+ yeptris_schema* yep_schema_compile_st(const char* bytes, size_t n, YeptrisStatus* st) {
133
+ *st = YEPTRIS_OK;
134
+ if (bytes == NULL && n != 0) {
135
+ *st = YEPTRIS_ERROR_ARG;
136
+ return NULL;
137
+ }
138
+ const yep_allocator* sys = yep_system_allocator();
139
+
140
+ /* the schema bytes are COPIED: the DOM's scalar views borrow its
141
+ * input, and the handle outlives this call */
142
+ char* copy = NULL;
143
+ if (n > 0) {
144
+ copy = yep_alloc(sys, n);
145
+ if (copy == NULL) {
146
+ *st = YEPTRIS_ERROR_MEMORY;
147
+ return NULL;
148
+ }
149
+ memcpy(copy, bytes, n);
150
+ }
151
+
152
+ /* document 0 of the stream is the schema (the one-shot's exact rule) */
153
+ YeptrisParseOptions opts;
154
+ memset(&opts, 0, sizeof(opts)); /* core12: the YAML->JSON data model */
155
+ YeptrisStatus ps = YEPTRIS_OK;
156
+ yeptris_document* doc = (yeptris_document*)yeptris_parse_eager_ex(copy, n, &opts, &ps);
157
+ if (doc == NULL) {
158
+ yep_free(sys, copy);
159
+ if (ps == YEPTRIS_OK) { /* empty bytes: the stream holds no document */
160
+ yep_error_set(yep_error_tls(), YEP_ERR_UNEXPECTED, 0, 0, 0,
161
+ "the schema bytes hold no document");
162
+ *st = YEPTRIS_ERROR_ARG;
163
+ } else {
164
+ *st = ps; /* the schema did not parse — the engine's own status */
165
+ }
166
+ return NULL;
167
+ }
168
+ const yep_dom* dom = yep_doc_dom(doc);
169
+ if (dom == NULL || dom->dcount == 0) {
170
+ yeptris_document_free(doc);
171
+ yep_free(sys, copy);
172
+ yep_error_set(yep_error_tls(), YEP_ERR_UNEXPECTED, 0, 0, 0,
173
+ "the schema bytes hold no document");
174
+ *st = YEPTRIS_ERROR_ARG;
175
+ return NULL;
176
+ }
177
+
178
+ /* the pattern programs: compiled once, here (a failure to retain is
179
+ * an allocation failure — loud, like every constructor's OOM) */
180
+ yep_re_cache* cache = yep_re_cache_new();
181
+ if (cache == NULL || collect_patterns(cache, dom, dom->docs[0], 0) != 0) {
182
+ yep_re_cache_free(cache);
183
+ yeptris_document_free(doc);
184
+ yep_free(sys, copy);
185
+ yep_error_set(yep_error_tls(), YEP_ERR_MEMORY, 0, 0, 0,
186
+ "the schema's pattern programs failed to compile");
187
+ *st = YEPTRIS_ERROR_MEMORY;
188
+ return NULL;
189
+ }
190
+
191
+ yeptris_schema* s = yep_alloc(sys, sizeof(*s));
192
+ if (s == NULL) {
193
+ yep_re_cache_free(cache);
194
+ yeptris_document_free(doc);
195
+ yep_free(sys, copy);
196
+ *st = YEPTRIS_ERROR_MEMORY;
197
+ return NULL;
198
+ }
199
+ s->bytes = copy;
200
+ s->doc = doc;
201
+ s->dom = dom;
202
+ s->sroot = dom->docs[0];
203
+ s->cache = cache;
204
+ return s;
205
+ }
206
+
207
+ /* ---- the public face (validate.h) --------------------------------------- */
208
+
209
+ YEPTRIS_API yeptris_schema* yeptris_schema_compile(const char* bytes, size_t n) {
210
+ YeptrisStatus st = YEPTRIS_OK;
211
+ return yep_schema_compile_st(bytes, n, &st); /* the error channel carries the why */
212
+ }
213
+
214
+ YEPTRIS_API void yeptris_schema_free(yeptris_schema* s) {
215
+ if (s == NULL) {
216
+ return;
217
+ }
218
+ const yep_allocator* sys = yep_system_allocator();
219
+ yep_re_cache_free(s->cache);
220
+ yeptris_document_free(s->doc); /* the DOM and every pool under it */
221
+ yep_free(sys, s->bytes); /* the views' home: freed after its readers */
222
+ yep_free(sys, s);
223
+ }
224
+
225
+ YEPTRIS_API YeptrisStatus yeptris_schema_validate(yeptris_schema* s, const char* buf, size_t len,
226
+ yeptris_validate_report** out) {
227
+ if (out == NULL || s == NULL || (buf == NULL && len != 0)) {
228
+ return YEPTRIS_ERROR_ARG;
229
+ }
230
+ *out = NULL;
231
+
232
+ /* the instance stream (core12, the one-shot's exact parse) */
233
+ YeptrisParseOptions opts;
234
+ memset(&opts, 0, sizeof(opts));
235
+ YeptrisStatus st = YEPTRIS_OK;
236
+ YeptrisDocument idoc = yeptris_parse_eager_ex(buf, len, &opts, &st);
237
+ if (idoc == NULL) {
238
+ if (st == YEPTRIS_OK) {
239
+ /* an empty instance stream: nothing to invalidate */
240
+ yeptris_validate_report* r = yep_validate_report_new();
241
+ if (r == NULL) {
242
+ return YEPTRIS_ERROR_MEMORY;
243
+ }
244
+ *out = r;
245
+ return YEPTRIS_OK;
246
+ }
247
+ return st; /* the parse's own error */
248
+ }
249
+ yep_dom* idom = yep_doc_dom((yeptris_document*)idoc);
250
+ if (idom == NULL) {
251
+ yeptris_document_free(idoc);
252
+ return YEPTRIS_ERROR_MEMORY;
253
+ }
254
+
255
+ yeptris_validate_report* r = yep_validate_report_new();
256
+ if (r == NULL) {
257
+ yeptris_document_free(idoc);
258
+ return YEPTRIS_ERROR_MEMORY;
259
+ }
260
+ /* the handle is a pure reader here (its cache is immutable): the
261
+ * same walk, the same report shape, the one-shot's verdicts */
262
+ int rc = yep_jsonschema_run(s->dom, s->sroot, idom, idom->docs, idom->dcount, r, s->cache);
263
+ yeptris_document_free(idoc);
264
+ if (rc != 0) {
265
+ yeptris_validate_report_free(r);
266
+ return YEPTRIS_ERROR_MEMORY;
267
+ }
268
+ *out = r;
269
+ return r->count > 0 ? YEPTRIS_ERROR_SCHEMA : YEPTRIS_OK;
270
+ }
@@ -72,10 +72,24 @@ void yep_validate_path_pop(yep_vctx* c, size_t mark);
72
72
  * literals, '.', classes, groups, alternation, the greedy/lazy
73
73
  * quantifiers, anchors, \d\w\s\D\W\S\b\B and \xHH. Byte-oriented
74
74
  * (ASCII classes; UTF-8 literals match byte-wise). A Thompson NFA —
75
- * O(len * m), no backtracking blowup; patterns over the program
76
- * budget are invalid. 1 match, 0 no match, -1 invalid pattern. */
75
+ * O(len * m), no backtracking blowup, no recursion over the subject.
76
+ * Patterns over the program budget are invalid. 1 match, 0 no match,
77
+ * -1 invalid pattern. */
77
78
  int yep_re_search(const char* pat, uint32_t pat_len, const char* s, uint32_t s_len);
78
79
 
80
+ /* The retained-program cache behind the compiled schema (#885 item 3):
81
+ * pattern source -> compiled NFA, populated at compile time, immutable
82
+ * afterwards (read-only sharing, the document law). A miss — a NULL
83
+ * cache included — compiles fresh with yep_re_search's exact verdicts;
84
+ * cache_add returns 1 stored, 0 not retained (invalid pattern, empty,
85
+ * table full — misses recompile), -1 allocation failure (loud). */
86
+ typedef struct yep_re_cache yep_re_cache;
87
+ yep_re_cache* yep_re_cache_new(void);
88
+ void yep_re_cache_free(yep_re_cache* t);
89
+ int yep_re_cache_add(yep_re_cache* t, const char* pat, uint32_t plen);
90
+ int yep_re_cache_search(const yep_re_cache* t, const char* pat, uint32_t plen, const char* s,
91
+ uint32_t s_len);
92
+
79
93
  /* Canonical scalar tag of a DOM node (explicit tag, then the parse
80
94
  * resolver's plain verdict, then str): the value model both walks
81
95
  * compare under. */
@@ -90,10 +104,25 @@ int yep_validate_node_equal(const yep_dom* da, uint32_t a, const yep_dom* db, ui
90
104
  int depth);
91
105
 
92
106
  /* jsonschema.c's driver: applies the schema tree (its own DOM) to
93
- * every instance document root, emitting into `rep`. Returns 0, -1
94
- * on OOM. */
107
+ * every instance document root, emitting into `rep`. `cache` is the
108
+ * compiled schema's retained pattern programs (NULL: none — the
109
+ * one-shot face). Returns 0, -1 on OOM. */
95
110
  int yep_jsonschema_run(const yep_dom* schema_dom, uint32_t schema_root, const yep_dom* instance_dom,
96
- const uint32_t* doc_roots, uint32_t doc_count, yeptris_validate_report* rep);
111
+ const uint32_t* doc_roots, uint32_t doc_count, yeptris_validate_report* rep,
112
+ const yep_re_cache* cache);
113
+
114
+ /* The report constructor (validate.c owns the report machinery): a
115
+ * fresh empty report, NULL on allocation failure. */
116
+ yeptris_validate_report* yep_validate_report_new(void);
117
+
118
+ /* compile.c's seam (#885 item 3): the compiled-schema constructor with
119
+ * an explicit status — the one-shot face preserves its exact observable
120
+ * statuses through it. NULL on failure with *st = YEPTRIS_ERROR_ARG
121
+ * (NULL bytes with length, or bytes that hold no document; the thread
122
+ * error channel carries the message), the failed parse's status, or
123
+ * YEPTRIS_ERROR_MEMORY. */
124
+ struct yeptris_schema;
125
+ yeptris_schema* yep_schema_compile_st(const char* bytes, size_t n, YeptrisStatus* st);
97
126
 
98
127
  #ifdef __cplusplus
99
128
  }