oj 3.13.7 → 3.13.23

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.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +75 -0
  3. data/README.md +11 -0
  4. data/ext/oj/buf.h +4 -0
  5. data/ext/oj/circarray.c +1 -1
  6. data/ext/oj/code.c +15 -22
  7. data/ext/oj/compat.c +10 -10
  8. data/ext/oj/custom.c +66 -112
  9. data/ext/oj/dump.c +147 -184
  10. data/ext/oj/dump.h +25 -8
  11. data/ext/oj/dump_compat.c +47 -89
  12. data/ext/oj/dump_leaf.c +14 -58
  13. data/ext/oj/dump_object.c +72 -188
  14. data/ext/oj/dump_strict.c +19 -31
  15. data/ext/oj/encoder.c +43 -0
  16. data/ext/oj/extconf.rb +5 -4
  17. data/ext/oj/fast.c +36 -24
  18. data/ext/oj/intern.c +22 -12
  19. data/ext/oj/intern.h +1 -1
  20. data/ext/oj/mimic_json.c +74 -73
  21. data/ext/oj/object.c +54 -72
  22. data/ext/oj/odd.c +83 -63
  23. data/ext/oj/odd.h +13 -13
  24. data/ext/oj/oj.c +166 -175
  25. data/ext/oj/oj.h +25 -3
  26. data/ext/oj/parse.c +123 -79
  27. data/ext/oj/parse.h +2 -0
  28. data/ext/oj/parser.c +77 -21
  29. data/ext/oj/parser.h +12 -0
  30. data/ext/oj/rails.c +46 -70
  31. data/ext/oj/rails.h +1 -1
  32. data/ext/oj/reader.c +2 -0
  33. data/ext/oj/saj.c +11 -23
  34. data/ext/oj/saj2.c +333 -85
  35. data/ext/oj/saj2.h +23 -0
  36. data/ext/oj/sparse.c +4 -0
  37. data/ext/oj/stream_writer.c +3 -1
  38. data/ext/oj/strict.c +13 -13
  39. data/ext/oj/string_writer.c +12 -5
  40. data/ext/oj/usual.c +86 -131
  41. data/ext/oj/usual.h +68 -0
  42. data/ext/oj/val_stack.c +1 -1
  43. data/ext/oj/validate.c +21 -26
  44. data/ext/oj/wab.c +22 -27
  45. data/lib/oj/saj.rb +20 -6
  46. data/lib/oj/state.rb +1 -1
  47. data/lib/oj/version.rb +1 -1
  48. data/pages/Compatibility.md +1 -1
  49. data/pages/JsonGem.md +15 -0
  50. data/pages/Modes.md +6 -3
  51. data/pages/Options.md +6 -0
  52. data/pages/Rails.md +12 -0
  53. data/test/activesupport7/abstract_unit.rb +49 -0
  54. data/test/activesupport7/decoding_test.rb +125 -0
  55. data/test/activesupport7/encoding_test.rb +486 -0
  56. data/test/activesupport7/encoding_test_cases.rb +104 -0
  57. data/test/activesupport7/time_zone_test_helpers.rb +47 -0
  58. data/test/bar.rb +3 -8
  59. data/test/bug.rb +16 -0
  60. data/test/foo.rb +71 -7
  61. data/test/helper.rb +8 -2
  62. data/test/json_gem/json_generator_test.rb +5 -4
  63. data/test/json_gem/json_parser_test.rb +8 -1
  64. data/test/json_gem/test_helper.rb +7 -3
  65. data/test/perf_dump.rb +50 -0
  66. data/test/test_compat.rb +25 -0
  67. data/test/test_custom.rb +13 -2
  68. data/test/test_fast.rb +37 -7
  69. data/test/test_file.rb +23 -7
  70. data/test/test_gc.rb +11 -0
  71. data/test/test_object.rb +8 -10
  72. data/test/test_parser.rb +3 -19
  73. data/test/test_parser_debug.rb +27 -0
  74. data/test/test_parser_saj.rb +92 -2
  75. data/test/test_saj.rb +1 -1
  76. data/test/test_scp.rb +2 -4
  77. data/test/test_strict.rb +2 -0
  78. data/test/test_various.rb +32 -2
  79. data/test/test_wab.rb +2 -0
  80. data/test/tests.rb +9 -1
  81. data/test/tests_mimic.rb +9 -0
  82. data/test/tests_mimic_addition.rb +9 -0
  83. metadata +15 -115
