isomorfeus-iodine 0.7.49 → 0.7.50

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +1 -1
  3. data/CHANGELOG.md +17 -3
  4. data/Rakefile +1 -9
  5. data/examples/etag.ru +16 -0
  6. data/ext/{iodine → iodine_ext}/extconf.rb +1 -1
  7. data/ext/{iodine → iodine_ext}/fio.c +0 -0
  8. data/ext/{iodine → iodine_ext}/fio.h +0 -0
  9. data/ext/{iodine → iodine_ext}/fio_cli.c +0 -0
  10. data/ext/{iodine → iodine_ext}/fio_cli.h +189 -189
  11. data/ext/{iodine → iodine_ext}/fio_json_parser.h +687 -687
  12. data/ext/{iodine → iodine_ext}/fio_siphash.c +157 -157
  13. data/ext/{iodine → iodine_ext}/fio_siphash.h +37 -37
  14. data/ext/{iodine → iodine_ext}/fio_tls.h +129 -129
  15. data/ext/{iodine → iodine_ext}/fio_tls_missing.c +0 -0
  16. data/ext/{iodine → iodine_ext}/fio_tls_openssl.c +0 -0
  17. data/ext/{iodine → iodine_ext}/fio_tmpfile.h +0 -0
  18. data/ext/{iodine → iodine_ext}/fiobj.h +44 -44
  19. data/ext/{iodine → iodine_ext}/fiobj4fio.h +21 -21
  20. data/ext/{iodine → iodine_ext}/fiobj_ary.c +333 -333
  21. data/ext/{iodine → iodine_ext}/fiobj_ary.h +139 -139
  22. data/ext/{iodine → iodine_ext}/fiobj_data.c +0 -0
  23. data/ext/{iodine → iodine_ext}/fiobj_data.h +0 -0
  24. data/ext/{iodine → iodine_ext}/fiobj_hash.c +0 -0
  25. data/ext/{iodine → iodine_ext}/fiobj_hash.h +176 -176
  26. data/ext/{iodine → iodine_ext}/fiobj_json.c +622 -622
  27. data/ext/{iodine → iodine_ext}/fiobj_json.h +68 -68
  28. data/ext/{iodine → iodine_ext}/fiobj_mem.h +71 -71
  29. data/ext/{iodine → iodine_ext}/fiobj_mustache.c +0 -0
  30. data/ext/{iodine → iodine_ext}/fiobj_mustache.h +62 -62
  31. data/ext/{iodine → iodine_ext}/fiobj_numbers.c +0 -0
  32. data/ext/{iodine → iodine_ext}/fiobj_numbers.h +127 -127
  33. data/ext/{iodine → iodine_ext}/fiobj_str.c +0 -0
  34. data/ext/{iodine → iodine_ext}/fiobj_str.h +172 -172
  35. data/ext/{iodine → iodine_ext}/fiobject.c +0 -0
  36. data/ext/{iodine → iodine_ext}/fiobject.h +0 -0
  37. data/ext/{iodine → iodine_ext}/hpack.h +1923 -1923
  38. data/ext/{iodine → iodine_ext}/http.c +14 -27
  39. data/ext/{iodine → iodine_ext}/http.h +1002 -1002
  40. data/ext/{iodine → iodine_ext}/http1.c +0 -0
  41. data/ext/{iodine → iodine_ext}/http1.h +29 -29
  42. data/ext/{iodine → iodine_ext}/http1_parser.h +0 -0
  43. data/ext/{iodine → iodine_ext}/http_internal.c +0 -0
  44. data/ext/{iodine → iodine_ext}/http_internal.h +0 -0
  45. data/ext/{iodine → iodine_ext}/http_mime_parser.h +350 -350
  46. data/ext/{iodine → iodine_ext}/iodine.c +1 -1
  47. data/ext/{iodine → iodine_ext}/iodine.h +0 -0
  48. data/ext/{iodine → iodine_ext}/iodine_caller.c +0 -0
  49. data/ext/{iodine → iodine_ext}/iodine_caller.h +0 -0
  50. data/ext/{iodine → iodine_ext}/iodine_connection.c +0 -0
  51. data/ext/{iodine → iodine_ext}/iodine_connection.h +55 -55
  52. data/ext/{iodine → iodine_ext}/iodine_defer.c +0 -0
  53. data/ext/{iodine → iodine_ext}/iodine_defer.h +6 -6
  54. data/ext/{iodine → iodine_ext}/iodine_fiobj2rb.h +120 -120
  55. data/ext/{iodine → iodine_ext}/iodine_helpers.c +0 -0
  56. data/ext/{iodine → iodine_ext}/iodine_helpers.h +12 -12
  57. data/ext/{iodine → iodine_ext}/iodine_http.c +0 -2
  58. data/ext/{iodine → iodine_ext}/iodine_http.h +23 -23
  59. data/ext/{iodine → iodine_ext}/iodine_json.c +302 -302
  60. data/ext/{iodine → iodine_ext}/iodine_json.h +6 -6
  61. data/ext/{iodine → iodine_ext}/iodine_mustache.c +0 -0
  62. data/ext/{iodine → iodine_ext}/iodine_mustache.h +6 -6
  63. data/ext/{iodine → iodine_ext}/iodine_pubsub.c +0 -0
  64. data/ext/{iodine → iodine_ext}/iodine_pubsub.h +26 -26
  65. data/ext/{iodine → iodine_ext}/iodine_rack_io.c +0 -0
  66. data/ext/{iodine → iodine_ext}/iodine_rack_io.h +20 -20
  67. data/ext/{iodine → iodine_ext}/iodine_store.c +0 -0
  68. data/ext/{iodine → iodine_ext}/iodine_store.h +20 -20
  69. data/ext/{iodine → iodine_ext}/iodine_tcp.c +0 -0
  70. data/ext/{iodine → iodine_ext}/iodine_tcp.h +0 -0
  71. data/ext/{iodine → iodine_ext}/iodine_tls.c +0 -0
  72. data/ext/{iodine → iodine_ext}/iodine_tls.h +13 -13
  73. data/ext/{iodine → iodine_ext}/mustache_parser.h +0 -0
  74. data/ext/{iodine → iodine_ext}/redis_engine.c +0 -0
  75. data/ext/{iodine → iodine_ext}/redis_engine.h +0 -0
  76. data/ext/{iodine → iodine_ext}/resp_parser.h +0 -0
  77. data/ext/{iodine → iodine_ext}/websocket_parser.h +505 -505
  78. data/ext/{iodine → iodine_ext}/websockets.c +0 -0
  79. data/ext/{iodine → iodine_ext}/websockets.h +185 -185
  80. data/isomorfeus-iodine.gemspec +1 -2
  81. data/lib/iodine/version.rb +1 -1
  82. data/lib/iodine.rb +1 -1
  83. metadata +79 -78
