yeptris 0.6.50.0-arm-linux-eabihf → 0.6.51.0-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.
- checksums.yaml +4 -4
- data/ext/yeptris_native/version.h +2 -2
- data/lib/yeptris/3.4/native.so +0 -0
- data/lib/yeptris/json.rb +16 -7
- data/lib/yeptris.rb +1 -1
- data/libyeptris.so +0 -0
- data/vendor/libyeptris/CMakeLists.txt +1 -1
- data/vendor/libyeptris/src/include/yeptris/cbor.h +49 -0
- data/vendor/libyeptris/src/yeptris/cbor/decode.c +22 -0
- data/vendor/libyeptris/src/yeptris/cbor/sink.h +7 -29
- data/vendor/libyeptris/src/yeptris/events/values.c +13 -0
- data/vendor/libyeptris/src/yeptris/events/values_priv.h +2 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1762c833f5c3ee978bdf6b43d59e7ae4523ff6edba01ade64354eddd3f3cfbf9
|
|
4
|
+
data.tar.gz: a84e2415681f867a3aa4b1d45ee16ccfcb66213bd6f8494905ec9d420663c217
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c87d565da52486b460e944c1a04aa89f100118de2ad0255e31a0d0497dbc7d2b5c588531b7097f2212087006a0cec2a39d44734159605b060c16029bfd76940a
|
|
7
|
+
data.tar.gz: 352d9550314e65f0c920d97ac1859d36fdb0b3492acd965be1f7568452e057fbe30dbf5ad7b10fa09ee15e70c0844bbdce691f77a8f7479654fb2cc94e1d32fd
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
|
|
12
12
|
#define YEPTRIS_VERSION_MAJOR 0
|
|
13
13
|
#define YEPTRIS_VERSION_MINOR 6
|
|
14
|
-
#define YEPTRIS_VERSION_PATCH
|
|
15
|
-
#define YEPTRIS_VERSION_STRING "0.6.
|
|
14
|
+
#define YEPTRIS_VERSION_PATCH 51
|
|
15
|
+
#define YEPTRIS_VERSION_STRING "0.6.51"
|
|
16
16
|
|
|
17
17
|
#ifdef __cplusplus
|
|
18
18
|
extern "C" {
|
data/lib/yeptris/3.4/native.so
CHANGED
|
Binary file
|
data/lib/yeptris/json.rb
CHANGED
|
@@ -34,12 +34,21 @@ module Yeptris
|
|
|
34
34
|
|
|
35
35
|
module_function
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
# allow_duplicate_key: opts out of the resolved json gem's strict
|
|
38
|
+
# duplicate-key contract (json >= 3 rejects by default) — last value
|
|
39
|
+
# wins, exactly the historical JSON.parse contract. System-boundary
|
|
40
|
+
# parsers need it: third-party feeds (Crossref book records keyed by
|
|
41
|
+
# ISBN, NIST's pubs export keyed by " ", the UN search API's blank
|
|
42
|
+
# keys) genuinely carry duplicates, and rejecting them breaks the fetch
|
|
43
|
+
# rather than flagging the data (relaton/relaton#413, the ask in
|
|
44
|
+
# yeptris-ruby#335). Default stays the json-gem-parity strictness.
|
|
45
|
+
def load(source, allow_duplicate_key: false)
|
|
46
|
+
strict = STRICT_DUPLICATE_KEYS && !allow_duplicate_key
|
|
38
47
|
source = ::Yeptris.read_input(source)
|
|
39
48
|
source = source.to_s
|
|
40
49
|
if defined?(::Yeptris::Native)
|
|
41
50
|
begin
|
|
42
|
-
return ::Yeptris::Native.load_json(source,
|
|
51
|
+
return ::Yeptris::Native.load_json(source, strict)
|
|
43
52
|
rescue ::Yeptris::ParseError => e
|
|
44
53
|
raise ParseError, e.message
|
|
45
54
|
end
|
|
@@ -53,9 +62,9 @@ module Yeptris
|
|
|
53
62
|
# none) answered last-wins under json >= 3 — found by canon's
|
|
54
63
|
# dependent CI, whose parity pin now names the lane.
|
|
55
64
|
return marshal_engine(
|
|
56
|
-
source,
|
|
65
|
+
source, strict ? ::Yeptris::FFI::MARSHAL_STRICT_DUP_KEYS : 0
|
|
57
66
|
) if ::Yeptris::FFI::MARSHAL_STRICT_DUP
|
|
58
|
-
tape_engine(source)
|
|
67
|
+
tape_engine(source, strict)
|
|
59
68
|
end
|
|
60
69
|
|
|
61
70
|
# The marshal engine (#278): yeptris_parse_json gates the strict
|
|
@@ -156,19 +165,19 @@ module Yeptris
|
|
|
156
165
|
out.force_encoding(Encoding::UTF_8)
|
|
157
166
|
end
|
|
158
167
|
|
|
159
|
-
def tape_engine(source)
|
|
168
|
+
def tape_engine(source, strict_dup = STRICT_DUPLICATE_KEYS)
|
|
160
169
|
tape = ::Yeptris::FFI::JsonTape.new
|
|
161
170
|
rc = ::Yeptris::FFI.yeptris_parse_json_tape(source, source.bytesize, tape)
|
|
162
171
|
raise ParseError, ::Yeptris::FFI.last_error_message if rc != ::Yeptris::FFI::OK
|
|
163
172
|
|
|
164
173
|
begin
|
|
165
|
-
walk_tape(source, tape)
|
|
174
|
+
walk_tape(source, tape, strict_dup)
|
|
166
175
|
ensure
|
|
167
176
|
::Yeptris::FFI.yeptris_tape_free(tape)
|
|
168
177
|
end
|
|
169
178
|
end
|
|
170
179
|
|
|
171
|
-
def walk_tape(src, tape, strict_dup
|
|
180
|
+
def walk_tape(src, tape, strict_dup)
|
|
172
181
|
n = tape[:count]
|
|
173
182
|
kinds = tape[:kinds].read_bytes(n).unpack("C*")
|
|
174
183
|
offs = tape[:offs].read_bytes(n * 4).unpack("V*")
|
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.
|
|
6
|
+
VERSION = "0.6.51.0".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
|
data/libyeptris.so
CHANGED
|
Binary file
|
|
@@ -53,6 +53,55 @@ extern "C" {
|
|
|
53
53
|
YEPTRIS_API YeptrisDocument yeptris_cbor_decode(const void* buf, size_t len, uint32_t opts,
|
|
54
54
|
YeptrisStatus* status);
|
|
55
55
|
|
|
56
|
+
/* The SAX decode face (#742): yeptris_cbor_decode's grammar driving
|
|
57
|
+
* consumer callbacks — items land as they parse, no document, no
|
|
58
|
+
* nodes. Measured (perf ledger 2026-10-29): the scan-only route reads
|
|
59
|
+
* ~2.1x the DOM entry on the same corpus (DOM construction is over
|
|
60
|
+
* half the decode lane), so validation, counting, and streaming
|
|
61
|
+
* transforms belong here. Items arrive in encoding order; map items
|
|
62
|
+
* set is_key on the key half. Strings with borrowed=1 point INTO buf —
|
|
63
|
+
* keep it valid while you hold them; borrowed=0 is decoder scratch.
|
|
64
|
+
* tag ("N N N", outermost first; NULL when none) and tag_len are
|
|
65
|
+
* callback-call-local. open's cap is the expected item count (maps
|
|
66
|
+
* count pairs*2; UINT64_MAX = indefinite); close fires for both the
|
|
67
|
+
* definite-complete and the break path, after the last child. The
|
|
68
|
+
* rendered text forms match the DOM ledger exactly (numbers-as-text,
|
|
69
|
+
* false/true/null/undefined, simple(N)).
|
|
70
|
+
*
|
|
71
|
+
* Every callback returns 0 on sink failure — the decode then reports
|
|
72
|
+
* YEPTRIS_ERROR_MEMORY — and may raise through host languages; the
|
|
73
|
+
* decoder owns no host state across them except the indefinite buffer,
|
|
74
|
+
* which its own exit paths free. All seven callbacks and sax itself
|
|
75
|
+
* must be non-NULL (YEPTRIS_ERROR_ARG otherwise): the loop dispatches
|
|
76
|
+
* unconditionally.
|
|
77
|
+
*
|
|
78
|
+
* consumed == NULL: trailing bytes after the one data item fail
|
|
79
|
+
* YEPTRIS_ERROR_PARSE. consumed != NULL: on success it receives the
|
|
80
|
+
* byte count of the items decoded — walk a CBOR Sequence (RFC 8742)
|
|
81
|
+
* by advancing buf by it. On failure *status (may be NULL) carries the
|
|
82
|
+
* code and yeptris_last_error() the message with the byte offset.
|
|
83
|
+
*
|
|
84
|
+
* Memory: none — the decoder allocates only its indefinite-chunk
|
|
85
|
+
* scratch and frees it on every exit. */
|
|
86
|
+
typedef struct yeptris_cbor_sax {
|
|
87
|
+
void* ctx;
|
|
88
|
+
int (*text)(void* ctx, const char* s, uint32_t n, uint8_t tag_id, int is_key, const char* tag,
|
|
89
|
+
uint32_t tag_len);
|
|
90
|
+
int (*int_val)(void* ctx, int negative, uint64_t mag, int is_key, const char* tag,
|
|
91
|
+
uint32_t tag_len);
|
|
92
|
+
int (*float_val)(void* ctx, double dv, int is_key, const char* tag, uint32_t tag_len);
|
|
93
|
+
int (*str_val)(void* ctx, const unsigned char* p, uint32_t n, int borrowed, int is_key,
|
|
94
|
+
const char* tag, uint32_t tag_len);
|
|
95
|
+
int (*bytes_val)(void* ctx, const unsigned char* p, uint32_t n, int borrowed, int is_key,
|
|
96
|
+
const char* tag, uint32_t tag_len);
|
|
97
|
+
int (*open)(void* ctx, int is_map, uint64_t cap, const char* tag, uint32_t tag_len);
|
|
98
|
+
int (*close)(void* ctx, int is_map);
|
|
99
|
+
} yeptris_cbor_sax;
|
|
100
|
+
|
|
101
|
+
YEPTRIS_API YeptrisStatus yeptris_cbor_decode_sax(const void* buf, size_t len, uint32_t opts,
|
|
102
|
+
const yeptris_cbor_sax* sax, size_t* consumed,
|
|
103
|
+
YeptrisStatus* status);
|
|
104
|
+
|
|
56
105
|
/* CBOR Sequences (RFC 8742): top-level data items, concatenated —
|
|
57
106
|
* no framing bytes. Iterates the buffer, one document per item; the
|
|
58
107
|
* callback OWNS each item (free it with yeptris_document_free) and
|
|
@@ -1032,3 +1032,25 @@ YEPTRIS_API YeptrisDocument yeptris_cbor_decode(const void* buf, size_t len, uin
|
|
|
1032
1032
|
}
|
|
1033
1033
|
return (YeptrisDocument)doc;
|
|
1034
1034
|
}
|
|
1035
|
+
|
|
1036
|
+
YEPTRIS_API YeptrisStatus yeptris_cbor_decode_sax(const void* buf, size_t len, uint32_t opts,
|
|
1037
|
+
const yeptris_cbor_sax* sax, size_t* consumed,
|
|
1038
|
+
YeptrisStatus* status) {
|
|
1039
|
+
if ((buf == NULL && len != 0) || sax == NULL || (opts & ~YEPTRIS_CBOR_STRICT) != 0 ||
|
|
1040
|
+
sax->text == NULL || sax->int_val == NULL || sax->float_val == NULL ||
|
|
1041
|
+
sax->str_val == NULL || sax->bytes_val == NULL || sax->open == NULL || sax->close == NULL) {
|
|
1042
|
+
if (status != NULL) {
|
|
1043
|
+
*status = YEPTRIS_ERROR_ARG;
|
|
1044
|
+
}
|
|
1045
|
+
return YEPTRIS_ERROR_ARG;
|
|
1046
|
+
}
|
|
1047
|
+
/* yeptris_cbor_sax IS yep_cbor_sink (sink.h aliases the public
|
|
1048
|
+
* face): the decoder drives the caller's vtable directly. */
|
|
1049
|
+
YeptrisStatus st = (YeptrisStatus)yep_cbor_decode_gen((const unsigned char*)buf, len,
|
|
1050
|
+
(opts & YEPTRIS_CBOR_STRICT) != 0,
|
|
1051
|
+
consumed, (const yep_cbor_sink*)sax);
|
|
1052
|
+
if (status != NULL) {
|
|
1053
|
+
*status = st;
|
|
1054
|
+
}
|
|
1055
|
+
return st;
|
|
1056
|
+
}
|
|
@@ -4,7 +4,11 @@
|
|
|
4
4
|
* source of CBOR semantics; a sink implements the item constructors
|
|
5
5
|
* on top of it. Two sinks exist: the DOM builder (the default, the
|
|
6
6
|
* yeptris_cbor_decode public path) and the native ext's VALUE builder
|
|
7
|
-
* (one pass, no intermediate).
|
|
7
|
+
* (one pass, no intermediate). The sink vtable IS the public SAX face
|
|
8
|
+
* (yeptris_cbor_sax, <yeptris/cbor.h> — #742): the alias keeps the
|
|
9
|
+
* decoder driving the same layout the public entry hands over, so
|
|
10
|
+
* yeptris_cbor_decode_sax is a straight passthrough. Callback/field
|
|
11
|
+
* contracts are documented there; sinks receive the resolver's tag_id
|
|
8
12
|
* and the pending semantic-tag chain in its text form ("N N N",
|
|
9
13
|
* outermost first — NULL when the item carries no chain).
|
|
10
14
|
*/
|
|
@@ -15,35 +19,9 @@
|
|
|
15
19
|
#include <stdint.h>
|
|
16
20
|
|
|
17
21
|
#include <yeptris/api.h> /* YEPTRIS_API (the ext links these) */
|
|
22
|
+
#include <yeptris/cbor.h>
|
|
18
23
|
|
|
19
|
-
typedef
|
|
20
|
-
void* ctx;
|
|
21
|
-
/* All callbacks return 0 on sink failure (the decoder reports
|
|
22
|
-
* MEMORY). They may raise through host languages (longjmp): the
|
|
23
|
-
* decoder owns no host-managed state across them except the
|
|
24
|
-
* indefinite buffer, which its own exit paths free. */
|
|
25
|
-
/* is_key: 1 = the item lands in the enclosing map's key slot
|
|
26
|
-
* (sinks key-intern strings; the DOM ignores it). Rendered text:
|
|
27
|
-
* numbers-as-text, false/true/null/undefined, simple(N) — the
|
|
28
|
-
* exact bytes the DOM path stores. */
|
|
29
|
-
int (*text)(void* ctx, const char* s, uint32_t n, uint8_t tag_id, int is_key, const char* tag,
|
|
30
|
-
uint32_t tag_len);
|
|
31
|
-
/* Known integers: value = negative ? -(mag) : mag, mag <= 2^63. */
|
|
32
|
-
int (*int_val)(void* ctx, int negative, uint64_t mag, int is_key, const char* tag,
|
|
33
|
-
uint32_t tag_len);
|
|
34
|
-
int (*float_val)(void* ctx, double dv, int is_key, const char* tag, uint32_t tag_len);
|
|
35
|
-
/* Strings. borrowed: 1 = p is the input (a sink may record the
|
|
36
|
-
* offset), 0 = the decoder's scratch buffer (copy or take it). */
|
|
37
|
-
int (*str_val)(void* ctx, const unsigned char* p, uint32_t n, int borrowed, int is_key,
|
|
38
|
-
const char* tag, uint32_t tag_len);
|
|
39
|
-
int (*bytes_val)(void* ctx, const unsigned char* p, uint32_t n, int borrowed, int is_key,
|
|
40
|
-
const char* tag, uint32_t tag_len);
|
|
41
|
-
/* Containers. cap: expected item count (maps: pairs*2), UINT64_MAX
|
|
42
|
-
* for indefinite. close fires for BOTH the definite-complete and
|
|
43
|
-
* the break paths, after the last child. */
|
|
44
|
-
int (*open)(void* ctx, int is_map, uint64_t cap, const char* tag, uint32_t tag_len);
|
|
45
|
-
int (*close)(void* ctx, int is_map);
|
|
46
|
-
} yep_cbor_sink;
|
|
24
|
+
typedef yeptris_cbor_sax yep_cbor_sink;
|
|
47
25
|
|
|
48
26
|
/* The generic engine: the grammar, driving `sink`. Same reject/
|
|
49
27
|
* encoding/depth semantics as the DOM entry. */
|
|
@@ -72,6 +72,16 @@ void yep_val_put(yep_value_ctx* c, const YeptrisValue* v) {
|
|
|
72
72
|
void yep_val_slot(yep_value_ctx* c, YeptrisValue* v) {
|
|
73
73
|
if (c->depth > 0 && c->depth <= YEP_V_MAX_DEPTH) {
|
|
74
74
|
int di = c->depth - 1;
|
|
75
|
+
if (c->is_seq[di]) {
|
|
76
|
+
/* a sequence entry never takes a key slot — the toggle
|
|
77
|
+
* flagged every ODD-position entry is_key=1, and the
|
|
78
|
+
* marshal strict-dup scan then false-flagged arrays with a
|
|
79
|
+
* repeated value at two odd positions ("[\"a\",\"b\",\"a\"]"
|
|
80
|
+
* = "duplicate key in object"; yeptris-ruby#333, the
|
|
81
|
+
* yeptris#680 class resurfacing through the value
|
|
82
|
+
* stream's own parity) */
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
75
85
|
if (c->key_pend[di] == 0) {
|
|
76
86
|
v->is_key = 1;
|
|
77
87
|
c->key_pend[di] = 1;
|
|
@@ -169,6 +179,7 @@ static int transform(yep_value_ctx* c, const yep_rec_store* store) {
|
|
|
169
179
|
yep_val_put(c, &v);
|
|
170
180
|
if (c->depth < YEP_V_MAX_DEPTH) {
|
|
171
181
|
c->key_pend[c->depth] = 0;
|
|
182
|
+
c->is_seq[c->depth] = 1;
|
|
172
183
|
}
|
|
173
184
|
c->depth++;
|
|
174
185
|
continue;
|
|
@@ -179,6 +190,7 @@ static int transform(yep_value_ctx* c, const yep_rec_store* store) {
|
|
|
179
190
|
yep_val_put(c, &v);
|
|
180
191
|
if (c->depth < YEP_V_MAX_DEPTH) {
|
|
181
192
|
c->key_pend[c->depth] = 0;
|
|
193
|
+
c->is_seq[c->depth] = 0;
|
|
182
194
|
}
|
|
183
195
|
c->depth++;
|
|
184
196
|
continue;
|
|
@@ -285,6 +297,7 @@ static int lin_node(yep_value_ctx* c, const yep_dom* d, uint32_t id) {
|
|
|
285
297
|
yep_val_put(c, &v);
|
|
286
298
|
if (c->depth < YEP_V_MAX_DEPTH) {
|
|
287
299
|
c->key_pend[c->depth] = 0;
|
|
300
|
+
c->is_seq[c->depth] = (n->kind == YEP_DOM_SEQUENCE);
|
|
288
301
|
}
|
|
289
302
|
c->depth++;
|
|
290
303
|
if (lin_children(c, d, n) != 0) {
|
|
@@ -24,6 +24,8 @@ typedef struct yep_value_ctx {
|
|
|
24
24
|
int oom;
|
|
25
25
|
int unsupported; /* linearize: construct the emitter cannot express */
|
|
26
26
|
uint8_t key_pend[YEP_V_MAX_DEPTH]; /* per open map: key slot taken */
|
|
27
|
+
uint8_t is_seq[YEP_V_MAX_DEPTH]; /* per open frame: 1 = sequence —
|
|
28
|
+
* entries never take key slots */
|
|
27
29
|
int depth;
|
|
28
30
|
} yep_value_ctx;
|
|
29
31
|
|