data/ext/oj/saj2.c CHANGED
@@ -3,21 +3,11 @@
3
3
  #include "cache.h"
4
4
  #include "oj.h"
5
5
  #include "parser.h"
6
-
7
- typedef struct _delegate {
8
- VALUE handler;
9
- VALUE * keys;
10
- VALUE * tail;
11
- size_t klen;
12
- struct _cache *str_cache;
13
- uint8_t cache_str;
14
- bool cache_keys;
15
- bool thread_safe;
16
- } * Delegate;
6
+ #include "saj2.h"
17
7
 
18
8
  static VALUE get_key(ojParser p) {
19
- Delegate d = (Delegate)p->ctx;
20
- const char * key = buf_str(&p->key);
9
+ Saj d = (Saj)p->ctx;
10
+ const char *key = buf_str(&p->key);
21
11
  size_t len = buf_len(&p->key);
22
12
  volatile VALUE rkey;
23
13
 
@@ -29,7 +19,7 @@ static VALUE get_key(ojParser p) {
29
19
  return rkey;
30
20
  }
31
21
 
32
- static void push_key(Delegate d, VALUE key) {
22
+ static void push_key(Saj d, VALUE key) {
33
23
  if (d->klen <= (size_t)(d->tail - d->keys)) {
34
24
  size_t off = d->tail - d->keys;
35
25
 
@@ -45,31 +35,55 @@ static void noop(ojParser p) {
45
35
  }
46
36
 
47
37
  static void open_object(ojParser p) {
48
- rb_funcall(((Delegate)p->ctx)->handler, oj_hash_start_id, 1, Qnil);
38
+ rb_funcall(((Saj)p->ctx)->handler, oj_hash_start_id, 1, Qnil);
39
+ }
40
+
41
+ static void open_object_loc(ojParser p) {
42
+ rb_funcall(((Saj)p->ctx)->handler, oj_hash_start_id, 3, Qnil, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
49
43
  }
50
44
 
51
45
  static void open_object_key(ojParser p) {
52
- Delegate d = (Delegate)p->ctx;
46
+ Saj d = (Saj)p->ctx;
53
47
  volatile VALUE key = get_key(p);
54
48
 
55
49
  push_key(d, key);
56
50
  rb_funcall(d->handler, oj_hash_start_id, 1, key);
57
51
  }
58
52
 
53
+ static void open_object_loc_key(ojParser p) {
54
+ Saj d = (Saj)p->ctx;
55
+ volatile VALUE key = get_key(p);
56
+
57
+ push_key(d, key);
58
+ rb_funcall(d->handler, oj_hash_start_id, 3, key, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
59
+ }
60
+
59
61
  static void open_array(ojParser p) {
60
- rb_funcall(((Delegate)p->ctx)->handler, oj_array_start_id, 1, Qnil);
62
+ rb_funcall(((Saj)p->ctx)->handler, oj_array_start_id, 1, Qnil);
63
+ }
64
+
65
+ static void open_array_loc(ojParser p) {
66
+ rb_funcall(((Saj)p->ctx)->handler, oj_array_start_id, 3, Qnil, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
61
67
  }
62
68
 
63
69
  static void open_array_key(ojParser p) {
64
- Delegate d = (Delegate)p->ctx;
70
+ Saj d = (Saj)p->ctx;
65
71
  volatile VALUE key = get_key(p);
66
72
 
67
73
  push_key(d, key);
68
74
  rb_funcall(d->handler, oj_array_start_id, 1, key);
69
75
  }
70
76
 
77
+ static void open_array_loc_key(ojParser p) {
78
+ Saj d = (Saj)p->ctx;
79
+ volatile VALUE key = get_key(p);
80
+
81
+ push_key(d, key);
82
+ rb_funcall(d->handler, oj_array_start_id, 3, key, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
83
+ }
84
+
71
85
  static void close_object(ojParser p) {
72
- Delegate d = (Delegate)p->ctx;
86
+ Saj d = (Saj)p->ctx;
73
87
  VALUE key = Qnil;
74
88
 
75
89
  if (OBJECT_FUN == p->stack[p->depth]) {
@@ -82,8 +96,22 @@ static void close_object(ojParser p) {
82
96
  rb_funcall(d->handler, oj_hash_end_id, 1, key);
83
97
  }
84
98
 
99
+ static void close_object_loc(ojParser p) {
100
+ Saj d = (Saj)p->ctx;
101
+ VALUE key = Qnil;
102
+
103
+ if (OBJECT_FUN == p->stack[p->depth]) {
104
+ d->tail--;
105
+ if (d->tail < d->keys) {
106
+ rb_raise(rb_eIndexError, "accessing key stack");
107
+ }
108
+ key = *d->tail;
109
+ }
110
+ rb_funcall(d->handler, oj_hash_end_id, 3, key, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
111
+ }
112
+
85
113
  static void close_array(ojParser p) {
86
- Delegate d = (Delegate)p->ctx;
114
+ Saj d = (Saj)p->ctx;
87
115
  VALUE key = Qnil;
88
116
 
89
117
  if (OBJECT_FUN == p->stack[p->depth]) {
@@ -96,66 +124,200 @@ static void close_array(ojParser p) {
96
124
  rb_funcall(d->handler, oj_array_end_id, 1, key);
97
125
  }
98
126
 
127
+ static void close_array_loc(ojParser p) {
128
+ Saj d = (Saj)p->ctx;
129
+ VALUE key = Qnil;
130
+
131
+ if (OBJECT_FUN == p->stack[p->depth]) {
132
+ d->tail--;
133
+ if (d->tail < d->keys) {
134
+ rb_raise(rb_eIndexError, "accessing key stack");
135
+ }
136
+ key = *d->tail;
137
+ }
138
+ rb_funcall(d->handler, oj_array_end_id, 3, key, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
139
+ }
140
+
99
141
  static void add_null(ojParser p) {
100
- rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, Qnil, Qnil);
142
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 2, Qnil, Qnil);
143
+ }
144
+
145
+ static void add_null_loc(ojParser p) {
146
+ rb_funcall(((Saj)p->ctx)->handler,
147
+ oj_add_value_id,
148
+ 4,
149
+ Qnil,
150
+ Qnil,
151
+ LONG2FIX(p->line),
152
+ LONG2FIX(p->cur - p->col));
101
153
  }
102
154
 
103
155
  static void add_null_key(ojParser p) {
104
- rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, Qnil, get_key(p));
156
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 2, Qnil, get_key(p));
157
+ }
158
+
159
+ static void add_null_key_loc(ojParser p) {
160
+ rb_funcall(((Saj)p->ctx)->handler,
161
+ oj_add_value_id,
162
+ 4,
163
+ Qnil,
164
+ get_key(p),
165
+ LONG2FIX(p->line),
166
+ LONG2FIX(p->cur - p->col));
105
167
  }
106
168
 
107
169
  static void add_true(ojParser p) {
108
- rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, Qtrue, Qnil);
170
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 2, Qtrue, Qnil);
171
+ }
172
+
173
+ static void add_true_loc(ojParser p) {
174
+ rb_funcall(((Saj)p->ctx)->handler,
175
+ oj_add_value_id,
176
+ 4,
177
+ Qtrue,
178
+ Qnil,
179
+ LONG2FIX(p->line),
180
+ LONG2FIX(p->cur - p->col));
109
181
  }
110
182
 
111
183
  static void add_true_key(ojParser p) {
112
- rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, Qtrue, get_key(p));
184
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 2, Qtrue, get_key(p));
185
+ }
186
+
187
+ static void add_true_key_loc(ojParser p) {
188
+ rb_funcall(((Saj)p->ctx)->handler,
189
+ oj_add_value_id,
190
+ 4,
191
+ Qtrue,
192
+ get_key(p),
193
+ LONG2FIX(p->line),
194
+ LONG2FIX(p->cur - p->col));
113
195
  }
114
196
 
115
197
  static void add_false(ojParser p) {
116
- rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, Qfalse, Qnil);
198
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 2, Qfalse, Qnil);
199
+ }
200
+
201
+ static void add_false_loc(ojParser p) {
202
+ rb_funcall(((Saj)p->ctx)->handler,
203
+ oj_add_value_id,
204
+ 4,
205
+ Qfalse,
206
+ Qnil,
207
+ LONG2FIX(p->line),
208
+ LONG2FIX(p->cur - p->col));
117
209
  }
118
210
 
119
211
  static void add_false_key(ojParser p) {
120
- rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, Qfalse, get_key(p));
212
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 2, Qfalse, get_key(p));
213
+ }
214
+
215
+ static void add_false_key_loc(ojParser p) {
216
+ rb_funcall(((Saj)p->ctx)->handler,
217
+ oj_add_value_id,
218
+ 4,
219
+ Qfalse,
220
+ get_key(p),
221
+ LONG2FIX(p->line),
222
+ LONG2FIX(p->cur - p->col));
121
223
  }
122
224
 
123
225
  static void add_int(ojParser p) {
124
- rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, LONG2NUM(p->num.fixnum), Qnil);
226
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 2, LONG2NUM(p->num.fixnum), Qnil);
227
+ }
228
+
229
+ static void add_int_loc(ojParser p) {
230
+ rb_funcall(((Saj)p->ctx)->handler,
231
+ oj_add_value_id,
232
+ 4,
233
+ LONG2NUM(p->num.fixnum),
234
+ Qnil,
235
+ LONG2FIX(p->line),
236
+ LONG2FIX(p->cur - p->col));
125
237
  }
