yeptris 0.6.9.1 → 0.6.9.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/ext/yeptris_native/cbor_ruby.c +134 -0
- data/ext/yeptris_native/yeptris_native.c +14 -0
- data/lib/yeptris/cbor.rb +7 -0
- data/lib/yeptris.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 128c08457353396f6f709f8719256a3b3ce1463518456b34987f252314a0dda4
|
|
4
|
+
data.tar.gz: 9c20441656c1fdb05003d3e0fa0ee4af6d7d758d5505d387fb09dfb86d37e493
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a3db668d48f7febd05d6ab518c5696704a6673fe5b9e7dd2fab2ea3ea3fcb41e021cb41b3136ddc96f6d5540a8ee9e8cc6c37997ff4a56de719ec1e783fa7fa0
|
|
7
|
+
data.tar.gz: 4cb9c60fd78802cb49a97fffb1ce9fd27e047cd5204edf5c1e2621110613122babbac634d2a273a360029ea6c5df15bbdb7298fcb100c3fa53a66abb838bbf56
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/* cbor_ruby.c — CBOR decode → Ruby VALUE in one C pass (#157).
|
|
2
|
+
*
|
|
3
|
+
* The FFI ladder's CBOR.load pays decode + a Marshal emit/load round
|
|
4
|
+
* trip; this walks the decoded DOM directly, building the same VALUEs
|
|
5
|
+
* the materializer builds (tag-driven scalar semantics, insertion-
|
|
6
|
+
* order mappings), with no intermediate representation.
|
|
7
|
+
*/
|
|
8
|
+
#include <ruby.h>
|
|
9
|
+
/* rb_hash_new_capa is Ruby 3.2+; older Rubies grow dynamically (the
|
|
10
|
+
* json_ruby.c guard, verbatim). */
|
|
11
|
+
#if RUBY_API_VERSION_MAJOR > 3 || (RUBY_API_VERSION_MAJOR == 3 && RUBY_API_VERSION_MINOR >= 2)
|
|
12
|
+
#define HASH_NEW_CAPA(n) rb_hash_new_capa(n)
|
|
13
|
+
#else
|
|
14
|
+
#define HASH_NEW_CAPA(n) rb_hash_new()
|
|
15
|
+
#endif
|
|
16
|
+
#include <ruby/encoding.h>
|
|
17
|
+
#include <stdlib.h>
|
|
18
|
+
#include <string.h>
|
|
19
|
+
|
|
20
|
+
#include "dom/dom.h"
|
|
21
|
+
#include "doc.h" /* the public YeptrisDocument wrapper: ->dom */
|
|
22
|
+
#include <yeptris/cbor.h>
|
|
23
|
+
#include <yeptris/dom.h>
|
|
24
|
+
#include <yeptris/resolve.h>
|
|
25
|
+
|
|
26
|
+
static const char* cr_view(const yep_dom* d, yep_sview sv, uint32_t* len) {
|
|
27
|
+
*len = sv.len;
|
|
28
|
+
if (sv.len == 0) {
|
|
29
|
+
return "";
|
|
30
|
+
}
|
|
31
|
+
return (sv.off & YEP_SV_INPUT) ? (d->str + (sv.off & YEP_SV_OFF)) : (d->input_base + sv.off);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
static VALUE cr_scalar(const yep_dom* d, const yep_dnode* n) {
|
|
35
|
+
uint32_t len = 0;
|
|
36
|
+
const char* p = cr_view(d, n->value, &len);
|
|
37
|
+
switch (n->tag_id) {
|
|
38
|
+
case YEPTRIS_TAG_NULL:
|
|
39
|
+
return Qnil;
|
|
40
|
+
case YEPTRIS_TAG_BOOL:
|
|
41
|
+
if (len == 1) { /* Psych: "y"/"n" stay Strings */
|
|
42
|
+
return rb_utf8_str_new(p, len);
|
|
43
|
+
}
|
|
44
|
+
return (len == 4 && memcmp(p, "true", 4) == 0) ? Qtrue : Qfalse;
|
|
45
|
+
case YEPTRIS_TAG_INT: {
|
|
46
|
+
char buf[32];
|
|
47
|
+
size_t cp = len < sizeof(buf) - 1 ? len : sizeof(buf) - 1;
|
|
48
|
+
memcpy(buf, p, cp);
|
|
49
|
+
buf[cp] = '\0';
|
|
50
|
+
char* end = NULL;
|
|
51
|
+
long long v = strtoll(buf, &end, 10);
|
|
52
|
+
if (end != buf && *end == '\0' && end == buf + len && v > INT64_MIN) {
|
|
53
|
+
return LL2NUM(v);
|
|
54
|
+
}
|
|
55
|
+
return rb_utf8_str_new(p, len); /* int_or_string's fallback */
|
|
56
|
+
}
|
|
57
|
+
case YEPTRIS_TAG_FLOAT: {
|
|
58
|
+
char buf[64];
|
|
59
|
+
size_t cp = len < sizeof(buf) - 1 ? len : sizeof(buf) - 1;
|
|
60
|
+
memcpy(buf, p, cp);
|
|
61
|
+
buf[cp] = '\0';
|
|
62
|
+
char* end = NULL;
|
|
63
|
+
double v = strtod(buf, &end);
|
|
64
|
+
if (end != buf && end != buf + len) {
|
|
65
|
+
return rb_utf8_str_new(p, len); /* float_or_string's fallback */
|
|
66
|
+
}
|
|
67
|
+
return DBL2NUM(v);
|
|
68
|
+
}
|
|
69
|
+
default:
|
|
70
|
+
return rb_utf8_str_new(p, len);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
static VALUE cr_walk(const yep_dom* d, uint32_t id) {
|
|
75
|
+
const yep_dnode* n = &d->nodes[id];
|
|
76
|
+
switch (n->kind) {
|
|
77
|
+
case YEP_DOM_SCALAR:
|
|
78
|
+
return cr_scalar(d, n);
|
|
79
|
+
case YEP_DOM_SEQUENCE: {
|
|
80
|
+
long cnt = (long)n->count;
|
|
81
|
+
VALUE a = rb_ary_new_capa(cnt);
|
|
82
|
+
uint32_t c = n->first_child;
|
|
83
|
+
for (long i = 0; i < cnt && c != UINT32_MAX; i++) {
|
|
84
|
+
rb_ary_push(a, cr_walk(d, c));
|
|
85
|
+
c = d->nodes[c].next_sibling;
|
|
86
|
+
}
|
|
87
|
+
return a;
|
|
88
|
+
}
|
|
89
|
+
case YEP_DOM_MAPPING: {
|
|
90
|
+
long pairs = (long)(n->count / 2);
|
|
91
|
+
VALUE h = HASH_NEW_CAPA(pairs);
|
|
92
|
+
uint32_t c = n->first_child;
|
|
93
|
+
for (long i = 0; i < pairs && c != UINT32_MAX; i++) {
|
|
94
|
+
VALUE k = cr_walk(d, c);
|
|
95
|
+
c = d->nodes[c].next_sibling;
|
|
96
|
+
VALUE v = (c != UINT32_MAX) ? cr_walk(d, c) : Qnil;
|
|
97
|
+
if (c != UINT32_MAX) {
|
|
98
|
+
c = d->nodes[c].next_sibling;
|
|
99
|
+
}
|
|
100
|
+
rb_hash_aset(h, k, v);
|
|
101
|
+
}
|
|
102
|
+
return h;
|
|
103
|
+
}
|
|
104
|
+
default: /* ALIAS: CBOR decode never produces one */
|
|
105
|
+
return Qnil;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
VALUE yep_rb_cbor_load(const char* p, size_t len, int strict) {
|
|
110
|
+
YeptrisStatus st = YEPTRIS_OK;
|
|
111
|
+
/* the DOM borrows the input buffer zero-copy; the walk ALLOCATES,
|
|
112
|
+
* and a GC compaction mid-walk moves the caller's String — the
|
|
113
|
+
* borrowed base dangles (the #160 CI bus error on 3.2/linux).
|
|
114
|
+
* Same discipline as the JSON walk: GC off across decode+walk */
|
|
115
|
+
VALUE gc_on = rb_gc_disable();
|
|
116
|
+
/* YeptrisDocument is a WRAPPER (doc.h) — ->dom is the tree; a raw
|
|
117
|
+
* yep_dom* cast read the wrapper's fields as the dom (the CI
|
|
118
|
+
* segfaults: docs at the wrong offset) */
|
|
119
|
+
yeptris_document* doc = (yeptris_document*)yeptris_cbor_decode(
|
|
120
|
+
p, len, strict ? YEPTRIS_CBOR_STRICT : 0, &st);
|
|
121
|
+
yep_dom* d = (doc != NULL) ? doc->dom : NULL;
|
|
122
|
+
if (d == NULL) {
|
|
123
|
+
if (RTEST(gc_on)) {
|
|
124
|
+
rb_gc_enable();
|
|
125
|
+
}
|
|
126
|
+
return Qundef;
|
|
127
|
+
}
|
|
128
|
+
VALUE v = (d->dcount > 0 && d->docs[0] != UINT32_MAX) ? cr_walk(d, d->docs[0]) : Qnil;
|
|
129
|
+
yeptris_document_free((YeptrisDocument)doc);
|
|
130
|
+
if (RTEST(gc_on)) {
|
|
131
|
+
rb_gc_enable();
|
|
132
|
+
}
|
|
133
|
+
return v;
|
|
134
|
+
}
|
|
@@ -230,6 +230,7 @@ static const YeptrisVisitVTable k_vt = {
|
|
|
230
230
|
|
|
231
231
|
/* fused JSON→Ruby (json_ruby.c) — no vtable, beats JSON.parse */
|
|
232
232
|
VALUE yep_rb_parse_json(const char* p, size_t len, int strict_dup);
|
|
233
|
+
VALUE yep_rb_cbor_load(const char* p, size_t len, int strict);
|
|
233
234
|
|
|
234
235
|
static VALUE ctx_result(rb_ctx* c, YeptrisStatus st) {
|
|
235
236
|
if (st != YEPTRIS_OK || c->failed) {
|
|
@@ -244,6 +245,18 @@ static VALUE ctx_result(rb_ctx* c, YeptrisStatus st) {
|
|
|
244
245
|
return c->root;
|
|
245
246
|
}
|
|
246
247
|
|
|
248
|
+
static VALUE native_cbor_load(int argc, VALUE* argv, VALUE self) {
|
|
249
|
+
(void)self;
|
|
250
|
+
VALUE input, strict;
|
|
251
|
+
rb_scan_args(argc, argv, "11", &input, &strict);
|
|
252
|
+
StringValue(input);
|
|
253
|
+
VALUE v = yep_rb_cbor_load(RSTRING_PTR(input), (size_t)RSTRING_LEN(input), RTEST(strict));
|
|
254
|
+
if (v == Qundef) {
|
|
255
|
+
rb_raise(rb_path2class("Yeptris::ParseError"), "native cbor decode failed");
|
|
256
|
+
}
|
|
257
|
+
return v;
|
|
258
|
+
}
|
|
259
|
+
|
|
247
260
|
static VALUE native_load_json(int argc, VALUE* argv, VALUE self) {
|
|
248
261
|
(void)self;
|
|
249
262
|
VALUE input, strict;
|
|
@@ -415,6 +428,7 @@ RUBY_FUNC_EXPORTED void Init_native(void) {
|
|
|
415
428
|
VALUE mYep = rb_define_module("Yeptris");
|
|
416
429
|
VALUE mNat = rb_define_module_under(mYep, "Native");
|
|
417
430
|
rb_define_singleton_method(mNat, "load_json", native_load_json, -1);
|
|
431
|
+
rb_define_singleton_method(mNat, "cbor_load", native_cbor_load, -1);
|
|
418
432
|
rb_define_singleton_method(mNat, "load", native_load, 2);
|
|
419
433
|
rb_define_singleton_method(mNat, "load_stream", native_load_stream, 2);
|
|
420
434
|
rb_define_singleton_method(mNat, "gc_mode", native_gc_mode, 0);
|
data/lib/yeptris/cbor.rb
CHANGED
|
@@ -26,6 +26,13 @@ module Yeptris
|
|
|
26
26
|
def load(data, strict: false)
|
|
27
27
|
raise Error, "libyeptris has no CBOR support" unless available?
|
|
28
28
|
|
|
29
|
+
# #157: the native materializer (decode + direct VALUE
|
|
30
|
+
# construction in one C pass) when the extension is loaded;
|
|
31
|
+
# the FFI ladder otherwise
|
|
32
|
+
if defined?(::Yeptris::Native) && ::Yeptris::Native.respond_to?(:cbor_load)
|
|
33
|
+
return ::Yeptris::Native.cbor_load(data, strict)
|
|
34
|
+
end
|
|
35
|
+
|
|
29
36
|
doc_ptr = ::Yeptris::FFI.yeptris_cbor_decode(data, data.bytesize, strict ? STRICT : 0, nil)
|
|
30
37
|
raise ParseError, ::Yeptris::FFI.last_error_message if doc_ptr.null?
|
|
31
38
|
|
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.9.
|
|
6
|
+
VERSION = "0.6.9.2".freeze
|
|
7
7
|
# The error hierarchy lives in THIS file (the parent namespace's
|
|
8
8
|
# own file): nested constants do not trigger a parent-constant
|
|
9
9
|
# autoload, and the law forbids internal requires — defining the
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: yeptris
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.6.9.
|
|
4
|
+
version: 0.6.9.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -37,6 +37,7 @@ files:
|
|
|
37
37
|
- README.adoc
|
|
38
38
|
- ext/build_windows_native.rb
|
|
39
39
|
- ext/libyeptris/extconf.rb
|
|
40
|
+
- ext/yeptris_native/cbor_ruby.c
|
|
40
41
|
- ext/yeptris_native/extconf.rb
|
|
41
42
|
- ext/yeptris_native/json_ruby.c
|
|
42
43
|
- ext/yeptris_native/yeptris_native.c
|