oj 3.13.21 → 3.13.22
Sign up to get free protection for your applications and to get access to all the features.
- 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 */
|