126
238
 
127
239
  static void add_int_key(ojParser p) {
128
- rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, LONG2NUM(p->num.fixnum), get_key(p));
240
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 2, LONG2NUM(p->num.fixnum), get_key(p));
241
+ }
242
+
243
+ static void add_int_key_loc(ojParser p) {
244
+ rb_funcall(((Saj)p->ctx)->handler,
245
+ oj_add_value_id,
246
+ 4,
247
+ LONG2NUM(p->num.fixnum),
248
+ get_key(p),
249
+ LONG2FIX(p->line),
250
+ LONG2FIX(p->cur - p->col));
129
251
  }
130
252
 
131
253
  static void add_float(ojParser p) {
132
- rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, rb_float_new(p->num.dub), Qnil);
254
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 2, rb_float_new(p->num.dub), Qnil);
255
+ }
256
+
257
+ static void add_float_loc(ojParser p) {
258
+ rb_funcall(((Saj)p->ctx)->handler,
259
+ oj_add_value_id,
260
+ 4,
261
+ rb_float_new(p->num.dub),
262
+ Qnil,
263
+ LONG2FIX(p->line),
264
+ LONG2FIX(p->cur - p->col));
133
265
  }
134
266
 
135
267
  static void add_float_key(ojParser p) {
136
- rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, rb_float_new(p->num.dub), get_key(p));
268
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 2, rb_float_new(p->num.dub), get_key(p));
269
+ }
270
+
271
+ static void add_float_key_loc(ojParser p) {
272
+ rb_funcall(((Saj)p->ctx)->handler,
273
+ oj_add_value_id,
274
+ 4,
275
+ rb_float_new(p->num.dub),
276
+ get_key(p),
277
+ LONG2FIX(p->line),
278
+ LONG2FIX(p->cur - p->col));
137
279
  }
