oj 3.13.21 → 3.13.22
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/CHANGELOG.md +4 -0
- data/README.md +2 -0
- data/ext/oj/custom.c +21 -40
- data/ext/oj/fast.c +15 -13
- data/ext/oj/intern.c +6 -9
- data/ext/oj/introspect.c +96 -0
- data/ext/oj/object.c +33 -32
- data/ext/oj/oj.c +9 -1
- data/ext/oj/oj.h +3 -0
- data/ext/oj/parser.c +26 -0
- data/ext/oj/parser.h +11 -0
- data/ext/oj/saj2.c +56 -62
- data/ext/oj/saj2.h +23 -0
- data/ext/oj/usual.c +82 -129
- data/ext/oj/usual.h +68 -0
- data/ext/oj/val_stack.c +1 -1
- data/lib/oj/state.rb +1 -1
- data/lib/oj/version.rb +1 -1
- data/test/json_gem/json_generator_test.rb +3 -4
- data/test/json_gem/json_parser_test.rb +1 -3
- data/test/test_custom.rb +9 -10
- data/test/test_file.rb +3 -10
- data/test/test_gc.rb +0 -2
- data/test/test_integer_range.rb +0 -6
- data/test/test_object.rb +3 -48
- data/test/test_parser.rb +3 -19
- data/test/test_parser_debug.rb +27 -0
- data/test/test_scp.rb +2 -4
- data/test/test_various.rb +2 -3
- data/test/tests.rb +9 -0
- data/test/tests_mimic.rb +9 -0
- data/test/tests_mimic_addition.rb +9 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d90ba7b2698041767008afd20cef0dbd6ba1af0d97affa2253b12e199e6c528d
|
4
|
+
data.tar.gz: f9a8219f0b6f66ef0608136068d78cbc6c8b1ee765bfaa68eeb828cae1401fd8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e72d7030911b6609946437de78aaf4fa9003a598c77dca472c2998f9af6115436e817fb4c46ec0ead55cb1ccb0ba80298c2ab060fab9fe37d0ec825d0ec6e5e4
|
7
|
+
data.tar.gz: 4aacdb9f034a2548a3eb942b4a29fb66a9839a63770bd10d0b8b62d93d944070d78ee53ca26881f05108047cc9c120efb3a732048b0be51a608f144f2ad0a374
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -109,6 +109,8 @@ Follow [@peterohler on Twitter](http://twitter.com/peterohler) for announcements
|
|
109
109
|
|
110
110
|
- *Agoo-C, a high performance C web server supporting GraphQL on GitHub*: https://github.com/ohler55/agoo-c
|
111
111
|
|
112
|
+
- *oj-introspect, an example of creating an Oj parser extension in C*: https://github.com/meinac/oj-introspect
|
113
|
+
|
112
114
|
#### Contributing
|
113
115
|
|
114
116
|
+ Provide a Pull Request off the `develop` branch.
|
data/ext/oj/custom.c
CHANGED
@@ -31,14 +31,14 @@ static void dump_obj_str(VALUE obj, int depth, Out out) {
|
|
31
31
|
|
32
32
|
static void dump_obj_as_str(VALUE obj, int depth, Out out) {
|
33
33
|
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
34
|
-
const char
|
34
|
+
const char *str = RSTRING_PTR(rstr);
|
35
35
|
|
36
36
|
oj_dump_cstr(str, RSTRING_LEN(rstr), 0, 0, out);
|
37
37
|
}
|
38
38
|
|
39
39
|
static void bigdecimal_dump(VALUE obj, int depth, Out out) {
|
40
40
|
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
41
|
-
const char
|
41
|
+
const char *str = RSTRING_PTR(rstr);
|
42
42
|
int len = (int)RSTRING_LEN(rstr);
|
43
43
|
|
44
44
|
if (0 == strcasecmp("Infinity", str)) {
|
@@ -82,8 +82,7 @@ static VALUE complex_load(VALUE clas, VALUE args) {
|
|
82
82
|
real_id = rb_intern("real");
|
83
83
|
imag_id = rb_intern("imag");
|
84
84
|
}
|
85
|
-
return rb_complex_new(rb_hash_aref(args, rb_id2str(real_id)),
|
86
|
-
rb_hash_aref(args, rb_id2str(imag_id)));
|
85
|
+
return rb_complex_new(rb_hash_aref(args, rb_id2str(real_id)), rb_hash_aref(args, rb_id2str(imag_id)));
|
87
86
|
}
|
88
87
|
|
89
88
|
static void time_dump(VALUE obj, int depth, Out out) {
|
@@ -246,8 +245,7 @@ static VALUE rational_load(VALUE clas, VALUE args) {
|
|
246
245
|
numerator_id = rb_intern("numerator");
|
247
246
|
denominator_id = rb_intern("denominator");
|
248
247
|
}
|
249
|
-
return rb_rational_new(rb_hash_aref(args, rb_id2str(numerator_id)),
|
250
|
-
rb_hash_aref(args, rb_id2str(denominator_id)));
|
248
|
+
return rb_rational_new(rb_hash_aref(args, rb_id2str(numerator_id)), rb_hash_aref(args, rb_id2str(denominator_id)));
|
251
249
|
}
|
252
250
|
|
253
251
|
static VALUE regexp_load(VALUE clas, VALUE args) {
|
@@ -292,8 +290,7 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
|
|
292
290
|
assure_size(out, depth * out->indent + 1);
|
293
291
|
fill_indent(out, depth);
|
294
292
|
} else {
|
295
|
-
assure_size(out,
|
296
|
-
depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1);
|
293
|
+
assure_size(out, depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1);
|
297
294
|
if (0 < out->opts->dump_opts.hash_size) {
|
298
295
|
APPEND_CHARS(out->cur, out->opts->dump_opts.hash_nl, out->opts->dump_opts.hash_size);
|
299
296
|
}
|
@@ -352,9 +349,7 @@ static void dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
|
|
352
349
|
assure_size(out, depth * out->indent + 2);
|
353
350
|
fill_indent(out, depth);
|
354
351
|
} else {
|
355
|
-
assure_size(
|
356
|
-
out,
|
357
|
-
depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1);
|
352
|
+
assure_size(out, depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1);
|
358
353
|
if (0 < out->opts->dump_opts.hash_size) {
|
359
354
|
APPEND_CHARS(out->cur, out->opts->dump_opts.hash_nl, out->opts->dump_opts.hash_size);
|
360
355
|
}
|
@@ -372,10 +367,10 @@ static void dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
|
|
372
367
|
}
|
373
368
|
|
374
369
|
static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
|
375
|
-
ID
|
376
|
-
AttrGetFunc
|
370
|
+
ID *idp;
|
371
|
+
AttrGetFunc *fp;
|
377
372
|
volatile VALUE v;
|
378
|
-
const char
|
373
|
+
const char *name;
|
379
374
|
size_t size;
|
380
375
|
int d2 = depth + 1;
|
381
376
|
|
@@ -384,7 +379,7 @@ static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
|
|
384
379
|
if (NULL != out->opts->create_id && Yes == out->opts->create_ok) {
|
385
380
|
const char *classname = rb_class2name(clas);
|
386
381
|
int clen = (int)strlen(classname);
|
387
|
-
size_t
|
382
|
+
size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
|
388
383
|
|
389
384
|
size = d2 * out->indent + 10 + clen + out->opts->create_id_len + sep_len;
|
390
385
|
assure_size(out, size);
|
@@ -481,7 +476,7 @@ static VALUE dump_common(VALUE obj, int depth, Out out) {
|
|
481
476
|
oj_dump_raw_json(obj, depth, out);
|
482
477
|
} else if (Yes == out->opts->to_json && rb_respond_to(obj, oj_to_json_id)) {
|
483
478
|
volatile VALUE rs;
|
484
|
-
const char
|
479
|
+
const char *s;
|
485
480
|
int len;
|
486
481
|
|
487
482
|
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
@@ -521,11 +516,7 @@ static VALUE dump_common(VALUE obj, int depth, Out out) {
|
|
521
516
|
if (aj == obj) {
|
522
517
|
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
523
518
|
|
524
|
-
oj_dump_cstr(RSTRING_PTR(rstr),
|
525
|
-
(int)RSTRING_LEN(rstr),
|
526
|
-
false,
|
527
|
-
false,
|
528
|
-
out);
|
519
|
+
oj_dump_cstr(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), false, false, out);
|
529
520
|
} else {
|
530
521
|
oj_dump_custom_val(aj, depth, out, true);
|
531
522
|
}
|
@@ -609,7 +600,7 @@ static void dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out)
|
|
609
600
|
assure_size(out, 2);
|
610
601
|
*out->cur++ = '{';
|
611
602
|
if (Qundef != clas && NULL != out->opts->create_id && Yes == out->opts->create_ok) {
|
612
|
-
size_t
|
603
|
+
size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
|
613
604
|
const char *classname = rb_obj_classname(obj);
|
614
605
|
size_t len = strlen(classname);
|
615
606
|
|
@@ -911,7 +902,7 @@ void oj_dump_custom_val(VALUE obj, int depth, Out out, bool as_ok) {
|
|
911
902
|
///// load functions /////
|
912
903
|
|
913
904
|
static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
|
914
|
-
const char
|
905
|
+
const char *key = kval->key;
|
915
906
|
int klen = kval->klen;
|
916
907
|
Val parent = stack_peek(&pi->stack);
|
917
908
|
volatile VALUE rkey = kval->key_val;
|
@@ -928,14 +919,14 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c
|
|
928
919
|
}
|
929
920
|
}
|
930
921
|
} else {
|
931
|
-
|
932
|
-
//volatile VALUE rstr = rb_utf8_str_new(str, len);
|
922
|
+
volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
|
923
|
+
// volatile VALUE rstr = rb_utf8_str_new(str, len);
|
933
924
|
|
934
925
|
if (Qundef == rkey) {
|
935
926
|
if (Yes == pi->options.sym_key) {
|
936
927
|
rkey = ID2SYM(rb_intern3(key, klen, oj_utf8_encoding));
|
937
928
|
} else {
|
938
|
-
|
929
|
+
rkey = rb_utf8_str_new(key, klen);
|
939
930
|
}
|
940
931
|
}
|
941
932
|
if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
|
@@ -1008,20 +999,10 @@ static void hash_set_num(struct _parseInfo *pi, Val kval, NumInfo ni) {
|
|
1008
999
|
// match the expected value.
|
1009
1000
|
parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
|
1010
1001
|
} else if (ni->has_exp) {
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
sec_as_time(t, &ti);
|
1016
|
-
|
1017
|
-
args[0] = LONG2NUM(ti.year);
|
1018
|
-
args[1] = LONG2NUM(ti.mon);
|
1019
|
-
args[2] = LONG2NUM(ti.day);
|
1020
|
-
args[3] = LONG2NUM(ti.hour);
|
1021
|
-
args[4] = LONG2NUM(ti.min);
|
1022
|
-
args[5] = rb_float_new((double)ti.sec + ((double)nsec + 0.5) / 1000000000.0);
|
1023
|
-
args[6] = LONG2NUM(ni->exp);
|
1024
|
-
parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args);
|
1002
|
+
struct timespec ts;
|
1003
|
+
ts.tv_sec = ni->i;
|
1004
|
+
ts.tv_nsec = nsec;
|
1005
|
+
parent->val = rb_time_timespec_new(&ts, (int)ni->exp);
|
1025
1006
|
} else {
|
1026
1007
|
parent->val = rb_time_nano_new(ni->i, (long)nsec);
|
1027
1008
|
}
|
data/ext/oj/fast.c
CHANGED
@@ -677,21 +677,23 @@ static void free_doc_cb(void *x) {
|
|
677
677
|
}
|
678
678
|
|
679
679
|
static void mark_leaf(Leaf leaf) {
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
680
|
+
if (NULL != leaf) {
|
681
|
+
switch (leaf->value_type) {
|
682
|
+
case COL_VAL:
|
683
|
+
if (NULL != leaf->elements) {
|
684
|
+
Leaf first = leaf->elements->next;
|
685
|
+
Leaf e = first;
|
685
686
|
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
687
|
+
do {
|
688
|
+
mark_leaf(e);
|
689
|
+
e = e->next;
|
690
|
+
} while (e != first);
|
691
|
+
}
|
692
|
+
break;
|
693
|
+
case RUBY_VAL: mark(leaf->value); break;
|
693
694
|
|
694
|
-
|
695
|
+
default: break;
|
696
|
+
}
|
695
697
|
}
|
696
698
|
}
|
697
699
|
|
data/ext/oj/intern.c
CHANGED
@@ -37,13 +37,10 @@ typedef struct _hash {
|
|
37
37
|
struct _hash class_hash;
|
38
38
|
struct _hash attr_hash;
|
39
39
|
|
40
|
-
static struct _cache *str_cache = NULL;
|
41
40
|
static VALUE str_cache_obj;
|
42
41
|
|
43
|
-
static struct _cache *sym_cache = NULL;
|
44
42
|
static VALUE sym_cache_obj;
|
45
43
|
|
46
|
-
static struct _cache *attr_cache = NULL;
|
47
44
|
static VALUE attr_cache_obj;
|
48
45
|
|
49
46
|
static VALUE form_str(const char *str, size_t len) {
|
@@ -93,15 +90,15 @@ void oj_hash_init(void) {
|
|
93
90
|
rb_gc_register_address(&cache_class);
|
94
91
|
rb_undef_alloc_func(cache_class);
|
95
92
|
|
96
|
-
str_cache = cache_create(0, form_str, true, true);
|
93
|
+
struct _cache *str_cache = cache_create(0, form_str, true, true);
|
97
94
|
str_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, str_cache);
|
98
95
|
rb_gc_register_address(&str_cache_obj);
|
99
96
|
|
100
|
-
sym_cache = cache_create(0, form_sym, true, true);
|
97
|
+
struct _cache *sym_cache = cache_create(0, form_sym, true, true);
|
101
98
|
sym_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, sym_cache);
|
102
99
|
rb_gc_register_address(&sym_cache_obj);
|
103
100
|
|
104
|
-
attr_cache
|
101
|
+
struct _cache *attr_cache = cache_create(0, form_attr, false, true);
|
105
102
|
attr_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, attr_cache);
|
106
103
|
rb_gc_register_address(&attr_cache_obj);
|
107
104
|
|
@@ -122,18 +119,18 @@ oj_str_intern(const char *key, size_t len) {
|
|
122
119
|
#if HAVE_RB_ENC_INTERNED_STR && 0
|
123
120
|
return rb_enc_interned_str(key, len, rb_utf8_encoding());
|
124
121
|
#else
|
125
|
-
return cache_intern(
|
122
|
+
return cache_intern(DATA_PTR(str_cache_obj), key, len);
|
126
123
|
#endif
|
127
124
|
}
|
128
125
|
|
129
126
|
VALUE
|
130
127
|
oj_sym_intern(const char *key, size_t len) {
|
131
|
-
|
128
|
+
return cache_intern(DATA_PTR(sym_cache_obj), key, len);
|
132
129
|
}
|
133
130
|
|
134
131
|
ID
|
135
132
|
oj_attr_intern(const char *key, size_t len) {
|
136
|
-
|
133
|
+
return cache_intern(DATA_PTR(attr_cache_obj), key, len);
|
137
134
|
}
|
138
135
|
|
139
136
|
static uint64_t hash_calc(const uint8_t *key, size_t len) {
|
data/ext/oj/introspect.c
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
|
2
|
+
#include "cache.h"
|
3
|
+
#include "oj.h"
|
4
|
+
#include "parser.h"
|
5
|
+
#include "usual.h"
|
6
|
+
|
7
|
+
#define BYTE_OFFSETS_STACK_INC_SIZE 256
|
8
|
+
|
9
|
+
VALUE mod = Qnil;
|
10
|
+
|
11
|
+
typedef struct _introspect {
|
12
|
+
struct _usual usual;
|
13
|
+
void (*start)(struct _ojParser *p);
|
14
|
+
void (*free)(struct _ojParser *p);
|
15
|
+
void (*mark)(struct _ojParser *p);
|
16
|
+
void (*open_object)(struct _ojParser *p);
|
17
|
+
void (*close_object)(struct _ojParser *p);
|
18
|
+
|
19
|
+
int len;
|
20
|
+
int cur;
|
21
|
+
long *stack;
|
22
|
+
|
23
|
+
} * Introspect;
|
24
|
+
|
25
|
+
static void dfree(ojParser p) {
|
26
|
+
Introspect d = (Introspect)p->ctx;
|
27
|
+
|
28
|
+
xfree(d->stack);
|
29
|
+
// As with the mark() function, this function should still work.
|
30
|
+
d->free(p);
|
31
|
+
}
|
32
|
+
|
33
|
+
static void start(ojParser p) {
|
34
|
+
Introspect d = (Introspect)p->ctx;
|
35
|
+
|
36
|
+
d->start(p);
|
37
|
+
|
38
|
+
d->stack = ALLOC_N(long, BYTE_OFFSETS_STACK_INC_SIZE);
|
39
|
+
d->len = BYTE_OFFSETS_STACK_INC_SIZE;
|
40
|
+
d->cur = 0;
|
41
|
+
}
|
42
|
+
|
43
|
+
static void open_object(ojParser p) {
|
44
|
+
Introspect d = (Introspect)p->ctx;
|
45
|
+
|
46
|
+
d->open_object(p);
|
47
|
+
|
48
|
+
// TBD add offset
|
49
|
+
}
|
50
|
+
|
51
|
+
static void close_object(ojParser p) {
|
52
|
+
Introspect d = (Introspect)p->ctx;
|
53
|
+
|
54
|
+
d->close_object(p);
|
55
|
+
|
56
|
+
// TBD set offset on hash
|
57
|
+
}
|
58
|
+
|
59
|
+
static VALUE new_parser(VALUE self, VALUE ropts) {
|
60
|
+
volatile VALUE pv = oj_parser_new();
|
61
|
+
ojParser p = (ojParser)DATA_PTR(pv);
|
62
|
+
Introspect d = ALLOC(struct _introspect);
|
63
|
+
|
64
|
+
oj_init_usual(p, &d->usual);
|
65
|
+
|
66
|
+
// Set the options before switching to the Introspect delegate.
|
67
|
+
p->ctx = (void *)d;
|
68
|
+
|
69
|
+
d->free = p->free;
|
70
|
+
p->free = dfree;
|
71
|
+
|
72
|
+
d->start = p->start;
|
73
|
+
p->start = start;
|
74
|
+
|
75
|
+
// We are cheating with the mark, free, and options functions. Since
|
76
|
+
// struct _usual is the first member of struct _introspect the cast to
|
77
|
+
// Usual in the usual.c mark() function should still work just fine.
|
78
|
+
|
79
|
+
d->open_object = p->funcs[TOP_FUN].open_object;
|
80
|
+
p->funcs[TOP_FUN].open_object = open_object;
|
81
|
+
|
82
|
+
d->close_object = p->funcs[TOP_FUN].close_object;
|
83
|
+
p->funcs[TOP_FUN].close_object = close_object;
|
84
|
+
|
85
|
+
Check_Type(ropts, T_HASH);
|
86
|
+
oj_parser_set_option(p, ropts);
|
87
|
+
|
88
|
+
return pv;
|
89
|
+
}
|
90
|
+
|
91
|
+
void Init_introspect(void) {
|
92
|
+
mod = rb_define_module("Introspect");
|
93
|
+
rb_gc_register_address(&mod);
|
94
|
+
|
95
|
+
rb_define_module_function(mod, "parser", new_parser, 1);
|
96
|
+
}
|
data/ext/oj/object.c
CHANGED
@@ -67,9 +67,9 @@ static VALUE str_to_value(ParseInfo pi, const char *str, size_t len, const char
|
|
67
67
|
|
68
68
|
// The much faster approach (4x faster)
|
69
69
|
static int parse_num(const char *str, const char *end, int cnt) {
|
70
|
-
int
|
70
|
+
int n = 0;
|
71
71
|
char c;
|
72
|
-
int
|
72
|
+
int i;
|
73
73
|
|
74
74
|
for (i = cnt; 0 < i; i--, str++) {
|
75
75
|
c = *str;
|
@@ -83,9 +83,9 @@ static int parse_num(const char *str, const char *end, int cnt) {
|
|
83
83
|
|
84
84
|
VALUE
|
85
85
|
oj_parse_xml_time(const char *str, int len) {
|
86
|
-
VALUE
|
86
|
+
VALUE args[8];
|
87
87
|
const char *end = str + len;
|
88
|
-
int
|
88
|
+
int n;
|
89
89
|
|
90
90
|
// year
|
91
91
|
if (0 > (n = parse_num(str, end, 4))) {
|
@@ -269,19 +269,10 @@ static int hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
|
|
269
269
|
// match the expected value.
|
270
270
|
parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
|
271
271
|
} else if (ni->has_exp) {
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
sec_as_time(t, &ti);
|
277
|
-
args[0] = LONG2NUM((long)(ti.year));
|
278
|
-
args[1] = LONG2NUM(ti.mon);
|
279
|
-
args[2] = LONG2NUM(ti.day);
|
280
|
-
args[3] = LONG2NUM(ti.hour);
|
281
|
-
args[4] = LONG2NUM(ti.min);
|
282
|
-
args[5] = rb_float_new((double)ti.sec + ((double)nsec + 0.5) / 1000000000.0);
|
283
|
-
args[6] = LONG2NUM(ni->exp);
|
284
|
-
parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args);
|
272
|
+
struct timespec ts;
|
273
|
+
ts.tv_sec = ni->i;
|
274
|
+
ts.tv_nsec = nsec;
|
275
|
+
parent->val = rb_time_timespec_new(&ts, (int)ni->exp);
|
285
276
|
} else {
|
286
277
|
parent->val = rb_time_nano_new(ni->i, (long)nsec);
|
287
278
|
}
|
@@ -333,26 +324,30 @@ static int hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, vol
|
|
333
324
|
// If struct is not defined then we let this fail and raise an exception.
|
334
325
|
sc = oj_name2struct(pi, *RARRAY_PTR(value), rb_eArgError);
|
335
326
|
}
|
336
|
-
|
337
|
-
|
338
|
-
|
327
|
+
if (sc == rb_cRange) {
|
328
|
+
parent->val = rb_class_new_instance(len - 1, RARRAY_PTR(value) + 1, rb_cRange);
|
329
|
+
} else {
|
330
|
+
// Create a properly initialized struct instance without calling the initialize method.
|
331
|
+
parent->val = rb_obj_alloc(sc);
|
332
|
+
// If the JSON array has more entries than the struct class allows, we record an error.
|
339
333
|
#ifdef RSTRUCT_LEN
|
340
334
|
#if RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
341
335
|
slen = (int)NUM2LONG(RSTRUCT_LEN(parent->val));
|
342
336
|
#else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
343
|
-
|
337
|
+
slen = (int)RSTRUCT_LEN(parent->val);
|
344
338
|
#endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
345
339
|
#else
|
346
|
-
|
340
|
+
slen = FIX2INT(rb_funcall2(parent->val, oj_length_id, 0, 0));
|
347
341
|
#endif
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
342
|
+
// MRI >= 1.9
|
343
|
+
if (len - 1 > slen) {
|
344
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data");
|
345
|
+
} else {
|
346
|
+
int i;
|
353
347
|
|
354
|
-
|
355
|
-
|
348
|
+
for (i = 0; i < len - 1; i++) {
|
349
|
+
rb_struct_aset(parent->val, INT2FIX(i), RARRAY_PTR(value)[i + 1]);
|
350
|
+
}
|
356
351
|
}
|
357
352
|
}
|
358
353
|
return 1;
|
@@ -374,11 +369,17 @@ static int hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, vol
|
|
374
369
|
}
|
375
370
|
|
376
371
|
void oj_set_obj_ivar(Val parent, Val kval, VALUE value) {
|
377
|
-
|
372
|
+
if (kval->klen == 5 && strncmp("~mesg", kval->key, 5) == 0 && rb_obj_is_kind_of(parent->val, rb_eException)) {
|
373
|
+
parent->val = rb_funcall(parent->val, rb_intern("exception"), 1, value);
|
374
|
+
} else if (kval->klen == 3 && strncmp("~bt", kval->key, 3) == 0 && rb_obj_is_kind_of(parent->val, rb_eException)) {
|
375
|
+
rb_funcall(parent->val, rb_intern("set_backtrace"), 1, value);
|
376
|
+
} else {
|
377
|
+
rb_ivar_set(parent->val, oj_attr_intern(kval->key, kval->klen), value);
|
378
|
+
}
|
378
379
|
}
|
379
380
|
|
380
381
|
static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
|
381
|
-
const char
|
382
|
+
const char *key = kval->key;
|
382
383
|
int klen = kval->klen;
|
383
384
|
Val parent = stack_peek(&pi->stack);
|
384
385
|
volatile VALUE rval = Qnil;
|
@@ -451,7 +452,7 @@ WHICH_TYPE:
|
|
451
452
|
}
|
452
453
|
|
453
454
|
static void hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
|
454
|
-
const char
|
455
|
+
const char *key = kval->key;
|
455
456
|
int klen = kval->klen;
|
456
457
|
Val parent = stack_peek(&pi->stack);
|
457
458
|
volatile VALUE rval = Qnil;
|
data/ext/oj/oj.c
CHANGED
@@ -32,6 +32,7 @@ ID oj_array_append_id;
|
|
32
32
|
ID oj_array_end_id;
|
33
33
|
ID oj_array_start_id;
|
34
34
|
ID oj_as_json_id;
|
35
|
+
ID oj_at_id;
|
35
36
|
ID oj_begin_id;
|
36
37
|
ID oj_bigdecimal_id;
|
37
38
|
ID oj_end_id;
|
@@ -89,7 +90,9 @@ VALUE oj_array_class_sym;
|
|
89
90
|
VALUE oj_create_additions_sym;
|
90
91
|
VALUE oj_decimal_class_sym;
|
91
92
|
VALUE oj_hash_class_sym;
|
93
|
+
VALUE oj_in_sym;
|
92
94
|
VALUE oj_indent_sym;
|
95
|
+
VALUE oj_nanosecond_sym;
|
93
96
|
VALUE oj_object_class_sym;
|
94
97
|
VALUE oj_quirks_mode_sym;
|
95
98
|
VALUE oj_safe_sym;
|
@@ -929,7 +932,7 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
929
932
|
if (Qnil == v) {
|
930
933
|
return ST_CONTINUE;
|
931
934
|
}
|
932
|
-
if (
|
935
|
+
if (rb_obj_class(v) == rb_cRange) {
|
933
936
|
VALUE min = rb_funcall(v, oj_begin_id, 0);
|
934
937
|
VALUE max = rb_funcall(v, oj_end_id, 0);
|
935
938
|
|
@@ -1814,6 +1817,7 @@ void Init_oj(void) {
|
|
1814
1817
|
oj_array_end_id = rb_intern("array_end");
|
1815
1818
|
oj_array_start_id = rb_intern("array_start");
|
1816
1819
|
oj_as_json_id = rb_intern("as_json");
|
1820
|
+
oj_at_id = rb_intern("at");
|
1817
1821
|
oj_begin_id = rb_intern("begin");
|
1818
1822
|
oj_bigdecimal_id = rb_intern("BigDecimal");
|
1819
1823
|
oj_end_id = rb_intern("end");
|
@@ -1961,10 +1965,14 @@ void Init_oj(void) {
|
|
1961
1965
|
rb_gc_register_address(&oj_decimal_class_sym);
|
1962
1966
|
oj_hash_class_sym = ID2SYM(rb_intern("hash_class"));
|
1963
1967
|
rb_gc_register_address(&oj_hash_class_sym);
|
1968
|
+
oj_in_sym = ID2SYM(rb_intern("in"));
|
1969
|
+
rb_gc_register_address(&oj_in_sym);
|
1964
1970
|
oj_indent_sym = ID2SYM(rb_intern("indent"));
|
1965
1971
|
rb_gc_register_address(&oj_indent_sym);
|
1966
1972
|
oj_max_nesting_sym = ID2SYM(rb_intern("max_nesting"));
|
1967
1973
|
rb_gc_register_address(&oj_max_nesting_sym);
|
1974
|
+
oj_nanosecond_sym = ID2SYM(rb_intern("nanosecond"));
|
1975
|
+
rb_gc_register_address(&oj_nanosecond_sym);
|
1968
1976
|
oj_object_class_sym = ID2SYM(rb_intern("object_class"));
|
1969
1977
|
rb_gc_register_address(&oj_object_class_sym);
|
1970
1978
|
oj_object_nl_sym = ID2SYM(rb_intern("object_nl"));
|
data/ext/oj/oj.h
CHANGED
@@ -317,7 +317,9 @@ extern VALUE oj_ascii_only_sym;
|
|
317
317
|
extern VALUE oj_create_additions_sym;
|
318
318
|
extern VALUE oj_decimal_class_sym;
|
319
319
|
extern VALUE oj_hash_class_sym;
|
320
|
+
extern VALUE oj_in_sym;
|
320
321
|
extern VALUE oj_indent_sym;
|
322
|
+
extern VALUE oj_nanosecond_sym;
|
321
323
|
extern VALUE oj_max_nesting_sym;
|
322
324
|
extern VALUE oj_object_class_sym;
|
323
325
|
extern VALUE oj_object_nl_sym;
|
@@ -334,6 +336,7 @@ extern ID oj_array_append_id;
|
|
334
336
|
extern ID oj_array_end_id;
|
335
337
|
extern ID oj_array_start_id;
|
336
338
|
extern ID oj_as_json_id;
|
339
|
+
extern ID oj_at_id;
|
337
340
|
extern ID oj_begin_id;
|
338
341
|
extern ID oj_bigdecimal_id;
|
339
342
|
extern ID oj_end_id;
|
data/ext/oj/parser.c
CHANGED
@@ -1254,6 +1254,32 @@ static VALUE parser_new(int argc, VALUE *argv, VALUE self) {
|
|
1254
1254
|
return Data_Wrap_Struct(parser_class, parser_mark, parser_free, p);
|
1255
1255
|
}
|
1256
1256
|
|
1257
|
+
// Create a new parser without setting the delegate. The parser is
|
1258
|
+
// wrapped. The parser is (ojParser)DATA_PTR(value) where value is the return
|
1259
|
+
// from this function. A delegate must be added before the parser can be
|
1260
|
+
// used. Optionally oj_parser_set_options can be called if the options are not
|
1261
|
+
// set directly.
|
1262
|
+
VALUE oj_parser_new() {
|
1263
|
+
ojParser p = ALLOC(struct _ojParser);
|
1264
|
+
|
1265
|
+
#if HAVE_RB_EXT_RACTOR_SAFE
|
1266
|
+
// This doesn't seem to do anything.
|
1267
|
+
rb_ext_ractor_safe(true);
|
1268
|
+
#endif
|
1269
|
+
memset(p, 0, sizeof(struct _ojParser));
|
1270
|
+
buf_init(&p->key);
|
1271
|
+
buf_init(&p->buf);
|
1272
|
+
p->map = value_map;
|
1273
|
+
|
1274
|
+
return Data_Wrap_Struct(parser_class, parser_mark, parser_free, p);
|
1275
|
+
}
|
1276
|
+
|
1277
|
+
// Set set the options from a hash (ropts).
|
1278
|
+
void oj_parser_set_option(ojParser p, VALUE ropts) {
|
1279
|
+
Check_Type(ropts, T_HASH);
|
1280
|
+
rb_hash_foreach(ropts, opt_cb, (VALUE)p);
|
1281
|
+
}
|
1282
|
+
|
1257
1283
|
/* Document-method: method_missing(value)
|
1258
1284
|
* call-seq: method_missing(value)
|
1259
1285
|
*
|
data/ext/oj/parser.h
CHANGED
@@ -88,4 +88,15 @@ typedef struct _ojParser {
|
|
88
88
|
bool just_one;
|
89
89
|
} * ojParser;
|
90
90
|
|
91
|
+
// Create a new parser without setting the delegate. The parser is
|
92
|
+
// wrapped. The parser is (ojParser)DATA_PTR(value) where value is the return
|
93
|
+
// from this function. A delegate must be added before the parser can be
|
94
|
+
// used. Optionally oj_parser_set_options can be called if the options are not
|
95
|
+
// set directly.
|
96
|
+
extern VALUE oj_parser_new();
|
97
|
+
|
98
|
+
// Set set the options from a hash (ropts).
|
99
|
+
extern void oj_parser_set_option(ojParser p, VALUE ropts);
|
100
|
+
|
101
|
+
|
91
102
|
#endif /* OJ_PARSER_H */
|