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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ca812104ece12895a17969eea5c870837070875b8c59917220adea228f24cab2
4
- data.tar.gz: c46bd5d0d161b9e8e0337daf5af42f9fcc37ec41401a2d9fb3c5416e2ce2fccc
3
+ metadata.gz: d90ba7b2698041767008afd20cef0dbd6ba1af0d97affa2253b12e199e6c528d
4
+ data.tar.gz: f9a8219f0b6f66ef0608136068d78cbc6c8b1ee765bfaa68eeb828cae1401fd8
5
5
  SHA512:
6
- metadata.gz: 860134683a2d535fc9dfd17eb6ad369855ede35c0474dd386d9a8a3fb80e1a5d9cf2133d04c6ebea84d65ad127b62a2e83adf4f5166db8cbdf0dadf50f9d3984
7
- data.tar.gz: cac281da136cf4a336245105eb847ec369e36b09ec8f48e80e3e48bacd0aacc6052d88b1cdca3a912f82f329444fa6c74e02e3ee5f9c56b6002afafbd65611ca
6
+ metadata.gz: e72d7030911b6609946437de78aaf4fa9003a598c77dca472c2998f9af6115436e817fb4c46ec0ead55cb1ccb0ba80298c2ab060fab9fe37d0ec825d0ec6e5e4
7
+ data.tar.gz: 4aacdb9f034a2548a3eb942b4a29fb66a9839a63770bd10d0b8b62d93d944070d78ee53ca26881f05108047cc9c120efb3a732048b0be51a608f144f2ad0a374
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 3.13.22 - 2022-11-01
4
+
5
+ - Reorganized Oj::Parser code to allow for parser extensions in C.
6
+
3
7
  ## 3.13.21 - 2022-08-19
4
8
 
5
9
  - Bug parsing big numbers fixed in the SAJ parser.
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 * str = RSTRING_PTR(rstr);
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 * str = RSTRING_PTR(rstr);
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 * idp;
376
- AttrGetFunc * fp;
370
+ ID *idp;
371
+ AttrGetFunc *fp;
377
372
  volatile VALUE v;
378
- const char * name;
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 sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
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 * s;
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 sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
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 * key = kval->key;
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
- volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
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
- rkey = rb_utf8_str_new(key, klen);
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
- int64_t t = (int64_t)(ni->i + ni->exp);
1012
- struct _timeInfo ti;
1013
- VALUE args[8];
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
- switch (leaf->value_type) {
681
- case COL_VAL:
682
- if (NULL != leaf->elements) {
683
- Leaf first = leaf->elements->next;
684
- Leaf e = first;
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
- do {
687
- mark_leaf(e);
688
- e = e->next;
689
- } while (e != first);
690
- }
691
- break;
692
- case RUBY_VAL: mark(leaf->value); break;
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
- default: break;
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 = cache_create(0, form_attr, false, true);
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(str_cache, key, len);
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
- return cache_intern(sym_cache, key, len);
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
- return cache_intern(attr_cache, key, len);
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) {
@@ -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 n = 0;
70
+ int n = 0;
71
71
  char c;
72
- int i;
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 args[8];
86
+ VALUE args[8];
87
87
  const char *end = str + len;
88
- int n;
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
- int64_t t = (int64_t)(ni->i + ni->exp);
273
- struct _timeInfo ti;
274
- VALUE args[8];
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
- // Create a properly initialized struct instance without calling the initialize method.
337
- parent->val = rb_obj_alloc(sc);
338
- // If the JSON array has more entries than the struct class allows, we record an error.
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
- slen = (int)RSTRUCT_LEN(parent->val);
337
+ slen = (int)RSTRUCT_LEN(parent->val);
344
338
  #endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
345
339
  #else
346
- slen = FIX2INT(rb_funcall2(parent->val, oj_length_id, 0, 0));
340
+ slen = FIX2INT(rb_funcall2(parent->val, oj_length_id, 0, 0));
347
341
  #endif
348
- // MRI >= 1.9
349
- if (len - 1 > slen) {
350
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data");
351
- } else {
352
- int i;
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
- for (i = 0; i < len - 1; i++) {
355
- rb_struct_aset(parent->val, INT2FIX(i), RARRAY_PTR(value)[i + 1]);
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
- rb_ivar_set(parent->val, oj_attr_intern(kval->key, kval->klen), value);
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 * key = kval->key;
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 * key = kval->key;
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 (TYPE(v) == T_STRUCT && rb_obj_class(v) == rb_cRange) {
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 */