138
280
 
139
281
  static void add_big(ojParser p) {
140
- rb_funcall((VALUE)p->ctx,
282
+ rb_funcall(((Saj)p->ctx)->handler,
141
283
  oj_add_value_id,
142
284
  2,
143
285
  rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new(buf_str(&p->buf), buf_len(&p->buf))),
144
286
  Qnil);
145
287
  }
146
288
 
289
+ static void add_big_loc(ojParser p) {
290
+ rb_funcall(((Saj)p->ctx)->handler,
291
+ oj_add_value_id,
292
+ 4,
293
+ rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new(buf_str(&p->buf), buf_len(&p->buf))),
294
+ Qnil,
295
+ LONG2FIX(p->line),
296
+ LONG2FIX(p->cur - p->col));
297
+ }
298
+
147
299
  static void add_big_key(ojParser p) {
148
- rb_funcall((VALUE)p->ctx,
300
+ rb_funcall(((Saj)p->ctx)->handler,
149
301
  oj_add_value_id,
150
302
  2,
151
303
  rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new(buf_str(&p->buf), buf_len(&p->buf))),
152
304
  get_key(p));
153
305
  }
154
306
 
307
+ static void add_big_key_loc(ojParser p) {
308
+ rb_funcall(((Saj)p->ctx)->handler,
309
+ oj_add_value_id,
310
+ 4,
311
+ rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new(buf_str(&p->buf), buf_len(&p->buf))),
312
+ get_key(p),
313
+ LONG2FIX(p->line),
314
+ LONG2FIX(p->cur - p->col));
315
+ }
316
+
155
317
  static void add_str(ojParser p) {
156
- Delegate d = (Delegate)p->ctx;
318
+ Saj d = (Saj)p->ctx;
157
319
  volatile VALUE rstr;
158
- const char * str = buf_str(&p->buf);
320
+ const char *str = buf_str(&p->buf);
159
321
  size_t len = buf_len(&p->buf);
160
322
 
161
323
  if (d->cache_str < len) {
@@ -166,10 +328,24 @@ static void add_str(ojParser p) {
166
328
  rb_funcall(d->handler, oj_add_value_id, 2, rstr, Qnil);
167
329
  }
168
330
 
331
+ static void add_str_loc(ojParser p) {
332
+ Saj d = (Saj)p->ctx;
333
+ volatile VALUE rstr;
334
+ const char *str = buf_str(&p->buf);
335
+ size_t len = buf_len(&p->buf);
336
+
337
+ if (d->cache_str < len) {
338
+ rstr = cache_intern(d->str_cache, str, len);
339
+ } else {
340
+ rstr = rb_utf8_str_new(str, len);
341
+ }
342
+ rb_funcall(d->handler, oj_add_value_id, 4, rstr, Qnil, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
343
+ }
344
+
169
345
  static void add_str_key(ojParser p) {
170
- Delegate d = (Delegate)p->ctx;
346
+ Saj d = (Saj)p->ctx;
171
347
  volatile VALUE rstr;
172
- const char * str = buf_str(&p->buf);
348
+ const char *str = buf_str(&p->buf);
173
349
  size_t len = buf_len(&p->buf);
174
350
 
175
351
  if (d->cache_str < len) {
@@ -180,6 +356,20 @@ static void add_str_key(ojParser p) {
180
356
  rb_funcall(d->handler, oj_add_value_id, 2, rstr, get_key(p));
181
357
  }
182
358
 
359
+ static void add_str_key_loc(ojParser p) {
360
+ Saj d = (Saj)p->ctx;
361
+ volatile VALUE rstr;
362
+ const char *str = buf_str(&p->buf);
363
+ size_t len = buf_len(&p->buf);
364
+
365
+ if (d->cache_str < len) {
366
+ rstr = cache_intern(d->str_cache, str, len);
367
+ } else {
368
+ rstr = rb_utf8_str_new(str, len);
369
+ }
370
+ rb_funcall(d->handler, oj_add_value_id, 4, rstr, get_key(p), LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
371
+ }
372
+
183
373
  static void reset(ojParser p) {
184
374
  Funcs end = p->funcs + 3;
185
375
  Funcs f;
@@ -200,7 +390,7 @@ static void reset(ojParser p) {
200
390
  }
201
391
 
202
392
  static VALUE option(ojParser p, const char *key, VALUE value) {
203
- Delegate d = (Delegate)p->ctx;
393
+ Saj d = (Saj)p->ctx;
204
394
 
205
395
  if (0 == strcmp(key, "handler")) {
206
396
  return d->handler;
@@ -210,53 +400,107 @@ static VALUE option(ojParser p, const char *key, VALUE value) {
210
400
  d->handler = value;
211
401
  reset(p);
212
402
  if (rb_respond_to(value, oj_hash_start_id)) {
213
- p->funcs[TOP_FUN].open_object = open_object;
214
- p->funcs[ARRAY_FUN].open_object = open_object;
215
- p->funcs[OBJECT_FUN].open_object = open_object_key;
403
+ if (1 == rb_obj_method_arity(value, oj_hash_start_id)) {
404
+ p->funcs[TOP_FUN].open_object = open_object;
405
+ p->funcs[ARRAY_FUN].open_object = open_object;
406
+ p->funcs[OBJECT_FUN].open_object = open_object_key;
407
+ } else {
408
+ p->funcs[TOP_FUN].open_object = open_object_loc;
409
+ p->funcs[ARRAY_FUN].open_object = open_object_loc;
410
+ p->funcs[OBJECT_FUN].open_object = open_object_loc_key;
411
+ }
216
412
  }
217
413
  if (rb_respond_to(value, oj_array_start_id)) {
218
- p->funcs[TOP_FUN].open_array = open_array;
219
- p->funcs[ARRAY_FUN].open_array = open_array;
220
- p->funcs[OBJECT_FUN].open_array = open_array_key;
414
+ if (1 == rb_obj_method_arity(value, oj_array_start_id)) {
415
+ p->funcs[TOP_FUN].open_array = open_array;
416
+ p->funcs[ARRAY_FUN].open_array = open_array;
417
+ p->funcs[OBJECT_FUN].open_array = open_array_key;
418
+ } else {
419
+ p->funcs[TOP_FUN].open_array = open_array_loc;
420
+ p->funcs[ARRAY_FUN].open_array = open_array_loc;
421
+ p->funcs[OBJECT_FUN].open_array = open_array_loc_key;
422
+ }
221
423
  }
222
424
  if (rb_respond_to(value, oj_hash_end_id)) {
223
- p->funcs[TOP_FUN].close_object = close_object;
224
- p->funcs[ARRAY_FUN].close_object = close_object;
225
- p->funcs[OBJECT_FUN].close_object = close_object;
425
+ if (1 == rb_obj_method_arity(value, oj_hash_end_id)) {
426
+ p->funcs[TOP_FUN].close_object = close_object;
427
+ p->funcs[ARRAY_FUN].close_object = close_object;
428
+ p->funcs[OBJECT_FUN].close_object = close_object;
429
+ } else {
430
+ p->funcs[TOP_FUN].close_object = close_object_loc;
431
+ p->funcs[ARRAY_FUN].close_object = close_object_loc;
432
+ p->funcs[OBJECT_FUN].close_object = close_object_loc;
433
+ }
226
434
  }
227
435
  if (rb_respond_to(value, oj_array_end_id)) {
228
- p->funcs[TOP_FUN].close_array = close_array;
229
- p->funcs[ARRAY_FUN].close_array = close_array;
230
- p->funcs[OBJECT_FUN].close_array = close_array;
436
+ if (1 == rb_obj_method_arity(value, oj_array_end_id)) {
437
+ p->funcs[TOP_FUN].close_array = close_array;
438
+ p->funcs[ARRAY_FUN].close_array = close_array;
439
+ p->funcs[OBJECT_FUN].close_array = close_array;
440
+ } else {
441
+ p->funcs[TOP_FUN].close_array = close_array_loc;
442
+ p->funcs[ARRAY_FUN].close_array = close_array_loc;
443
+ p->funcs[OBJECT_FUN].close_array = close_array_loc;
444
+ }
231
445
  }
232
446
  if (rb_respond_to(value, oj_add_value_id)) {
233
- p->funcs[TOP_FUN].add_null = add_null;
234
- p->funcs[ARRAY_FUN].add_null = add_null;
235
- p->funcs[OBJECT_FUN].add_null = add_null_key;
236
-
237
- p->funcs[TOP_FUN].add_true = add_true;
238
- p->funcs[ARRAY_FUN].add_true = add_true;
239
- p->funcs[OBJECT_FUN].add_true = add_true_key;
240
-
241
- p->funcs[TOP_FUN].add_false = add_false;
242
- p->funcs[ARRAY_FUN].add_false = add_false;
243
- p->funcs[OBJECT_FUN].add_false = add_false_key;
244
-
245
- p->funcs[TOP_FUN].add_int = add_int;
246
- p->funcs[ARRAY_FUN].add_int = add_int;
247
- p->funcs[OBJECT_FUN].add_int = add_int_key;
248
-
249
- p->funcs[TOP_FUN].add_float = add_float;
250
- p->funcs[ARRAY_FUN].add_float = add_float;
251
- p->funcs[OBJECT_FUN].add_float = add_float_key;
252
-
253
- p->funcs[TOP_FUN].add_big = add_big;
254
- p->funcs[ARRAY_FUN].add_big = add_big;
255
- p->funcs[OBJECT_FUN].add_big = add_big_key;
256
-
257
- p->funcs[TOP_FUN].add_str = add_str;
258
- p->funcs[ARRAY_FUN].add_str = add_str;
259
- p->funcs[OBJECT_FUN].add_str = add_str_key;
447
+ if (2 == rb_obj_method_arity(value, oj_add_value_id)) {
448
+ p->funcs[TOP_FUN].add_null = add_null;
449
+ p->funcs[ARRAY_FUN].add_null = add_null;
450
+ p->funcs[OBJECT_FUN].add_null = add_null_key;
451
+
452
+ p->funcs[TOP_FUN].add_true = add_true;
453
+ p->funcs[ARRAY_FUN].add_true = add_true;
454
+ p->funcs[OBJECT_FUN].add_true = add_true_key;
455
+
456
+ p->funcs[TOP_FUN].add_false = add_false;
457
+ p->funcs[ARRAY_FUN].add_false = add_false;
458
+ p->funcs[OBJECT_FUN].add_false = add_false_key;
459
+
460
+ p->funcs[TOP_FUN].add_int = add_int;
461
+ p->funcs[ARRAY_FUN].add_int = add_int;
462
+ p->funcs[OBJECT_FUN].add_int = add_int_key;
463
+
464
+ p->funcs[TOP_FUN].add_float = add_float;
465
+ p->funcs[ARRAY_FUN].add_float = add_float;
466
+ p->funcs[OBJECT_FUN].add_float = add_float_key;
467
+
468
+ p->funcs[TOP_FUN].add_big = add_big;
469
+ p->funcs[ARRAY_FUN].add_big = add_big;
470
+ p->funcs[OBJECT_FUN].add_big = add_big_key;
471
+
472
+ p->funcs[TOP_FUN].add_str = add_str;
473
+ p->funcs[ARRAY_FUN].add_str = add_str;
474
+ p->funcs[OBJECT_FUN].add_str = add_str_key;
475
+ } else {
476
+ p->funcs[TOP_FUN].add_null = add_null_loc;
477
+ p->funcs[ARRAY_FUN].add_null = add_null_loc;
478
+ p->funcs[OBJECT_FUN].add_null = add_null_key_loc;
479
+
480
+ p->funcs[TOP_FUN].add_true = add_true_loc;
481
+ p->funcs[ARRAY_FUN].add_true = add_true_loc;
482
+ p->funcs[OBJECT_FUN].add_true = add_true_key_loc;
483
+
484
+ p->funcs[TOP_FUN].add_false = add_false_loc;
485
+ p->funcs[ARRAY_FUN].add_false = add_false_loc;
486
+ p->funcs[OBJECT_FUN].add_false = add_false_key_loc;
487
+
488
+ p->funcs[TOP_FUN].add_int = add_int_loc;
489
+ p->funcs[ARRAY_FUN].add_int = add_int_loc;
490
+ p->funcs[OBJECT_FUN].add_int = add_int_key_loc;
491
+
492
+ p->funcs[TOP_FUN].add_float = add_float_loc;
493
+ p->funcs[ARRAY_FUN].add_float = add_float_loc;
494
+ p->funcs[OBJECT_FUN].add_float = add_float_key_loc;
495
+
496
+ p->funcs[TOP_FUN].add_big = add_big_loc;
497
+ p->funcs[ARRAY_FUN].add_big = add_big_loc;
498
+ p->funcs[OBJECT_FUN].add_big = add_big_key_loc;
499
+
500
+ p->funcs[TOP_FUN].add_str = add_str_loc;
501
+ p->funcs[ARRAY_FUN].add_str = add_str_loc;
502
+ p->funcs[OBJECT_FUN].add_str = add_str_key_loc;
503
+ }
260
504
  }
261
505
  return Qnil;
262
506
  }
@@ -283,7 +527,7 @@ static VALUE option(ojParser p, const char *key, VALUE value) {
283
527
 
284
528
  return INT2NUM((int)d->cache_str);
285
529
  }
286
- rb_raise(rb_eArgError, "%s is not an option for the SAJ (Simple API for JSON) delegate", key);
530
+ rb_raise(rb_eArgError, "%s is not an option for the SAJ (Simple API for JSON) saj", key);
287
531
 
288
532
  return Qnil; // Never reached due to the raise but required by the compiler.
289
533
  }
@@ -293,13 +537,13 @@ static VALUE result(ojParser p) {
293
537
  }
294
538
 
295
539
  static void start(ojParser p) {
296
- Delegate d = (Delegate)p->ctx;
540
+ Saj d = (Saj)p->ctx;
297
541
 
298
542
  d->tail = d->keys;
299
543
  }
300
544
 
301
545
  static void dfree(ojParser p) {
302
- Delegate d = (Delegate)p->ctx;
546
+ Saj d = (Saj)p->ctx;
303
547
 
304
548
  if (NULL != d->keys) {
305
549
  xfree(d->keys);
@@ -309,11 +553,11 @@ static void dfree(ojParser p) {
309
553
  }
310
554
 
311
555
  static void mark(ojParser p) {
312
- if (NULL == p->ctx) {
556
+ if (NULL == p || NULL == p->ctx) {
313
557
  return;
314
558
  }
315
- Delegate d = (Delegate)p->ctx;
316
- VALUE *kp;
559
+ Saj d = (Saj)p->ctx;
560
+ VALUE *kp;
317
561
 
318
562
  cache_mark(d->str_cache);
319
563
  if (Qnil != d->handler) {
@@ -330,9 +574,7 @@ static VALUE form_str(const char *str, size_t len) {
330
574
  return rb_str_freeze(rb_utf8_str_new(str, len));
331
575
  }
332
576
 
333
- void oj_set_parser_saj(ojParser p) {
334
- Delegate d = ALLOC(struct _delegate);
335
-
577
+ void oj_init_saj(ojParser p, Saj d) {
336
578
  d->klen = 256;
337
579
  d->keys = ALLOC_N(VALUE, d->klen);
338
580
  d->tail = d->keys;
@@ -346,3 +588,9 @@ void oj_set_parser_saj(ojParser p) {
346
588
  p->mark = mark;
347
589
  p->start = start;
348
590
  }
591
+
592
+ void oj_set_parser_saj(ojParser p) {
593
+ Saj d = ALLOC(struct _saj);
594
+
595
+ oj_init_saj(p, d);
596
+ }
data/ext/oj/saj2.h ADDED
@@ -0,0 +1,23 @@
1
+ // Copyright (c) 2021, Peter Ohler, All rights reserved.
2
+
3
+ #include <ruby.h>
4
+ #include <stdbool.h>
5
+
6
+ struct _cache;
7
+ struct _ojParser;
8
+
9
+ typedef struct _saj {
10
+ VALUE handler;
11
+ VALUE *keys;
12
+ VALUE *tail;
13
+ size_t klen;
14
+ struct _cache *str_cache;
15
+ uint8_t cache_str;
16
+ bool cache_keys;
17
+ bool thread_safe;
18
+ } * Saj;
19
+
20
+ // Initialize the parser with the SAJ delegate. If the SAJ delegate is wrapped
21
+ // then this function is called first and then the parser functions can be
22
+ // replaced.
23
+ extern void oj_init_saj(struct _ojParser *p, Saj d);
data/ext/oj/sparse.c CHANGED
@@ -953,7 +953,11 @@ CLEANUP:
953
953
  }
954
954
  stack_cleanup(&pi->stack);
955
955
  if (0 != fd) {
956
+ #ifdef _WIN32
957
+ rb_w32_close(fd);
958
+ #else
956
959
  close(fd);
960
+ #endif
957
961
  }
958
962
  if (err_has(&pi->err)) {
959
963
  rb_set_errinfo(Qnil);
@@ -315,8 +315,10 @@ static VALUE stream_writer_flush(VALUE self) {
315
315
  * will create that element in the JSON document and subsequent pushes will add
316
316
  * the elements to that array or object until a pop() is called.
317
317
  */
318
- void oj_stream_writer_init() {
318
+ void oj_stream_writer_init(void) {
319
319
  oj_stream_writer_class = rb_define_class_under(Oj, "StreamWriter", rb_cObject);
320
+ rb_gc_register_address(&oj_stream_writer_class);
321
+ rb_undef_alloc_func(oj_stream_writer_class);
320
322
  rb_define_module_function(oj_stream_writer_class, "new", stream_writer_new, -1);
321
323
  rb_define_method(oj_stream_writer_class, "push_key", stream_writer_push_key, 1);
322
324
  rb_define_method(oj_stream_writer_class, "push_object", stream_writer_push_object, -1);