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 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 */