@@ -1,302 +1,302 @@
1
- #include "iodine.h"
2
-
3
- #include "fio.h"
4
-
5
- #include "fio_json_parser.h"
6
- #include "fiobj.h"
7
- #include "iodine_fiobj2rb.h"
8
- #include "iodine_store.h"
9
-
10
- static VALUE max_nesting;
11
- static VALUE allow_nan;
12
- static VALUE symbolize_names;
13
- static VALUE create_additions;
14
- static VALUE object_class;
15
- static VALUE array_class;
16
-
17
- #define FIO_ARY_NAME fio_json_stack
18
- #define FIO_ARY_TYPE VALUE
19
- #include "fio.h"
20
-
21
- /* *****************************************************************************
22
- JSON Callacks - these must be implemented in the C file that uses the parser
23
- ***************************************************************************** */
24
-
25
- /* *****************************************************************************
26
- JSON Parser handling (practically copied from the FIOBJ library)
27
- ***************************************************************************** */
28
-
29
- typedef struct {
30
- json_parser_s p;
31
- VALUE key;
32
- VALUE top;
33
- VALUE target;
34
- fio_json_stack_s stack;
35
- uint8_t is_hash;
36
- uint8_t symbolize;
37
- } iodine_json_parser_s;
38
-
39
- static inline void iodine_json_add2parser(iodine_json_parser_s *p, VALUE o) {
40
- if (p->top) {
41
- if (p->is_hash) {
42
- if (p->key) {
43
- rb_hash_aset(p->top, p->key, o);
44
- IodineStore.remove(p->key);
45
- p->key = (VALUE)0;
46
- } else {
47
- p->key = o;
48
- IodineStore.add(o);
49
- }
50
- } else {
51
- rb_ary_push(p->top, o);
52
- }
53
- } else {
54
- IodineStore.add(o);
55
- p->top = o;
56
- }
57
- }
58
-
59
- /** a NULL object was detected */
60
- static void fio_json_on_null(json_parser_s *p) {
61
- iodine_json_add2parser((iodine_json_parser_s *)p, Qnil);
62
- }
63
- /** a TRUE object was detected */
64
- static void fio_json_on_true(json_parser_s *p) {
65
- iodine_json_add2parser((iodine_json_parser_s *)p, Qtrue);
66
- }
67
- /** a FALSE object was detected */
68
- static void fio_json_on_false(json_parser_s *p) {
69
- iodine_json_add2parser((iodine_json_parser_s *)p, Qfalse);
70
- }
71
- /** a Numberl was detected (long long). */
72
- static void fio_json_on_number(json_parser_s *p, long long i) {
73
- iodine_json_add2parser((iodine_json_parser_s *)p, LONG2NUM(i));
74
- }
75
- /** a Float was detected (double). */
76
- static void fio_json_on_float(json_parser_s *p, double f) {
77
- iodine_json_add2parser((iodine_json_parser_s *)p, DBL2NUM(f));
78
- }
79
- /** a String was detected (int / float). update `pos` to point at ending */
80
- static void fio_json_on_string(json_parser_s *p, void *start, size_t length) {
81
- /* Ruby overhead for a rb_str_buf_new is very high. Double copy is faster. */
82
- char *tmp = fio_malloc(length);
83
- size_t new_len = fio_json_unescape_str(tmp, start, length);
84
- VALUE buf;
85
- if (((iodine_json_parser_s *)p)->symbolize &&
86
- ((iodine_json_parser_s *)p)->is_hash &&
87
- !((iodine_json_parser_s *)p)->key) {
88
- ID id = rb_intern2(tmp, new_len);
89
- buf = rb_id2sym(id);
90
- } else {
91
- buf = rb_str_new(tmp, new_len);
92
- }
93
- iodine_json_add2parser((iodine_json_parser_s *)p, buf);
94
- fio_free(tmp);
95
- }
96
- /** a dictionary object was detected, should return 0 unless error occurred. */
97
- static int fio_json_on_start_object(json_parser_s *p) {
98
- iodine_json_parser_s *pr = (iodine_json_parser_s *)p;
99
- if (pr->target) {
100
- /* push NULL, don't free the objects */
101
- fio_json_stack_push(&pr->stack, pr->top);
102
- pr->top = pr->target;
103
- pr->target = 0;
104
- } else {
105
- VALUE h = rb_hash_new();
106
- iodine_json_add2parser(pr, h);
107
- fio_json_stack_push(&pr->stack, pr->top);
108
- pr->top = h;
109
- }
110
- pr->is_hash = 1;
111
- return 0;
112
- }
113
- /** a dictionary object closure detected */
114
- static void fio_json_on_end_object(json_parser_s *p) {
115
- iodine_json_parser_s *pr = (iodine_json_parser_s *)p;
116
- if (pr->key) {
117
- FIO_LOG_WARNING("(JSON parsing) malformed JSON, "
118
- "ignoring dangling Hash key.");
119
- IodineStore.remove(pr->key);
120
- pr->key = (VALUE)0;
121
- }
122
- fio_json_stack_pop(&pr->stack, &pr->top);
123
- pr->is_hash = (TYPE(pr->top) == T_HASH);
124
- }
125
- /** an array object was detected */
126
- static int fio_json_on_start_array(json_parser_s *p) {
127
- iodine_json_parser_s *pr = (iodine_json_parser_s *)p;
128
- if (pr->target)
129
- return -1;
130
- VALUE ary = rb_ary_new();
131
- iodine_json_add2parser(pr, ary);
132
- fio_json_stack_push(&pr->stack, pr->top);
133
- pr->top = ary;
134
- pr->is_hash = 0;
135
- return 0;
136
- }
137
- /** an array closure was detected */
138
- static void fio_json_on_end_array(json_parser_s *p) {
139
- iodine_json_parser_s *pr = (iodine_json_parser_s *)p;
140
- fio_json_stack_pop(&pr->stack, &pr->top);
141
- pr->is_hash = (TYPE(pr->top) == T_HASH);
142
- }
143
- /** the JSON parsing is complete */
144
- static void fio_json_on_json(json_parser_s *p) { (void)p; /* do nothing */ }
145
- /** the JSON parsing is complete */
146
- static void fio_json_on_error(json_parser_s *p) {
147
- iodine_json_parser_s *pr = (iodine_json_parser_s *)p;
148
- #if DEBUG
149
- FIO_LOG_ERROR("JSON on error called.");
150
- #endif
151
- IodineStore.remove((VALUE)fio_json_stack_get(&pr->stack, 0));
152
- IodineStore.remove(pr->key);
153
- fio_json_stack_free(&pr->stack);
154
- *pr = (iodine_json_parser_s){.top = 0};
155
- }
156
-
157
- /* *****************************************************************************
158
- Iodine JSON Implementation
159
- ***************************************************************************** */
160
-
161
- static inline VALUE iodine_json_convert(VALUE str, fiobj2rb_settings_s s) {
162
-
163
- iodine_json_parser_s p = {.top = 0, .symbolize = s.str2sym};
164
- size_t consumed = fio_json_parse(&p.p, RSTRING_PTR(str), RSTRING_LEN(str));
165
- if (!consumed || p.p.depth) {
166
- IodineStore.remove((VALUE)fio_json_stack_get(&p.stack, 0));
167
- p.top = FIOBJ_INVALID;
168
- }
169
- fio_json_stack_free(&p.stack);
170
- if (p.key) {
171
- IodineStore.remove((VALUE)p.key);
172
- }
173
- if (!p.top) {
174
- rb_raise(rb_eEncodingError, "Malformed JSON format.");
175
- }
176
- IodineStore.remove(p.top);
177
- return p.top;
178
- }
179
-
180
- // static inline VALUE iodine_json_convert2(VALUE str, fiobj2rb_settings_s s) {
181
- // FIOBJ json;
182
- // if (!fiobj_json2obj(&json, RSTRING_PTR(str), RSTRING_LEN(str)) || !json) {
183
- // rb_raise(rb_eRuntimeError, "JSON parsing failed. Not JSON?");
184
- // return Qnil;
185
- // }
186
- // VALUE ret = fiobj2rb_deep(json, s.str2sym);
187
- // fiobj_free(json);
188
- // IodineStore.remove(ret);
189
- // return ret;
190
- // }
191
-
192
- static inline void iodine_json_update_settings(VALUE h,
193
- fiobj2rb_settings_s *s) {
194
- VALUE tmp;
195
- if (rb_hash_aref(h, max_nesting) != Qnil)
196
- FIO_LOG_WARNING("max_nesting ignored on this JSON implementation.");
197
- if (rb_hash_aref(h, allow_nan) != Qnil)
198
- fprintf(stderr, "WARNING: allow_nan ignored on this JSON implementation. "
199
- "NaN always allowed.\n");
200
- if (rb_hash_aref(h, create_additions) != Qnil)
201
- FIO_LOG_WARNING("create_additions ignored on this JSON implementation.");
202
- if (rb_hash_aref(h, object_class) != Qnil)
203
- FIO_LOG_WARNING("object_class ignored on this JSON implementation.");
204
- if (rb_hash_aref(h, array_class) != Qnil)
205
- FIO_LOG_WARNING("array_class ignored on this JSON implementation.");
206
- if ((tmp = rb_hash_aref(h, symbolize_names)) != Qnil) {
207
- if (tmp == Qtrue)
208
- s->str2sym = 1;
209
- else if (tmp == Qfalse)
210
- s->str2sym = 0;
211
- }
212
- }
213
-
214
- /**
215
- Parse a JSON string using the iodine lenient parser (it's also faster).
216
- */
217
- static VALUE iodine_json_parse(int argc, VALUE *argv, VALUE self) {
218
- fiobj2rb_settings_s s = {.str2sym = 0};
219
- if (argc > 2)
220
- rb_raise(rb_eTypeError, "function requires supports up to two arguments.");
221
- if (argc == 2) {
222
- Check_Type(argv[1], T_HASH);
223
- iodine_json_update_settings(argv[1], &s);
224
- }
225
- if (argc >= 1)
226
- Check_Type(argv[0], T_STRING);
227
- else
228
- rb_raise(rb_eTypeError, "function requires at least one argument.");
229
- return iodine_json_convert(argv[0], s);
230
- (void)self;
231
- }
232
-
233
- /**
234
- Parse a JSON string using the iodine lenient parser with a default Symbol
235
- rather than String key (this is often faster than the regular
236
- {Iodine::JSON.parse} function).
237
- */
238
- static VALUE iodine_json_parse_bang(int argc, VALUE *argv, VALUE self) {
239
- fiobj2rb_settings_s s = {.str2sym = 0};
240
- if (argc > 2)
241
- rb_raise(rb_eTypeError, "function requires supports up to two arguments.");
242
- if (argc == 2) {
243
- Check_Type(argv[1], T_HASH);
244
- iodine_json_update_settings(argv[1], &s);
245
- }
246
- if (argc >= 1)
247
- Check_Type(argv[0], T_STRING);
248
- else
249
- rb_raise(rb_eTypeError, "function requires at least one argument.");
250
- return iodine_json_convert(argv[0], s);
251
- (void)self;
252
- }
253
-
254
- void iodine_init_json(void) {
255
- /**
256
- Iodine::JSON offers a fast(er) JSON parser that is also lenient and supports
257
- some JSON extensions such as Hex number recognition and comments.
258
-
259
- You can test the parser using:
260
-
261
- JSON_FILENAME="foo.json"
262
-
263
- require 'json'
264
- require 'iodine'
265
- TIMES = 100
266
- STR = IO.binread(JSON_FILENAME); nil
267
-
268
- JSON.parse(STR) == Iodine::JSON.parse(STR) # => true
269
- JSON.parse(STR,
270
- symbolize_names: true) == Iodine::JSON.parse(STR,
271
- symbolize_names: true) # => true
272
- JSON.parse!(STR) == Iodine::JSON.parse!(STR) # => true/false (unknown)
273
-
274
- # warm-up
275
- TIMES.times { JSON.parse STR }
276
- TIMES.times { Iodine::JSON.parse STR }
277
-
278
- Benchmark.bm do |b|
279
- sys = b.report("system") { TIMES.times { JSON.parse STR } }
280
- sys_sym = b.report("system sym") { TIMES.times { JSON.parse STR,
281
- symbolize_names: true } }
282
- iodine = b.report("iodine") { TIMES.times { Iodine::JSON.parse STR } }
283
- iodine_sym = b.report("iodine sym") do
284
- TIMES.times { Iodine::JSON.parse STR,
285
- symbolize_names: true }
286
- end
287
- puts "System / Iodine: #{sys/iodine}"
288
- puts "System-sym/Iodine-sym: #{sys_sym/iodine_sym}"
289
- end; nil
290
-
291
-
292
- */
293
- VALUE tmp = rb_define_module_under(IodineModule, "JSON");
294
- max_nesting = ID2SYM(rb_intern("max_nesting"));
295
- allow_nan = ID2SYM(rb_intern("allow_nan"));
296
- symbolize_names = ID2SYM(rb_intern("symbolize_names"));
297
- create_additions = ID2SYM(rb_intern("create_additions"));
298
- object_class = ID2SYM(rb_intern("object_class"));
299
- array_class = ID2SYM(rb_intern("array_class"));
300
- rb_define_module_function(tmp, "parse", iodine_json_parse, -1);
301
- rb_define_module_function(tmp, "parse!", iodine_json_parse_bang, -1);
302
- }
1
+ #include "iodine.h"
2
+
3
+ #include "fio.h"
4
+
5
+ #include "fio_json_parser.h"
6
+ #include "fiobj.h"
7
+ #include "iodine_fiobj2rb.h"
8
+ #include "iodine_store.h"
9
+
10
+ static VALUE max_nesting;
11
+ static VALUE allow_nan;
12
+ static VALUE symbolize_names;
13
+ static VALUE create_additions;
14
+ static VALUE object_class;
15
+ static VALUE array_class;
16
+
17
+ #define FIO_ARY_NAME fio_json_stack
18
+ #define FIO_ARY_TYPE VALUE
19
+ #include "fio.h"
20
+
21
+ /* *****************************************************************************
22
+ JSON Callacks - these must be implemented in the C file that uses the parser
23
+ ***************************************************************************** */
24
+
25
+ /* *****************************************************************************
26
+ JSON Parser handling (practically copied from the FIOBJ library)
27
+ ***************************************************************************** */
28
+
29
+ typedef struct {
30
+ json_parser_s p;
31
+ VALUE key;
32
+ VALUE top;
33
+ VALUE target;
34
+ fio_json_stack_s stack;
35
+ uint8_t is_hash;
36
+ uint8_t symbolize;
37
+ } iodine_json_parser_s;
38
+
39
+ static inline void iodine_json_add2parser(iodine_json_parser_s *p, VALUE o) {
40
+ if (p->top) {
41
+ if (p->is_hash) {
42
+ if (p->key) {
43
+ rb_hash_aset(p->top, p->key, o);
44
+ IodineStore.remove(p->key);
45
+ p->key = (VALUE)0;
46
+ } else {
47
+ p->key = o;
48
+ IodineStore.add(o);
49
+ }
50
+ } else {
51
+ rb_ary_push(p->top, o);
52
+ }
53
+ } else {
54
+ IodineStore.add(o);
55
+ p->top = o;
56
+ }
57
+ }
58
+
59
+ /** a NULL object was detected */
60
+ static void fio_json_on_null(json_parser_s *p) {
61
+ iodine_json_add2parser((iodine_json_parser_s *)p, Qnil);
62
+ }
63
+ /** a TRUE object was detected */
64
+ static void fio_json_on_true(json_parser_s *p) {
65
+ iodine_json_add2parser((iodine_json_parser_s *)p, Qtrue);
66
+ }
67
+ /** a FALSE object was detected */
68
+ static void fio_json_on_false(json_parser_s *p) {
69
+ iodine_json_add2parser((iodine_json_parser_s *)p, Qfalse);
70
+ }
71
+ /** a Numberl was detected (long long). */
72
+ static void fio_json_on_number(json_parser_s *p, long long i) {
73
+ iodine_json_add2parser((iodine_json_parser_s *)p, LONG2NUM(i));
74
+ }
75
+ /** a Float was detected (double). */
76
+ static void fio_json_on_float(json_parser_s *p, double f) {
77
+ iodine_json_add2parser((iodine_json_parser_s *)p, DBL2NUM(f));
78
+ }
79
+ /** a String was detected (int / float). update `pos` to point at ending */
80
+ static void fio_json_on_string(json_parser_s *p, void *start, size_t length) {
81
+ /* Ruby overhead for a rb_str_buf_new is very high. Double copy is faster. */
82
+ char *tmp = fio_malloc(length);
83
+ size_t new_len = fio_json_unescape_str(tmp, start, length);
84
+ VALUE buf;
85
+ if (((iodine_json_parser_s *)p)->symbolize &&
86
+ ((iodine_json_parser_s *)p)->is_hash &&
87
+ !((iodine_json_parser_s *)p)->key) {
88
+ ID id = rb_intern2(tmp, new_len);
89
+ buf = rb_id2sym(id);
90
+ } else {
91
+ buf = rb_str_new(tmp, new_len);
92
+ }
93
+ iodine_json_add2parser((iodine_json_parser_s *)p, buf);
94
+ fio_free(tmp);
95
+ }
96
+ /** a dictionary object was detected, should return 0 unless error occurred. */
97
+ static int fio_json_on_start_object(json_parser_s *p) {
98
+ iodine_json_parser_s *pr = (iodine_json_parser_s *)p;
99
+ if (pr->target) {
100
+ /* push NULL, don't free the objects */
101
+ fio_json_stack_push(&pr->stack, pr->top);
102
+ pr->top = pr->target;
103
+ pr->target = 0;
104
+ } else {
105
+ VALUE h = rb_hash_new();
106
+ iodine_json_add2parser(pr, h);
107
+ fio_json_stack_push(&pr->stack, pr->top);
108
+ pr->top = h;
109
+ }
110
+ pr->is_hash = 1;
111
+ return 0;
112
+ }
113
+ /** a dictionary object closure detected */
114
+ static void fio_json_on_end_object(json_parser_s *p) {
115
+ iodine_json_parser_s *pr = (iodine_json_parser_s *)p;
116
+ if (pr->key) {
117
+ FIO_LOG_WARNING("(JSON parsing) malformed JSON, "
118
+ "ignoring dangling Hash key.");
119
+ IodineStore.remove(pr->key);
120
+ pr->key = (VALUE)0;
121
+ }
122
+ fio_json_stack_pop(&pr->stack, &pr->top);
123
+ pr->is_hash = (TYPE(pr->top) == T_HASH);
124
+ }
125
+ /** an array object was detected */
126
+ static int fio_json_on_start_array(json_parser_s *p) {
127
+ iodine_json_parser_s *pr = (iodine_json_parser_s *)p;
128
+ if (pr->target)
129
+ return -1;
130
+ VALUE ary = rb_ary_new();
131
+ iodine_json_add2parser(pr, ary);
132
+ fio_json_stack_push(&pr->stack, pr->top);
133
+ pr->top = ary;
134
+ pr->is_hash = 0;
135
+ return 0;
136
+ }
137
+ /** an array closure was detected */
138
+ static void fio_json_on_end_array(json_parser_s *p) {
139
+ iodine_json_parser_s *pr = (iodine_json_parser_s *)p;
140
+ fio_json_stack_pop(&pr->stack, &pr->top);
141
+ pr->is_hash = (TYPE(pr->top) == T_HASH);
142
+ }
143
+ /** the JSON parsing is complete */
144
+ static void fio_json_on_json(json_parser_s *p) { (void)p; /* do nothing */ }
145
+ /** the JSON parsing is complete */
146
+ static void fio_json_on_error(json_parser_s *p) {
147
+ iodine_json_parser_s *pr = (iodine_json_parser_s *)p;
148
+ #if DEBUG
149
+ FIO_LOG_ERROR("JSON on error called.");
150
+ #endif
151
+ IodineStore.remove((VALUE)fio_json_stack_get(&pr->stack, 0));
152
+ IodineStore.remove(pr->key);
153
+ fio_json_stack_free(&pr->stack);
154
+ *pr = (iodine_json_parser_s){.top = 0};
155
+ }
156
+
157
+ /* *****************************************************************************
158
+ Iodine JSON Implementation
159
+ ***************************************************************************** */
160
+
161
+ static inline VALUE iodine_json_convert(VALUE str, fiobj2rb_settings_s s) {
162
+
163
+ iodine_json_parser_s p = {.top = 0, .symbolize = s.str2sym};
164
+ size_t consumed = fio_json_parse(&p.p, RSTRING_PTR(str), RSTRING_LEN(str));
165
+ if (!consumed || p.p.depth) {
166
+ IodineStore.remove((VALUE)fio_json_stack_get(&p.stack, 0));
167
+ p.top = FIOBJ_INVALID;
168
+ }
169
+ fio_json_stack_free(&p.stack);
170
+ if (p.key) {
171
+ IodineStore.remove((VALUE)p.key);
172
+ }
173
+ if (!p.top) {
174
+ rb_raise(rb_eEncodingError, "Malformed JSON format.");
175
+ }
176
+ IodineStore.remove(p.top);
177
+ return p.top;
178
+ }
179
+
180
+ // static inline VALUE iodine_json_convert2(VALUE str, fiobj2rb_settings_s s) {
181
+ // FIOBJ json;
182
+ // if (!fiobj_json2obj(&json, RSTRING_PTR(str), RSTRING_LEN(str)) || !json) {
183
+ // rb_raise(rb_eRuntimeError, "JSON parsing failed. Not JSON?");
184
+ // return Qnil;
185
+ // }
186
+ // VALUE ret = fiobj2rb_deep(json, s.str2sym);
187
+ // fiobj_free(json);
188
+ // IodineStore.remove(ret);
189
+ // return ret;
190
+ // }
191
+
192
+ static inline void iodine_json_update_settings(VALUE h,
193
+ fiobj2rb_settings_s *s) {
194
+ VALUE tmp;
195
+ if (rb_hash_aref(h, max_nesting) != Qnil)
196
+ FIO_LOG_WARNING("max_nesting ignored on this JSON implementation.");
197
+ if (rb_hash_aref(h, allow_nan) != Qnil)
198
+ fprintf(stderr, "WARNING: allow_nan ignored on this JSON implementation. "
199
+ "NaN always allowed.\n");
200
+ if (rb_hash_aref(h, create_additions) != Qnil)
201
+ FIO_LOG_WARNING("create_additions ignored on this JSON implementation.");
202
+ if (rb_hash_aref(h, object_class) != Qnil)
203
+ FIO_LOG_WARNING("object_class ignored on this JSON implementation.");
204
+ if (rb_hash_aref(h, array_class) != Qnil)
205
+ FIO_LOG_WARNING("array_class ignored on this JSON implementation.");
206
+ if ((tmp = rb_hash_aref(h, symbolize_names)) != Qnil) {
207
+ if (tmp == Qtrue)
208
+ s->str2sym = 1;
209
+ else if (tmp == Qfalse)
210
+ s->str2sym = 0;
211
+ }
212
+ }
213
+
214
+ /**
215
+ Parse a JSON string using the iodine lenient parser (it's also faster).
216
+ */
217
+ static VALUE iodine_json_parse(int argc, VALUE *argv, VALUE self) {
218
+ fiobj2rb_settings_s s = {.str2sym = 0};
219
+ if (argc > 2)
220
+ rb_raise(rb_eTypeError, "function requires supports up to two arguments.");
221
+ if (argc == 2) {
222
+ Check_Type(argv[1], T_HASH);
223
+ iodine_json_update_settings(argv[1], &s);
224
+ }
225
+ if (argc >= 1)
226
+ Check_Type(argv[0], T_STRING);
227
+ else
228
+ rb_raise(rb_eTypeError, "function requires at least one argument.");
229
+ return iodine_json_convert(argv[0], s);
230
+ (void)self;
231
+ }
232
+
233
+ /**
234
+ Parse a JSON string using the iodine lenient parser with a default Symbol
235
+ rather than String key (this is often faster than the regular
236
+ {Iodine::JSON.parse} function).
237
+ */
238
+ static VALUE iodine_json_parse_bang(int argc, VALUE *argv, VALUE self) {
239
+ fiobj2rb_settings_s s = {.str2sym = 0};
240
+ if (argc > 2)
241
+ rb_raise(rb_eTypeError, "function requires supports up to two arguments.");
242
+ if (argc == 2) {
243
+ Check_Type(argv[1], T_HASH);
244
+ iodine_json_update_settings(argv[1], &s);
245
+ }
246
+ if (argc >= 1)
247
+ Check_Type(argv[0], T_STRING);
248
+ else
249
+ rb_raise(rb_eTypeError, "function requires at least one argument.");
250
+ return iodine_json_convert(argv[0], s);
251
+ (void)self;
252
+ }
253
+
254
+ void iodine_init_json(void) {
255
+ /**
256
+ Iodine::JSON offers a fast(er) JSON parser that is also lenient and supports
257
+ some JSON extensions such as Hex number recognition and comments.
258
+
259
+ You can test the parser using:
260
+
261
+ JSON_FILENAME="foo.json"
262
+
263
+ require 'json'
264
+ require 'iodine'
265
+ TIMES = 100
266
+ STR = IO.binread(JSON_FILENAME); nil
267
+
268
+ JSON.parse(STR) == Iodine::JSON.parse(STR) # => true
269
+ JSON.parse(STR,
270
+ symbolize_names: true) == Iodine::JSON.parse(STR,
271
+ symbolize_names: true) # => true
272
+ JSON.parse!(STR) == Iodine::JSON.parse!(STR) # => true/false (unknown)
273
+
274
+ # warm-up
275
+ TIMES.times { JSON.parse STR }
276
+ TIMES.times { Iodine::JSON.parse STR }
277
+
278
+ Benchmark.bm do |b|
279
+ sys = b.report("system") { TIMES.times { JSON.parse STR } }
280
+ sys_sym = b.report("system sym") { TIMES.times { JSON.parse STR,
281
+ symbolize_names: true } }
282
+ iodine = b.report("iodine") { TIMES.times { Iodine::JSON.parse STR } }
283
+ iodine_sym = b.report("iodine sym") do
284
+ TIMES.times { Iodine::JSON.parse STR,
285
+ symbolize_names: true }
286
+ end
287
+ puts "System / Iodine: #{sys/iodine}"
288
+ puts "System-sym/Iodine-sym: #{sys_sym/iodine_sym}"
289
+ end; nil
290
+
291
+
292
+ */
293
+ VALUE tmp = rb_define_module_under(IodineModule, "JSON");
294
+ max_nesting = ID2SYM(rb_intern("max_nesting"));
295
+ allow_nan = ID2SYM(rb_intern("allow_nan"));
296
+ symbolize_names = ID2SYM(rb_intern("symbolize_names"));
297
+ create_additions = ID2SYM(rb_intern("create_additions"));
298
+ object_class = ID2SYM(rb_intern("object_class"));
299
+ array_class = ID2SYM(rb_intern("array_class"));
300
+ rb_define_module_function(tmp, "parse", iodine_json_parse, -1);
301
+ rb_define_module_function(tmp, "parse!", iodine_json_parse_bang, -1);
302
+ }
@@ -1,6 +1,6 @@
1
- #ifndef H_IODINE_JSON_H
2
- #define H_IODINE_JSON_H
3
-
4
- void iodine_init_json(void);
5
-
6
- #endif
1
+ #ifndef H_IODINE_JSON_H
2
+ #define H_IODINE_JSON_H
3
+
4
+ void iodine_init_json(void);
5
+
6
+ #endif
File without changes
@@ -1,6 +1,6 @@
1
- #ifndef H_IODINE_MUSTACHE_H
2
- #define H_IODINE_MUSTACHE_H
3
-
4
- void iodine_init_mustache(void);
5
-
6
- #endif
1
+ #ifndef H_IODINE_MUSTACHE_H
2
+ #define H_IODINE_MUSTACHE_H
3
+
4
+ void iodine_init_mustache(void);
5
+
6
+ #endif
File without changes