json 2.7.4 → 2.10.1

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.
@@ -1,13 +1,171 @@
1
+ #include "ruby.h"
1
2
  #include "../fbuffer/fbuffer.h"
2
- #include "generator.h"
3
+
4
+ #include <math.h>
5
+ #include <ctype.h>
6
+
7
+ /* ruby api and some helpers */
8
+
9
+ typedef struct JSON_Generator_StateStruct {
10
+ VALUE indent;
11
+ VALUE space;
12
+ VALUE space_before;
13
+ VALUE object_nl;
14
+ VALUE array_nl;
15
+ VALUE as_json;
16
+
17
+ long max_nesting;
18
+ long depth;
19
+ long buffer_initial_length;
20
+
21
+ bool allow_nan;
22
+ bool ascii_only;
23
+ bool script_safe;
24
+ bool strict;
25
+ } JSON_Generator_State;
3
26
 
4
27
  #ifndef RB_UNLIKELY
5
28
  #define RB_UNLIKELY(cond) (cond)
6
29
  #endif
7
30
 
8
- static VALUE mJSON, cState, mString_Extend, eGeneratorError, eNestingError, Encoding_UTF_8;
31
+ static VALUE mJSON, cState, cFragment, mString_Extend, eGeneratorError, eNestingError, Encoding_UTF_8;
9
32
 
10
33
  static ID i_to_s, i_to_json, i_new, i_pack, i_unpack, i_create_id, i_extend, i_encode;
34
+ static VALUE sym_indent, sym_space, sym_space_before, sym_object_nl, sym_array_nl, sym_max_nesting, sym_allow_nan,
35
+ sym_ascii_only, sym_depth, sym_buffer_initial_length, sym_script_safe, sym_escape_slash, sym_strict, sym_as_json;
36
+
37
+
38
+ #define GET_STATE_TO(self, state) \
39
+ TypedData_Get_Struct(self, JSON_Generator_State, &JSON_Generator_State_type, state)
40
+
41
+ #define GET_STATE(self) \
42
+ JSON_Generator_State *state; \
43
+ GET_STATE_TO(self, state)
44
+
45
+ struct generate_json_data;
46
+
47
+ typedef void (*generator_func)(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
48
+
49
+ struct generate_json_data {
50
+ FBuffer *buffer;
51
+ VALUE vstate;
52
+ JSON_Generator_State *state;
53
+ VALUE obj;
54
+ generator_func func;
55
+ };
56
+
57
+ static VALUE cState_from_state_s(VALUE self, VALUE opts);
58
+ static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func, VALUE io);
59
+ static void generate_json(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
60
+ static void generate_json_object(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
61
+ static void generate_json_array(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
62
+ static void generate_json_string(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
63
+ static void generate_json_null(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
64
+ static void generate_json_false(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
65
+ static void generate_json_true(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
66
+ #ifdef RUBY_INTEGER_UNIFICATION
67
+ static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
68
+ #endif
69
+ static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
70
+ static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
71
+ static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
72
+ static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
73
+
74
+ static int usascii_encindex, utf8_encindex, binary_encindex;
75
+
76
+ #ifdef RBIMPL_ATTR_NORETURN
77
+ RBIMPL_ATTR_NORETURN()
78
+ #endif
79
+ static void raise_generator_error_str(VALUE invalid_object, VALUE str)
80
+ {
81
+ VALUE exc = rb_exc_new_str(eGeneratorError, str);
82
+ rb_ivar_set(exc, rb_intern("@invalid_object"), invalid_object);
83
+ rb_exc_raise(exc);
84
+ }
85
+
86
+ #ifdef RBIMPL_ATTR_NORETURN
87
+ RBIMPL_ATTR_NORETURN()
88
+ #endif
89
+ #ifdef RBIMPL_ATTR_FORMAT
90
+ RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 2, 3)
91
+ #endif
92
+ static void raise_generator_error(VALUE invalid_object, const char *fmt, ...)
93
+ {
94
+ va_list args;
95
+ va_start(args, fmt);
96
+ VALUE str = rb_vsprintf(fmt, args);
97
+ va_end(args);
98
+ raise_generator_error_str(invalid_object, str);
99
+ }
100
+
101
+ // 0 - single byte char that don't need to be escaped.
102
+ // (x | 8) - char that needs to be escaped.
103
+ static const unsigned char CHAR_LENGTH_MASK = 7;
104
+ static const unsigned char ESCAPE_MASK = 8;
105
+
106
+ typedef struct _search_state {
107
+ const char *ptr;
108
+ const char *end;
109
+ const char *cursor;
110
+ FBuffer *buffer;
111
+ } search_state;
112
+
113
+ static inline void search_flush(search_state *search)
114
+ {
115
+ fbuffer_append(search->buffer, search->cursor, search->ptr - search->cursor);
116
+ search->cursor = search->ptr;
117
+ }
118
+
119
+ static const unsigned char escape_table_basic[256] = {
120
+ // ASCII Control Characters
121
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
122
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
123
+ // ASCII Characters
124
+ 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // '"'
125
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
126
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
127
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, // '\\'
128
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
129
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
130
+ };
131
+
132
+ static inline unsigned char search_escape_basic(search_state *search)
133
+ {
134
+ while (search->ptr < search->end) {
135
+ if (RB_UNLIKELY(escape_table_basic[(const unsigned char)*search->ptr])) {
136
+ search_flush(search);
137
+ return 1;
138
+ } else {
139
+ search->ptr++;
140
+ }
141
+ }
142
+ search_flush(search);
143
+ return 0;
144
+ }
145
+
146
+ static inline void escape_UTF8_char_basic(search_state *search) {
147
+ const unsigned char ch = (unsigned char)*search->ptr;
148
+ switch (ch) {
149
+ case '"': fbuffer_append(search->buffer, "\\\"", 2); break;
150
+ case '\\': fbuffer_append(search->buffer, "\\\\", 2); break;
151
+ case '/': fbuffer_append(search->buffer, "\\/", 2); break;
152
+ case '\b': fbuffer_append(search->buffer, "\\b", 2); break;
153
+ case '\f': fbuffer_append(search->buffer, "\\f", 2); break;
154
+ case '\n': fbuffer_append(search->buffer, "\\n", 2); break;
155
+ case '\r': fbuffer_append(search->buffer, "\\r", 2); break;
156
+ case '\t': fbuffer_append(search->buffer, "\\t", 2); break;
157
+ default: {
158
+ const char *hexdig = "0123456789abcdef";
159
+ char scratch[6] = { '\\', 'u', '0', '0', 0, 0 };
160
+ scratch[4] = hexdig[(ch >> 4) & 0xf];
161
+ scratch[5] = hexdig[ch & 0xf];
162
+ fbuffer_append(search->buffer, scratch, 6);
163
+ break;
164
+ }
165
+ }
166
+ search->ptr++;
167
+ search->cursor = search->ptr;
168
+ }
11
169
 
12
170
  /* Converts in_string to a JSON string (without the wrapping '"'
13
171
  * characters) in FBuffer out_buffer.
@@ -19,296 +177,241 @@ static ID i_to_s, i_to_json, i_new, i_pack, i_unpack, i_create_id, i_extend, i_e
19
177
  *
20
178
  * - If out_ascii_only: non-ASCII characters (>0x7F)
21
179
  *
22
- * - If out_script_safe: forwardslash, line separator (U+2028), and
180
+ * - If script_safe: forwardslash (/), line separator (U+2028), and
23
181
  * paragraph separator (U+2029)
24
182
  *
25
183
  * Everything else (should be UTF-8) is just passed through and
26
184
  * appended to the result.
27
185
  */
28
- static void convert_UTF8_to_JSON(FBuffer *out_buffer, VALUE str, const char escape_table[256], bool out_script_safe)
186
+ static inline void convert_UTF8_to_JSON(search_state *search)
29
187
  {
30
- const char *hexdig = "0123456789abcdef";
31
- char scratch[12] = { '\\', 'u', 0, 0, 0, 0, '\\', 'u' };
32
-
33
- const char *ptr = RSTRING_PTR(str);
34
- unsigned long len = RSTRING_LEN(str);
188
+ while (search_escape_basic(search)) {
189
+ escape_UTF8_char_basic(search);
190
+ }
191
+ }
35
192
 
36
- unsigned long beg = 0, pos = 0;
193
+ static inline void escape_UTF8_char(search_state *search, unsigned char ch_len) {
194
+ const unsigned char ch = (unsigned char)*search->ptr;
195
+ switch (ch_len) {
196
+ case 1: {
197
+ switch (ch) {
198
+ case '"': fbuffer_append(search->buffer, "\\\"", 2); break;
199
+ case '\\': fbuffer_append(search->buffer, "\\\\", 2); break;
200
+ case '/': fbuffer_append(search->buffer, "\\/", 2); break;
201
+ case '\b': fbuffer_append(search->buffer, "\\b", 2); break;
202
+ case '\f': fbuffer_append(search->buffer, "\\f", 2); break;
203
+ case '\n': fbuffer_append(search->buffer, "\\n", 2); break;
204
+ case '\r': fbuffer_append(search->buffer, "\\r", 2); break;
205
+ case '\t': fbuffer_append(search->buffer, "\\t", 2); break;
206
+ default: {
207
+ const char *hexdig = "0123456789abcdef";
208
+ char scratch[6] = { '\\', 'u', '0', '0', 0, 0 };
209
+ scratch[4] = hexdig[(ch >> 4) & 0xf];
210
+ scratch[5] = hexdig[ch & 0xf];
211
+ fbuffer_append(search->buffer, scratch, 6);
212
+ break;
213
+ }
214
+ }
215
+ break;
216
+ }
217
+ case 3: {
218
+ if (search->ptr[2] & 1) {
219
+ fbuffer_append(search->buffer, "\\u2029", 6);
220
+ } else {
221
+ fbuffer_append(search->buffer, "\\u2028", 6);
222
+ }
223
+ break;
224
+ }
225
+ }
226
+ search->cursor = (search->ptr += ch_len);
227
+ }
37
228
 
38
- #define FLUSH_POS(bytes) if (pos > beg) { fbuffer_append(out_buffer, &ptr[beg], pos - beg); } pos += bytes; beg = pos;
229
+ static const unsigned char script_safe_escape_table[256] = {
230
+ // ASCII Control Characters
231
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
232
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
233
+ // ASCII Characters
234
+ 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, // '"' and '/'
235
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
236
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
237
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, // '\\'
238
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
239
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
240
+ // Continuation byte
241
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
242
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
243
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
244
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
245
+ // First byte of a 2-byte code point
246
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
247
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
248
+ // First byte of a 3-byte code point
249
+ 3, 3,11, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xE2 is the start of \u2028 and \u2029
250
+ //First byte of a 4+ byte code point
251
+ 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 9, 9,
252
+ };
39
253
 
40
- while (pos < len) {
41
- unsigned char ch = ptr[pos];
42
- unsigned char ch_len = escape_table[ch];
43
- /* JSON encoding */
254
+ static inline unsigned char search_script_safe_escape(search_state *search)
255
+ {
256
+ while (search->ptr < search->end) {
257
+ unsigned char ch = (unsigned char)*search->ptr;
258
+ unsigned char ch_len = script_safe_escape_table[ch];
44
259
 
45
260
  if (RB_UNLIKELY(ch_len)) {
46
- switch (ch_len) {
47
- case 0:
48
- pos++;
49
- break;
50
- case 1: {
51
- FLUSH_POS(1);
52
- switch (ch) {
53
- case '"': fbuffer_append(out_buffer, "\\\"", 2); break;
54
- case '\\': fbuffer_append(out_buffer, "\\\\", 2); break;
55
- case '/': fbuffer_append(out_buffer, "\\/", 2); break;
56
- case '\b': fbuffer_append(out_buffer, "\\b", 2); break;
57
- case '\f': fbuffer_append(out_buffer, "\\f", 2); break;
58
- case '\n': fbuffer_append(out_buffer, "\\n", 2); break;
59
- case '\r': fbuffer_append(out_buffer, "\\r", 2); break;
60
- case '\t': fbuffer_append(out_buffer, "\\t", 2); break;
61
- default: {
62
- scratch[2] = hexdig[ch >> 12];
63
- scratch[3] = hexdig[(ch >> 8) & 0xf];
64
- scratch[4] = hexdig[(ch >> 4) & 0xf];
65
- scratch[5] = hexdig[ch & 0xf];
66
- fbuffer_append(out_buffer, scratch, 6);
67
- break;
68
- }
261
+ if (ch_len & ESCAPE_MASK) {
262
+ if (RB_UNLIKELY(ch_len == 11)) {
263
+ const unsigned char *uptr = (const unsigned char *)search->ptr;
264
+ if (!(uptr[1] == 0x80 && (uptr[2] >> 1) == 0x54)) {
265
+ search->ptr += 3;
266
+ continue;
69
267
  }
70
- break;
71
- }
72
- case 3: {
73
- unsigned char b2 = ptr[pos + 1];
74
- if (RB_UNLIKELY(out_script_safe && b2 == 0x80)) {
75
- unsigned char b3 = ptr[pos + 2];
76
- if (b3 == 0xA8) {
77
- FLUSH_POS(3);
78
- fbuffer_append(out_buffer, "\\u2028", 6);
79
- break;
80
- } else if (b3 == 0xA9) {
81
- FLUSH_POS(3);
82
- fbuffer_append(out_buffer, "\\u2029", 6);
83
- break;
84
- }
85
- }
86
- // fallthrough
87
268
  }
88
- default:
89
- pos += ch_len;
90
- break;
269
+ search_flush(search);
270
+ return ch_len & CHAR_LENGTH_MASK;
271
+ } else {
272
+ search->ptr += ch_len;
91
273
  }
92
274
  } else {
93
- pos++;
275
+ search->ptr++;
94
276
  }
95
277
  }
96
- #undef FLUSH_POS
278
+ search_flush(search);
279
+ return 0;
280
+ }
97
281
 
98
- if (beg < len) {
99
- fbuffer_append(out_buffer, &ptr[beg], len - beg);
282
+ static void convert_UTF8_to_script_safe_JSON(search_state *search)
283
+ {
284
+ unsigned char ch_len;
285
+ while ((ch_len = search_script_safe_escape(search))) {
286
+ escape_UTF8_char(search, ch_len);
100
287
  }
101
-
102
- RB_GC_GUARD(str);
103
288
  }
104
289
 
105
- static const char escape_table[256] = {
106
- // ASCII Control Characters
107
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
108
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
109
- // ASCII Characters
110
- 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, // '"'
111
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
112
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
113
- 0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0, // '\\'
114
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
115
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
116
- // Continuation byte
117
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
118
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
119
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
120
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
121
- // First byte of a 2-byte code point
122
- 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
123
- 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
124
- // First byte of a 4-byte code point
125
- 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
126
- //First byte of a 4+byte code point
127
- 4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1,
128
- };
129
-
130
- static const char script_safe_escape_table[256] = {
290
+ static const unsigned char ascii_only_escape_table[256] = {
131
291
  // ASCII Control Characters
132
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
133
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
292
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
293
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
134
294
  // ASCII Characters
135
- 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1, // '"' and '/'
136
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
137
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
138
- 0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0, // '\\'
139
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
140
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
295
+ 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // '"'
296
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
297
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
298
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, // '\\'
299
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
300
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
141
301
  // Continuation byte
142
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
143
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
144
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
145
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
146
- // First byte of a 2-byte code point
147
- 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
148
- 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
149
- // First byte of a 4-byte code point
150
- 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
151
- //First byte of a 4+byte code point
152
- 4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1,
302
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
303
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
304
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
305
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
306
+ // First byte of a 2-byte code point
307
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
308
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
309
+ // First byte of a 3-byte code point
310
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
311
+ //First byte of a 4+ byte code point
312
+ 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 9, 9,
153
313
  };
154
314
 
155
- static void convert_ASCII_to_JSON(FBuffer *out_buffer, VALUE str, const char escape_table[256])
315
+ static inline unsigned char search_ascii_only_escape(search_state *search, const unsigned char escape_table[256])
156
316
  {
157
- const char *hexdig = "0123456789abcdef";
158
- char scratch[12] = { '\\', 'u', 0, 0, 0, 0, '\\', 'u' };
159
-
160
- const char *ptr = RSTRING_PTR(str);
161
- unsigned long len = RSTRING_LEN(str);
162
-
163
- unsigned long beg = 0, pos;
317
+ while (search->ptr < search->end) {
318
+ unsigned char ch = (unsigned char)*search->ptr;
319
+ unsigned char ch_len = escape_table[ch];
164
320
 
165
- for (pos = 0; pos < len;) {
166
- unsigned char ch = ptr[pos];
167
- /* JSON encoding */
168
- if (escape_table[ch]) {
169
- if (pos > beg) {
170
- fbuffer_append(out_buffer, &ptr[beg], pos - beg);
171
- }
321
+ if (RB_UNLIKELY(ch_len)) {
322
+ search_flush(search);
323
+ return ch_len & CHAR_LENGTH_MASK;
324
+ } else {
325
+ search->ptr++;
326
+ }
327
+ }
328
+ search_flush(search);
329
+ return 0;
330
+ }
172
331
 
173
- beg = pos + 1;
332
+ static inline void full_escape_UTF8_char(search_state *search, unsigned char ch_len) {
333
+ const unsigned char ch = (unsigned char)*search->ptr;
334
+ switch (ch_len) {
335
+ case 1: {
174
336
  switch (ch) {
175
- case '"': fbuffer_append(out_buffer, "\\\"", 2); break;
176
- case '\\': fbuffer_append(out_buffer, "\\\\", 2); break;
177
- case '/': fbuffer_append(out_buffer, "\\/", 2); break;
178
- case '\b': fbuffer_append(out_buffer, "\\b", 2); break;
179
- case '\f': fbuffer_append(out_buffer, "\\f", 2); break;
180
- case '\n': fbuffer_append(out_buffer, "\\n", 2); break;
181
- case '\r': fbuffer_append(out_buffer, "\\r", 2); break;
182
- case '\t': fbuffer_append(out_buffer, "\\t", 2); break;
183
- default:
184
- scratch[2] = hexdig[ch >> 12];
185
- scratch[3] = hexdig[(ch >> 8) & 0xf];
337
+ case '"': fbuffer_append(search->buffer, "\\\"", 2); break;
338
+ case '\\': fbuffer_append(search->buffer, "\\\\", 2); break;
339
+ case '/': fbuffer_append(search->buffer, "\\/", 2); break;
340
+ case '\b': fbuffer_append(search->buffer, "\\b", 2); break;
341
+ case '\f': fbuffer_append(search->buffer, "\\f", 2); break;
342
+ case '\n': fbuffer_append(search->buffer, "\\n", 2); break;
343
+ case '\r': fbuffer_append(search->buffer, "\\r", 2); break;
344
+ case '\t': fbuffer_append(search->buffer, "\\t", 2); break;
345
+ default: {
346
+ const char *hexdig = "0123456789abcdef";
347
+ char scratch[6] = { '\\', 'u', '0', '0', 0, 0 };
186
348
  scratch[4] = hexdig[(ch >> 4) & 0xf];
187
349
  scratch[5] = hexdig[ch & 0xf];
188
- fbuffer_append(out_buffer, scratch, 6);
350
+ fbuffer_append(search->buffer, scratch, 6);
351
+ break;
352
+ }
189
353
  }
354
+ break;
190
355
  }
356
+ default: {
357
+ const char *hexdig = "0123456789abcdef";
358
+ char scratch[12] = { '\\', 'u', 0, 0, 0, 0, '\\', 'u' };
191
359
 
192
- pos++;
193
- }
194
-
195
- if (beg < len) {
196
- fbuffer_append(out_buffer, &ptr[beg], len - beg);
197
- }
198
-
199
- RB_GC_GUARD(str);
200
- }
201
-
202
- static void convert_UTF8_to_ASCII_only_JSON(FBuffer *out_buffer, VALUE str, const char escape_table[256], bool out_script_safe)
203
- {
204
- const char *hexdig = "0123456789abcdef";
205
- char scratch[12] = { '\\', 'u', 0, 0, 0, 0, '\\', 'u' };
206
-
207
- const char *ptr = RSTRING_PTR(str);
208
- unsigned long len = RSTRING_LEN(str);
209
-
210
- unsigned long beg = 0, pos = 0;
211
-
212
- #define FLUSH_POS(bytes) if (pos > beg) { fbuffer_append(out_buffer, &ptr[beg], pos - beg); } pos += bytes; beg = pos;
360
+ uint32_t wchar = 0;
213
361
 
214
- while (pos < len) {
215
- unsigned char ch = ptr[pos];
216
- unsigned char ch_len = escape_table[ch];
217
-
218
- if (RB_UNLIKELY(ch_len)) {
219
- switch (ch_len) {
220
- case 0:
221
- pos++;
362
+ switch(ch_len) {
363
+ case 2:
364
+ wchar = ch & 0x1F;
222
365
  break;
223
- case 1: {
224
- FLUSH_POS(1);
225
- switch (ch) {
226
- case '"': fbuffer_append(out_buffer, "\\\"", 2); break;
227
- case '\\': fbuffer_append(out_buffer, "\\\\", 2); break;
228
- case '/': fbuffer_append(out_buffer, "\\/", 2); break;
229
- case '\b': fbuffer_append(out_buffer, "\\b", 2); break;
230
- case '\f': fbuffer_append(out_buffer, "\\f", 2); break;
231
- case '\n': fbuffer_append(out_buffer, "\\n", 2); break;
232
- case '\r': fbuffer_append(out_buffer, "\\r", 2); break;
233
- case '\t': fbuffer_append(out_buffer, "\\t", 2); break;
234
- default: {
235
- scratch[2] = hexdig[ch >> 12];
236
- scratch[3] = hexdig[(ch >> 8) & 0xf];
237
- scratch[4] = hexdig[(ch >> 4) & 0xf];
238
- scratch[5] = hexdig[ch & 0xf];
239
- fbuffer_append(out_buffer, scratch, 6);
240
- break;
241
- }
242
- }
366
+ case 3:
367
+ wchar = ch & 0x0F;
243
368
  break;
244
- }
245
- default: {
246
- uint32_t wchar = 0;
247
- switch(ch_len) {
248
- case 2:
249
- wchar = ptr[pos] & 0x1F;
250
- break;
251
- case 3:
252
- wchar = ptr[pos] & 0x0F;
253
- break;
254
- case 4:
255
- wchar = ptr[pos] & 0x07;
256
- break;
257
- }
258
-
259
- for (short i = 1; i < ch_len; i++) {
260
- wchar = (wchar << 6) | (ptr[pos+i] & 0x3F);
261
- }
262
-
263
- FLUSH_POS(ch_len);
369
+ case 4:
370
+ wchar = ch & 0x07;
371
+ break;
372
+ }
264
373
 
265
- if (wchar <= 0xFFFF) {
266
- scratch[2] = hexdig[wchar >> 12];
267
- scratch[3] = hexdig[(wchar >> 8) & 0xf];
268
- scratch[4] = hexdig[(wchar >> 4) & 0xf];
269
- scratch[5] = hexdig[wchar & 0xf];
270
- fbuffer_append(out_buffer, scratch, 6);
271
- } else {
272
- uint16_t hi, lo;
273
- wchar -= 0x10000;
274
- hi = 0xD800 + (uint16_t)(wchar >> 10);
275
- lo = 0xDC00 + (uint16_t)(wchar & 0x3FF);
276
-
277
- scratch[2] = hexdig[hi >> 12];
278
- scratch[3] = hexdig[(hi >> 8) & 0xf];
279
- scratch[4] = hexdig[(hi >> 4) & 0xf];
280
- scratch[5] = hexdig[hi & 0xf];
281
-
282
- scratch[8] = hexdig[lo >> 12];
283
- scratch[9] = hexdig[(lo >> 8) & 0xf];
284
- scratch[10] = hexdig[(lo >> 4) & 0xf];
285
- scratch[11] = hexdig[lo & 0xf];
286
-
287
- fbuffer_append(out_buffer, scratch, 12);
288
- }
374
+ for (short i = 1; i < ch_len; i++) {
375
+ wchar = (wchar << 6) | (search->ptr[i] & 0x3F);
376
+ }
289
377
 
290
- break;
291
- }
378
+ if (wchar <= 0xFFFF) {
379
+ scratch[2] = hexdig[wchar >> 12];
380
+ scratch[3] = hexdig[(wchar >> 8) & 0xf];
381
+ scratch[4] = hexdig[(wchar >> 4) & 0xf];
382
+ scratch[5] = hexdig[wchar & 0xf];
383
+ fbuffer_append(search->buffer, scratch, 6);
384
+ } else {
385
+ uint16_t hi, lo;
386
+ wchar -= 0x10000;
387
+ hi = 0xD800 + (uint16_t)(wchar >> 10);
388
+ lo = 0xDC00 + (uint16_t)(wchar & 0x3FF);
389
+
390
+ scratch[2] = hexdig[hi >> 12];
391
+ scratch[3] = hexdig[(hi >> 8) & 0xf];
392
+ scratch[4] = hexdig[(hi >> 4) & 0xf];
393
+ scratch[5] = hexdig[hi & 0xf];
394
+
395
+ scratch[8] = hexdig[lo >> 12];
396
+ scratch[9] = hexdig[(lo >> 8) & 0xf];
397
+ scratch[10] = hexdig[(lo >> 4) & 0xf];
398
+ scratch[11] = hexdig[lo & 0xf];
399
+
400
+ fbuffer_append(search->buffer, scratch, 12);
292
401
  }
293
- } else {
294
- pos++;
295
- }
296
- }
297
- #undef FLUSH_POS
298
402
 
299
- if (beg < len) {
300
- fbuffer_append(out_buffer, &ptr[beg], len - beg);
403
+ break;
404
+ }
301
405
  }
302
-
303
- RB_GC_GUARD(str);
406
+ search->cursor = (search->ptr += ch_len);
304
407
  }
305
408
 
306
- static char *fstrndup(const char *ptr, unsigned long len) {
307
- char *result;
308
- if (len <= 0) return NULL;
309
- result = ALLOC_N(char, len);
310
- memcpy(result, ptr, len);
311
- return result;
409
+ static void convert_UTF8_to_ASCII_only_JSON(search_state *search, const unsigned char escape_table[256])
410
+ {
411
+ unsigned char ch_len;
412
+ while ((ch_len = search_ascii_only_escape(search, escape_table))) {
413
+ full_escape_UTF8_char(search, ch_len);
414
+ }
312
415
  }
313
416
 
314
417
  /*
@@ -403,7 +506,9 @@ static char *fstrndup(const char *ptr, unsigned long len) {
403
506
  */
404
507
  static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self)
405
508
  {
406
- GENERATE_JSON(object);
509
+ rb_check_arity(argc, 0, 1);
510
+ VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
511
+ return cState_partial_generate(Vstate, self, generate_json_object, Qfalse);
407
512
  }
408
513
 
409
514
  /*
@@ -415,7 +520,9 @@ static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self)
415
520
  * produced JSON string output further.
416
521
  */
417
522
  static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) {
418
- GENERATE_JSON(array);
523
+ rb_check_arity(argc, 0, 1);
524
+ VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
525
+ return cState_partial_generate(Vstate, self, generate_json_array, Qfalse);
419
526
  }
420
527
 
421
528
  #ifdef RUBY_INTEGER_UNIFICATION
@@ -426,7 +533,9 @@ static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) {
426
533
  */
427
534
  static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self)
428
535
  {
429
- GENERATE_JSON(integer);
536
+ rb_check_arity(argc, 0, 1);
537
+ VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
538
+ return cState_partial_generate(Vstate, self, generate_json_integer, Qfalse);
430
539
  }
431
540
 
432
541
  #else
@@ -437,7 +546,9 @@ static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self)
437
546
  */
438
547
  static VALUE mFixnum_to_json(int argc, VALUE *argv, VALUE self)
439
548
  {
440
- GENERATE_JSON(fixnum);
549
+ rb_check_arity(argc, 0, 1);
550
+ VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
551
+ return cState_partial_generate(Vstate, self, generate_json_fixnum, Qfalse);
441
552
  }
442
553
 
443
554
  /*
@@ -447,7 +558,9 @@ static VALUE mFixnum_to_json(int argc, VALUE *argv, VALUE self)
447
558
  */
448
559
  static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)
449
560
  {
450
- GENERATE_JSON(bignum);
561
+ rb_check_arity(argc, 0, 1);
562
+ VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
563
+ return cState_partial_generate(Vstate, self, generate_json_bignum, Qfalse);
451
564
  }
452
565
  #endif
453
566
 
@@ -458,7 +571,9 @@ static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)
458
571
  */
459
572
  static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self)
460
573
  {
461
- GENERATE_JSON(float);
574
+ rb_check_arity(argc, 0, 1);
575
+ VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
576
+ return cState_partial_generate(Vstate, self, generate_json_float, Qfalse);
462
577
  }
463
578
 
464
579
  /*
@@ -481,7 +596,9 @@ static VALUE mString_included_s(VALUE self, VALUE modul) {
481
596
  */
482
597
  static VALUE mString_to_json(int argc, VALUE *argv, VALUE self)
483
598
  {
484
- GENERATE_JSON(string);
599
+ rb_check_arity(argc, 0, 1);
600
+ VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
601
+ return cState_partial_generate(Vstate, self, generate_json_string, Qfalse);
485
602
  }
486
603
 
487
604
  /*
@@ -498,7 +615,7 @@ static VALUE mString_to_json_raw_object(VALUE self)
498
615
  VALUE result = rb_hash_new();
499
616
  rb_hash_aset(result, rb_funcall(mJSON, i_create_id, 0), rb_class_name(rb_obj_class(self)));
500
617
  ary = rb_funcall(self, i_unpack, 1, rb_str_new2("C*"));
501
- rb_hash_aset(result, rb_str_new2("raw"), ary);
618
+ rb_hash_aset(result, rb_utf8_str_new_lit("raw"), ary);
502
619
  return result;
503
620
  }
504
621
 
@@ -536,7 +653,8 @@ static VALUE mString_Extend_json_create(VALUE self, VALUE o)
536
653
  */
537
654
  static VALUE mTrueClass_to_json(int argc, VALUE *argv, VALUE self)
538
655
  {
539
- GENERATE_JSON(true);
656
+ rb_check_arity(argc, 0, 1);
657
+ return rb_utf8_str_new("true", 4);
540
658
  }
541
659
 
542
660
  /*
@@ -546,7 +664,8 @@ static VALUE mTrueClass_to_json(int argc, VALUE *argv, VALUE self)
546
664
  */
547
665
  static VALUE mFalseClass_to_json(int argc, VALUE *argv, VALUE self)
548
666
  {
549
- GENERATE_JSON(false);
667
+ rb_check_arity(argc, 0, 1);
668
+ return rb_utf8_str_new("false", 5);
550
669
  }
551
670
 
552
671
  /*
@@ -556,7 +675,8 @@ static VALUE mFalseClass_to_json(int argc, VALUE *argv, VALUE self)
556
675
  */
557
676
  static VALUE mNilClass_to_json(int argc, VALUE *argv, VALUE self)
558
677
  {
559
- GENERATE_JSON(null);
678
+ rb_check_arity(argc, 0, 1);
679
+ return rb_utf8_str_new("null", 4);
560
680
  }
561
681
 
562
682
  /*
@@ -573,30 +693,40 @@ static VALUE mObject_to_json(int argc, VALUE *argv, VALUE self)
573
693
  rb_scan_args(argc, argv, "01", &state);
574
694
  Check_Type(string, T_STRING);
575
695
  state = cState_from_state_s(cState, state);
576
- return cState_partial_generate(state, string);
696
+ return cState_partial_generate(state, string, generate_json_string, Qfalse);
697
+ }
698
+
699
+ static void State_mark(void *ptr)
700
+ {
701
+ JSON_Generator_State *state = ptr;
702
+ rb_gc_mark_movable(state->indent);
703
+ rb_gc_mark_movable(state->space);
704
+ rb_gc_mark_movable(state->space_before);
705
+ rb_gc_mark_movable(state->object_nl);
706
+ rb_gc_mark_movable(state->array_nl);
707
+ rb_gc_mark_movable(state->as_json);
708
+ }
709
+
710
+ static void State_compact(void *ptr)
711
+ {
712
+ JSON_Generator_State *state = ptr;
713
+ state->indent = rb_gc_location(state->indent);
714
+ state->space = rb_gc_location(state->space);
715
+ state->space_before = rb_gc_location(state->space_before);
716
+ state->object_nl = rb_gc_location(state->object_nl);
717
+ state->array_nl = rb_gc_location(state->array_nl);
718
+ state->as_json = rb_gc_location(state->as_json);
577
719
  }
578
720
 
579
721
  static void State_free(void *ptr)
580
722
  {
581
723
  JSON_Generator_State *state = ptr;
582
- if (state->indent) ruby_xfree(state->indent);
583
- if (state->space) ruby_xfree(state->space);
584
- if (state->space_before) ruby_xfree(state->space_before);
585
- if (state->object_nl) ruby_xfree(state->object_nl);
586
- if (state->array_nl) ruby_xfree(state->array_nl);
587
724
  ruby_xfree(state);
588
725
  }
589
726
 
590
727
  static size_t State_memsize(const void *ptr)
591
728
  {
592
- const JSON_Generator_State *state = ptr;
593
- size_t size = sizeof(*state);
594
- if (state->indent) size += state->indent_len + 1;
595
- if (state->space) size += state->space_len + 1;
596
- if (state->space_before) size += state->space_before_len + 1;
597
- if (state->object_nl) size += state->object_nl_len + 1;
598
- if (state->array_nl) size += state->array_nl_len + 1;
599
- return size;
729
+ return sizeof(JSON_Generator_State);
600
730
  }
601
731
 
602
732
  #ifndef HAVE_RB_EXT_RACTOR_SAFE
@@ -606,24 +736,55 @@ static size_t State_memsize(const void *ptr)
606
736
 
607
737
  static const rb_data_type_t JSON_Generator_State_type = {
608
738
  "JSON/Generator/State",
609
- {NULL, State_free, State_memsize,},
739
+ {
740
+ .dmark = State_mark,
741
+ .dfree = State_free,
742
+ .dsize = State_memsize,
743
+ .dcompact = State_compact,
744
+ },
610
745
  0, 0,
611
746
  RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE,
612
747
  };
613
748
 
749
+ static void state_init(JSON_Generator_State *state)
750
+ {
751
+ state->max_nesting = 100;
752
+ state->buffer_initial_length = FBUFFER_INITIAL_LENGTH_DEFAULT;
753
+ }
754
+
614
755
  static VALUE cState_s_allocate(VALUE klass)
615
756
  {
616
757
  JSON_Generator_State *state;
617
758
  VALUE obj = TypedData_Make_Struct(klass, JSON_Generator_State, &JSON_Generator_State_type, state);
618
- state->max_nesting = 100;
619
- state->buffer_initial_length = FBUFFER_INITIAL_LENGTH_DEFAULT;
759
+ state_init(state);
620
760
  return obj;
621
761
  }
622
762
 
763
+ static void vstate_spill(struct generate_json_data *data)
764
+ {
765
+ VALUE vstate = cState_s_allocate(cState);
766
+ GET_STATE(vstate);
767
+ MEMCPY(state, data->state, JSON_Generator_State, 1);
768
+ data->state = state;
769
+ data->vstate = vstate;
770
+ RB_OBJ_WRITTEN(vstate, Qundef, state->indent);
771
+ RB_OBJ_WRITTEN(vstate, Qundef, state->space);
772
+ RB_OBJ_WRITTEN(vstate, Qundef, state->space_before);
773
+ RB_OBJ_WRITTEN(vstate, Qundef, state->object_nl);
774
+ RB_OBJ_WRITTEN(vstate, Qundef, state->array_nl);
775
+ RB_OBJ_WRITTEN(vstate, Qundef, state->as_json);
776
+ }
777
+
778
+ static inline VALUE vstate_get(struct generate_json_data *data)
779
+ {
780
+ if (RB_UNLIKELY(!data->vstate)) {
781
+ vstate_spill(data);
782
+ }
783
+ return data->vstate;
784
+ }
785
+
623
786
  struct hash_foreach_arg {
624
- FBuffer *buffer;
625
- JSON_Generator_State *state;
626
- VALUE Vstate;
787
+ struct generate_json_data *data;
627
788
  int iter;
628
789
  };
629
790
 
@@ -631,27 +792,32 @@ static int
631
792
  json_object_i(VALUE key, VALUE val, VALUE _arg)
632
793
  {
633
794
  struct hash_foreach_arg *arg = (struct hash_foreach_arg *)_arg;
634
- FBuffer *buffer = arg->buffer;
635
- JSON_Generator_State *state = arg->state;
636
- VALUE Vstate = arg->Vstate;
795
+ struct generate_json_data *data = arg->data;
796
+
797
+ FBuffer *buffer = data->buffer;
798
+ JSON_Generator_State *state = data->state;
637
799
 
638
800
  long depth = state->depth;
639
801
  int j;
640
802
 
641
803
  if (arg->iter > 0) fbuffer_append_char(buffer, ',');
642
804
  if (RB_UNLIKELY(state->object_nl)) {
643
- fbuffer_append(buffer, state->object_nl, state->object_nl_len);
805
+ fbuffer_append_str(buffer, state->object_nl);
644
806
  }
645
807
  if (RB_UNLIKELY(state->indent)) {
646
808
  for (j = 0; j < depth; j++) {
647
- fbuffer_append(buffer, state->indent, state->indent_len);
809
+ fbuffer_append_str(buffer, state->indent);
648
810
  }
649
811
  }
650
812
 
651
813
  VALUE key_to_s;
652
814
  switch(rb_type(key)) {
653
815
  case T_STRING:
654
- key_to_s = key;
816
+ if (RB_LIKELY(RBASIC_CLASS(key) == rb_cString)) {
817
+ key_to_s = key;
818
+ } else {
819
+ key_to_s = rb_funcall(key, i_to_s, 0);
820
+ }
655
821
  break;
656
822
  case T_SYMBOL:
657
823
  key_to_s = rb_sym2str(key);
@@ -661,82 +827,97 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
661
827
  break;
662
828
  }
663
829
 
664
- generate_json_string(buffer, Vstate, state, key_to_s);
665
- if (RB_UNLIKELY(state->space_before)) fbuffer_append(buffer, state->space_before, state->space_before_len);
830
+ if (RB_LIKELY(RBASIC_CLASS(key_to_s) == rb_cString)) {
831
+ generate_json_string(buffer, data, state, key_to_s);
832
+ } else {
833
+ generate_json(buffer, data, state, key_to_s);
834
+ }
835
+ if (RB_UNLIKELY(state->space_before)) fbuffer_append_str(buffer, state->space_before);
666
836
  fbuffer_append_char(buffer, ':');
667
- if (RB_UNLIKELY(state->space)) fbuffer_append(buffer, state->space, state->space_len);
668
- generate_json(buffer, Vstate, state, val);
837
+ if (RB_UNLIKELY(state->space)) fbuffer_append_str(buffer, state->space);
838
+ generate_json(buffer, data, state, val);
669
839
 
670
840
  arg->iter++;
671
841
  return ST_CONTINUE;
672
842
  }
673
843
 
674
- static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
844
+ static inline long increase_depth(JSON_Generator_State *state)
675
845
  {
676
- long max_nesting = state->max_nesting;
677
846
  long depth = ++state->depth;
847
+ if (RB_UNLIKELY(depth > state->max_nesting && state->max_nesting)) {
848
+ rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
849
+ }
850
+ return depth;
851
+ }
852
+
853
+ static void generate_json_object(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
854
+ {
678
855
  int j;
679
- struct hash_foreach_arg arg;
856
+ long depth = increase_depth(state);
680
857
 
681
- if (max_nesting != 0 && depth > max_nesting) {
682
- rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
858
+ if (RHASH_SIZE(obj) == 0) {
859
+ fbuffer_append(buffer, "{}", 2);
860
+ --state->depth;
861
+ return;
683
862
  }
863
+
684
864
  fbuffer_append_char(buffer, '{');
685
865
 
686
- arg.buffer = buffer;
687
- arg.state = state;
688
- arg.Vstate = Vstate;
689
- arg.iter = 0;
866
+ struct hash_foreach_arg arg = {
867
+ .data = data,
868
+ .iter = 0,
869
+ };
690
870
  rb_hash_foreach(obj, json_object_i, (VALUE)&arg);
691
871
 
692
872
  depth = --state->depth;
693
873
  if (RB_UNLIKELY(state->object_nl)) {
694
- fbuffer_append(buffer, state->object_nl, state->object_nl_len);
874
+ fbuffer_append_str(buffer, state->object_nl);
695
875
  if (RB_UNLIKELY(state->indent)) {
696
876
  for (j = 0; j < depth; j++) {
697
- fbuffer_append(buffer, state->indent, state->indent_len);
877
+ fbuffer_append_str(buffer, state->indent);
698
878
  }
699
879
  }
700
880
  }
701
881
  fbuffer_append_char(buffer, '}');
702
882
  }
703
883
 
704
- static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
884
+ static void generate_json_array(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
705
885
  {
706
- long max_nesting = state->max_nesting;
707
- long depth = ++state->depth;
708
886
  int i, j;
709
- if (max_nesting != 0 && depth > max_nesting) {
710
- rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
887
+ long depth = increase_depth(state);
888
+
889
+ if (RARRAY_LEN(obj) == 0) {
890
+ fbuffer_append(buffer, "[]", 2);
891
+ --state->depth;
892
+ return;
711
893
  }
894
+
712
895
  fbuffer_append_char(buffer, '[');
713
- if (RB_UNLIKELY(state->array_nl)) fbuffer_append(buffer, state->array_nl, state->array_nl_len);
896
+ if (RB_UNLIKELY(state->array_nl)) fbuffer_append_str(buffer, state->array_nl);
714
897
  for(i = 0; i < RARRAY_LEN(obj); i++) {
715
898
  if (i > 0) {
716
899
  fbuffer_append_char(buffer, ',');
717
- if (RB_UNLIKELY(state->array_nl)) fbuffer_append(buffer, state->array_nl, state->array_nl_len);
900
+ if (RB_UNLIKELY(state->array_nl)) fbuffer_append_str(buffer, state->array_nl);
718
901
  }
719
902
  if (RB_UNLIKELY(state->indent)) {
720
903
  for (j = 0; j < depth; j++) {
721
- fbuffer_append(buffer, state->indent, state->indent_len);
904
+ fbuffer_append_str(buffer, state->indent);
722
905
  }
723
906
  }
724
- generate_json(buffer, Vstate, state, RARRAY_AREF(obj, i));
907
+ generate_json(buffer, data, state, RARRAY_AREF(obj, i));
725
908
  }
726
909
  state->depth = --depth;
727
910
  if (RB_UNLIKELY(state->array_nl)) {
728
- fbuffer_append(buffer, state->array_nl, state->array_nl_len);
911
+ fbuffer_append_str(buffer, state->array_nl);
729
912
  if (RB_UNLIKELY(state->indent)) {
730
913
  for (j = 0; j < depth; j++) {
731
- fbuffer_append(buffer, state->indent, state->indent_len);
914
+ fbuffer_append_str(buffer, state->indent);
732
915
  }
733
916
  }
734
917
  }
735
918
  fbuffer_append_char(buffer, ']');
736
919
  }
737
920
 
738
- static int usascii_encindex, utf8_encindex, binary_encindex;
739
-
740
921
  static inline int enc_utf8_compatible_p(int enc_idx)
741
922
  {
742
923
  if (enc_idx == usascii_encindex) return 1;
@@ -744,117 +925,176 @@ static inline int enc_utf8_compatible_p(int enc_idx)
744
925
  return 0;
745
926
  }
746
927
 
928
+ static VALUE encode_json_string_try(VALUE str)
929
+ {
930
+ return rb_funcall(str, i_encode, 1, Encoding_UTF_8);
931
+ }
932
+
933
+ static VALUE encode_json_string_rescue(VALUE str, VALUE exception)
934
+ {
935
+ raise_generator_error_str(str, rb_funcall(exception, rb_intern("message"), 0));
936
+ return Qundef;
937
+ }
938
+
747
939
  static inline VALUE ensure_valid_encoding(VALUE str)
748
940
  {
749
941
  int encindex = RB_ENCODING_GET(str);
750
942
  VALUE utf8_string;
751
943
  if (RB_UNLIKELY(!enc_utf8_compatible_p(encindex))) {
752
944
  if (encindex == binary_encindex) {
753
- // For historical reason, we silently reinterpret binary strings as UTF-8 if it would work.
754
- // TODO: Deprecate in 2.8.0
755
- // TODO: Remove in 3.0.0
756
945
  utf8_string = rb_enc_associate_index(rb_str_dup(str), utf8_encindex);
757
946
  switch (rb_enc_str_coderange(utf8_string)) {
758
947
  case ENC_CODERANGE_7BIT:
948
+ return utf8_string;
759
949
  case ENC_CODERANGE_VALID:
950
+ // For historical reason, we silently reinterpret binary strings as UTF-8 if it would work.
951
+ // TODO: Raise in 3.0.0
952
+ rb_warn("JSON.generate: UTF-8 string passed as BINARY, this will raise an encoding error in json 3.0");
760
953
  return utf8_string;
761
954
  break;
762
955
  }
763
956
  }
764
957
 
765
- str = rb_funcall(str, i_encode, 1, Encoding_UTF_8);
958
+ str = rb_rescue(encode_json_string_try, str, encode_json_string_rescue, str);
766
959
  }
767
960
  return str;
768
961
  }
769
962
 
770
- static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
963
+ static void generate_json_string(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
771
964
  {
772
965
  obj = ensure_valid_encoding(obj);
773
966
 
774
967
  fbuffer_append_char(buffer, '"');
775
968
 
969
+ long len;
970
+ search_state search;
971
+ search.buffer = buffer;
972
+ RSTRING_GETMEM(obj, search.ptr, len);
973
+ search.cursor = search.ptr;
974
+ search.end = search.ptr + len;
975
+
776
976
  switch(rb_enc_str_coderange(obj)) {
777
977
  case ENC_CODERANGE_7BIT:
778
- convert_ASCII_to_JSON(buffer, obj, state->script_safe ? script_safe_escape_table : escape_table);
779
- break;
780
978
  case ENC_CODERANGE_VALID:
781
979
  if (RB_UNLIKELY(state->ascii_only)) {
782
- convert_UTF8_to_ASCII_only_JSON(buffer, obj, state->script_safe ? script_safe_escape_table : escape_table, state->script_safe);
980
+ convert_UTF8_to_ASCII_only_JSON(&search, state->script_safe ? script_safe_escape_table : ascii_only_escape_table);
981
+ } else if (RB_UNLIKELY(state->script_safe)) {
982
+ convert_UTF8_to_script_safe_JSON(&search);
783
983
  } else {
784
- convert_UTF8_to_JSON(buffer, obj, state->script_safe ? script_safe_escape_table : escape_table, state->script_safe);
984
+ convert_UTF8_to_JSON(&search);
785
985
  }
786
986
  break;
787
987
  default:
788
- rb_raise(rb_path2class("JSON::GeneratorError"), "source sequence is illegal/malformed utf-8");
988
+ raise_generator_error(obj, "source sequence is illegal/malformed utf-8");
789
989
  break;
790
990
  }
791
991
  fbuffer_append_char(buffer, '"');
792
992
  }
793
993
 
794
- static void generate_json_null(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
994
+ static void generate_json_fallback(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
995
+ {
996
+ VALUE tmp;
997
+ if (rb_respond_to(obj, i_to_json)) {
998
+ tmp = rb_funcall(obj, i_to_json, 1, vstate_get(data));
999
+ Check_Type(tmp, T_STRING);
1000
+ fbuffer_append_str(buffer, tmp);
1001
+ } else {
1002
+ tmp = rb_funcall(obj, i_to_s, 0);
1003
+ Check_Type(tmp, T_STRING);
1004
+ generate_json_string(buffer, data, state, tmp);
1005
+ }
1006
+ }
1007
+
1008
+ static inline void generate_json_symbol(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
1009
+ {
1010
+ if (state->strict) {
1011
+ generate_json_string(buffer, data, state, rb_sym2str(obj));
1012
+ } else {
1013
+ generate_json_fallback(buffer, data, state, obj);
1014
+ }
1015
+ }
1016
+
1017
+ static void generate_json_null(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
795
1018
  {
796
1019
  fbuffer_append(buffer, "null", 4);
797
1020
  }
798
1021
 
799
- static void generate_json_false(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
1022
+ static void generate_json_false(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
800
1023
  {
801
1024
  fbuffer_append(buffer, "false", 5);
802
1025
  }
803
1026
 
804
- static void generate_json_true(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
1027
+ static void generate_json_true(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
805
1028
  {
806
1029
  fbuffer_append(buffer, "true", 4);
807
1030
  }
808
1031
 
809
- static void generate_json_fixnum(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
1032
+ static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
810
1033
  {
811
1034
  fbuffer_append_long(buffer, FIX2LONG(obj));
812
1035
  }
813
1036
 
814
- static void generate_json_bignum(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
1037
+ static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
815
1038
  {
816
1039
  VALUE tmp = rb_funcall(obj, i_to_s, 0);
817
1040
  fbuffer_append_str(buffer, tmp);
818
1041
  }
819
1042
 
820
1043
  #ifdef RUBY_INTEGER_UNIFICATION
821
- static void generate_json_integer(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
1044
+ static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
822
1045
  {
823
1046
  if (FIXNUM_P(obj))
824
- generate_json_fixnum(buffer, Vstate, state, obj);
1047
+ generate_json_fixnum(buffer, data, state, obj);
825
1048
  else
826
- generate_json_bignum(buffer, Vstate, state, obj);
1049
+ generate_json_bignum(buffer, data, state, obj);
827
1050
  }
828
1051
  #endif
829
- static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
1052
+
1053
+ static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
830
1054
  {
831
1055
  double value = RFLOAT_VALUE(obj);
832
1056
  char allow_nan = state->allow_nan;
833
- VALUE tmp = rb_funcall(obj, i_to_s, 0);
834
1057
  if (!allow_nan) {
835
- if (isinf(value)) {
836
- rb_raise(eGeneratorError, "%"PRIsVALUE" not allowed in JSON", tmp);
837
- } else if (isnan(value)) {
838
- rb_raise(eGeneratorError, "%"PRIsVALUE" not allowed in JSON", tmp);
1058
+ if (isinf(value) || isnan(value)) {
1059
+ if (state->strict && state->as_json) {
1060
+ VALUE casted_obj = rb_proc_call_with_block(state->as_json, 1, &obj, Qnil);
1061
+ if (casted_obj != obj) {
1062
+ increase_depth(state);
1063
+ generate_json(buffer, data, state, casted_obj);
1064
+ state->depth--;
1065
+ return;
1066
+ }
1067
+ }
1068
+ raise_generator_error(obj, "%"PRIsVALUE" not allowed in JSON", rb_funcall(obj, i_to_s, 0));
839
1069
  }
840
1070
  }
841
- fbuffer_append_str(buffer, tmp);
1071
+ fbuffer_append_str(buffer, rb_funcall(obj, i_to_s, 0));
842
1072
  }
843
1073
 
844
- static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
1074
+ static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
845
1075
  {
846
- VALUE tmp;
1076
+ VALUE fragment = RSTRUCT_GET(obj, 0);
1077
+ Check_Type(fragment, T_STRING);
1078
+ fbuffer_append_str(buffer, fragment);
1079
+ }
1080
+
1081
+ static void generate_json(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
1082
+ {
1083
+ bool as_json_called = false;
1084
+ start:
847
1085
  if (obj == Qnil) {
848
- generate_json_null(buffer, Vstate, state, obj);
1086
+ generate_json_null(buffer, data, state, obj);
849
1087
  } else if (obj == Qfalse) {
850
- generate_json_false(buffer, Vstate, state, obj);
1088
+ generate_json_false(buffer, data, state, obj);
851
1089
  } else if (obj == Qtrue) {
852
- generate_json_true(buffer, Vstate, state, obj);
1090
+ generate_json_true(buffer, data, state, obj);
853
1091
  } else if (RB_SPECIAL_CONST_P(obj)) {
854
1092
  if (RB_FIXNUM_P(obj)) {
855
- generate_json_fixnum(buffer, Vstate, state, obj);
1093
+ generate_json_fixnum(buffer, data, state, obj);
856
1094
  } else if (RB_FLONUM_P(obj)) {
857
- generate_json_float(buffer, Vstate, state, obj);
1095
+ generate_json_float(buffer, data, state, obj);
1096
+ } else if (RB_STATIC_SYM_P(obj)) {
1097
+ generate_json_symbol(buffer, data, state, obj);
858
1098
  } else {
859
1099
  goto general;
860
1100
  }
@@ -862,62 +1102,53 @@ static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *s
862
1102
  VALUE klass = RBASIC_CLASS(obj);
863
1103
  switch (RB_BUILTIN_TYPE(obj)) {
864
1104
  case T_BIGNUM:
865
- generate_json_bignum(buffer, Vstate, state, obj);
1105
+ generate_json_bignum(buffer, data, state, obj);
866
1106
  break;
867
1107
  case T_HASH:
868
1108
  if (klass != rb_cHash) goto general;
869
- generate_json_object(buffer, Vstate, state, obj);
1109
+ generate_json_object(buffer, data, state, obj);
870
1110
  break;
871
1111
  case T_ARRAY:
872
1112
  if (klass != rb_cArray) goto general;
873
- generate_json_array(buffer, Vstate, state, obj);
1113
+ generate_json_array(buffer, data, state, obj);
874
1114
  break;
875
1115
  case T_STRING:
876
1116
  if (klass != rb_cString) goto general;
877
- generate_json_string(buffer, Vstate, state, obj);
1117
+ generate_json_string(buffer, data, state, obj);
1118
+ break;
1119
+ case T_SYMBOL:
1120
+ generate_json_symbol(buffer, data, state, obj);
878
1121
  break;
879
1122
  case T_FLOAT:
880
1123
  if (klass != rb_cFloat) goto general;
881
- generate_json_float(buffer, Vstate, state, obj);
1124
+ generate_json_float(buffer, data, state, obj);
1125
+ break;
1126
+ case T_STRUCT:
1127
+ if (klass != cFragment) goto general;
1128
+ generate_json_fragment(buffer, data, state, obj);
882
1129
  break;
883
1130
  default:
884
1131
  general:
885
1132
  if (state->strict) {
886
- rb_raise(eGeneratorError, "%"PRIsVALUE" not allowed in JSON", CLASS_OF(obj));
887
- } else if (rb_respond_to(obj, i_to_json)) {
888
- tmp = rb_funcall(obj, i_to_json, 1, Vstate);
889
- Check_Type(tmp, T_STRING);
890
- fbuffer_append_str(buffer, tmp);
1133
+ if (RTEST(state->as_json) && !as_json_called) {
1134
+ obj = rb_proc_call_with_block(state->as_json, 1, &obj, Qnil);
1135
+ as_json_called = true;
1136
+ goto start;
1137
+ } else {
1138
+ raise_generator_error(obj, "%"PRIsVALUE" not allowed in JSON", CLASS_OF(obj));
1139
+ }
891
1140
  } else {
892
- tmp = rb_funcall(obj, i_to_s, 0);
893
- Check_Type(tmp, T_STRING);
894
- generate_json_string(buffer, Vstate, state, tmp);
1141
+ generate_json_fallback(buffer, data, state, obj);
895
1142
  }
896
1143
  }
897
1144
  }
898
1145
  }
899
1146
 
900
- static FBuffer *cState_prepare_buffer(VALUE self)
901
- {
902
- FBuffer *buffer;
903
- GET_STATE(self);
904
- buffer = fbuffer_alloc(state->buffer_initial_length);
905
-
906
- return buffer;
907
- }
908
-
909
- struct generate_json_data {
910
- FBuffer *buffer;
911
- VALUE vstate;
912
- JSON_Generator_State *state;
913
- VALUE obj;
914
- };
915
-
916
1147
  static VALUE generate_json_try(VALUE d)
917
1148
  {
918
1149
  struct generate_json_data *data = (struct generate_json_data *)d;
919
1150
 
920
- generate_json(data->buffer, data->vstate, data->state, data->obj);
1151
+ data->func(data->buffer, data, data->state, data->obj);
921
1152
 
922
1153
  return Qnil;
923
1154
  }
@@ -932,32 +1163,42 @@ static VALUE generate_json_rescue(VALUE d, VALUE exc)
932
1163
  return Qundef;
933
1164
  }
934
1165
 
935
- static VALUE cState_partial_generate(VALUE self, VALUE obj)
1166
+ static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func, VALUE io)
936
1167
  {
937
- FBuffer *buffer = cState_prepare_buffer(self);
938
1168
  GET_STATE(self);
939
1169
 
1170
+ char stack_buffer[FBUFFER_STACK_SIZE];
1171
+ FBuffer buffer = {
1172
+ .io = RTEST(io) ? io : Qfalse,
1173
+ };
1174
+ fbuffer_stack_init(&buffer, state->buffer_initial_length, stack_buffer, FBUFFER_STACK_SIZE);
1175
+
940
1176
  struct generate_json_data data = {
941
- .buffer = buffer,
1177
+ .buffer = &buffer,
942
1178
  .vstate = self,
943
1179
  .state = state,
944
- .obj = obj
1180
+ .obj = obj,
1181
+ .func = func
945
1182
  };
946
1183
  rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data);
947
1184
 
948
- return fbuffer_to_s(buffer);
1185
+ return fbuffer_finalize(&buffer);
949
1186
  }
950
1187
 
951
- /*
952
- * call-seq: generate(obj)
1188
+ /* call-seq:
1189
+ * generate(obj) -> String
1190
+ * generate(obj, anIO) -> anIO
953
1191
  *
954
1192
  * Generates a valid JSON document from object +obj+ and returns the
955
1193
  * result. If no valid JSON document can be created this method raises a
956
1194
  * GeneratorError exception.
957
1195
  */
958
- static VALUE cState_generate(VALUE self, VALUE obj)
1196
+ static VALUE cState_generate(int argc, VALUE *argv, VALUE self)
959
1197
  {
960
- VALUE result = cState_partial_generate(self, obj);
1198
+ rb_check_arity(argc, 1, 2);
1199
+ VALUE obj = argv[0];
1200
+ VALUE io = argc > 1 ? argv[1] : Qnil;
1201
+ VALUE result = cState_partial_generate(self, obj, generate_json, io);
961
1202
  GET_STATE(self);
962
1203
  (void)state;
963
1204
  return result;
@@ -985,11 +1226,12 @@ static VALUE cState_init_copy(VALUE obj, VALUE orig)
985
1226
  if (!objState) rb_raise(rb_eArgError, "unallocated JSON::State");
986
1227
 
987
1228
  MEMCPY(objState, origState, JSON_Generator_State, 1);
988
- objState->indent = fstrndup(origState->indent, origState->indent_len);
989
- objState->space = fstrndup(origState->space, origState->space_len);
990
- objState->space_before = fstrndup(origState->space_before, origState->space_before_len);
991
- objState->object_nl = fstrndup(origState->object_nl, origState->object_nl_len);
992
- objState->array_nl = fstrndup(origState->array_nl, origState->array_nl_len);
1229
+ objState->indent = origState->indent;
1230
+ objState->space = origState->space;
1231
+ objState->space_before = origState->space_before;
1232
+ objState->object_nl = origState->object_nl;
1233
+ objState->array_nl = origState->array_nl;
1234
+ objState->as_json = origState->as_json;
993
1235
  return obj;
994
1236
  }
995
1237
 
@@ -1019,7 +1261,18 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
1019
1261
  static VALUE cState_indent(VALUE self)
1020
1262
  {
1021
1263
  GET_STATE(self);
1022
- return state->indent ? rb_str_new(state->indent, state->indent_len) : rb_str_new2("");
1264
+ return state->indent ? state->indent : rb_str_freeze(rb_utf8_str_new("", 0));
1265
+ }
1266
+
1267
+ static VALUE string_config(VALUE config)
1268
+ {
1269
+ if (RTEST(config)) {
1270
+ Check_Type(config, T_STRING);
1271
+ if (RSTRING_LEN(config)) {
1272
+ return rb_str_new_frozen(config);
1273
+ }
1274
+ }
1275
+ return Qfalse;
1023
1276
  }
1024
1277
 
1025
1278
  /*
@@ -1029,21 +1282,8 @@ static VALUE cState_indent(VALUE self)
1029
1282
  */
1030
1283
  static VALUE cState_indent_set(VALUE self, VALUE indent)
1031
1284
  {
1032
- unsigned long len;
1033
1285
  GET_STATE(self);
1034
- Check_Type(indent, T_STRING);
1035
- len = RSTRING_LEN(indent);
1036
- if (len == 0) {
1037
- if (state->indent) {
1038
- ruby_xfree(state->indent);
1039
- state->indent = NULL;
1040
- state->indent_len = 0;
1041
- }
1042
- } else {
1043
- if (state->indent) ruby_xfree(state->indent);
1044
- state->indent = fstrndup(RSTRING_PTR(indent), len);
1045
- state->indent_len = len;
1046
- }
1286
+ RB_OBJ_WRITE(self, &state->indent, string_config(indent));
1047
1287
  return Qnil;
1048
1288
  }
1049
1289
 
@@ -1056,7 +1296,7 @@ static VALUE cState_indent_set(VALUE self, VALUE indent)
1056
1296
  static VALUE cState_space(VALUE self)
1057
1297
  {
1058
1298
  GET_STATE(self);
1059
- return state->space ? rb_str_new(state->space, state->space_len) : rb_str_new2("");
1299
+ return state->space ? state->space : rb_str_freeze(rb_utf8_str_new("", 0));
1060
1300
  }
1061
1301
 
1062
1302
  /*
@@ -1067,21 +1307,8 @@ static VALUE cState_space(VALUE self)
1067
1307
  */
1068
1308
  static VALUE cState_space_set(VALUE self, VALUE space)
1069
1309
  {
1070
- unsigned long len;
1071
1310
  GET_STATE(self);
1072
- Check_Type(space, T_STRING);
1073
- len = RSTRING_LEN(space);
1074
- if (len == 0) {
1075
- if (state->space) {
1076
- ruby_xfree(state->space);
1077
- state->space = NULL;
1078
- state->space_len = 0;
1079
- }
1080
- } else {
1081
- if (state->space) ruby_xfree(state->space);
1082
- state->space = fstrndup(RSTRING_PTR(space), len);
1083
- state->space_len = len;
1084
- }
1311
+ RB_OBJ_WRITE(self, &state->space, string_config(space));
1085
1312
  return Qnil;
1086
1313
  }
1087
1314
 
@@ -1093,7 +1320,7 @@ static VALUE cState_space_set(VALUE self, VALUE space)
1093
1320
  static VALUE cState_space_before(VALUE self)
1094
1321
  {
1095
1322
  GET_STATE(self);
1096
- return state->space_before ? rb_str_new(state->space_before, state->space_before_len) : rb_str_new2("");
1323
+ return state->space_before ? state->space_before : rb_str_freeze(rb_utf8_str_new("", 0));
1097
1324
  }
1098
1325
 
1099
1326
  /*
@@ -1103,21 +1330,8 @@ static VALUE cState_space_before(VALUE self)
1103
1330
  */
1104
1331
  static VALUE cState_space_before_set(VALUE self, VALUE space_before)
1105
1332
  {
1106
- unsigned long len;
1107
1333
  GET_STATE(self);
1108
- Check_Type(space_before, T_STRING);
1109
- len = RSTRING_LEN(space_before);
1110
- if (len == 0) {
1111
- if (state->space_before) {
1112
- ruby_xfree(state->space_before);
1113
- state->space_before = NULL;
1114
- state->space_before_len = 0;
1115
- }
1116
- } else {
1117
- if (state->space_before) ruby_xfree(state->space_before);
1118
- state->space_before = fstrndup(RSTRING_PTR(space_before), len);
1119
- state->space_before_len = len;
1120
- }
1334
+ RB_OBJ_WRITE(self, &state->space_before, string_config(space_before));
1121
1335
  return Qnil;
1122
1336
  }
1123
1337
 
@@ -1130,7 +1344,7 @@ static VALUE cState_space_before_set(VALUE self, VALUE space_before)
1130
1344
  static VALUE cState_object_nl(VALUE self)
1131
1345
  {
1132
1346
  GET_STATE(self);
1133
- return state->object_nl ? rb_str_new(state->object_nl, state->object_nl_len) : rb_str_new2("");
1347
+ return state->object_nl ? state->object_nl : rb_str_freeze(rb_utf8_str_new("", 0));
1134
1348
  }
1135
1349
 
1136
1350
  /*
@@ -1141,20 +1355,8 @@ static VALUE cState_object_nl(VALUE self)
1141
1355
  */
1142
1356
  static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
1143
1357
  {
1144
- unsigned long len;
1145
1358
  GET_STATE(self);
1146
- Check_Type(object_nl, T_STRING);
1147
- len = RSTRING_LEN(object_nl);
1148
- if (len == 0) {
1149
- if (state->object_nl) {
1150
- ruby_xfree(state->object_nl);
1151
- state->object_nl = NULL;
1152
- }
1153
- } else {
1154
- if (state->object_nl) ruby_xfree(state->object_nl);
1155
- state->object_nl = fstrndup(RSTRING_PTR(object_nl), len);
1156
- state->object_nl_len = len;
1157
- }
1359
+ RB_OBJ_WRITE(self, &state->object_nl, string_config(object_nl));
1158
1360
  return Qnil;
1159
1361
  }
1160
1362
 
@@ -1166,7 +1368,7 @@ static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
1166
1368
  static VALUE cState_array_nl(VALUE self)
1167
1369
  {
1168
1370
  GET_STATE(self);
1169
- return state->array_nl ? rb_str_new(state->array_nl, state->array_nl_len) : rb_str_new2("");
1371
+ return state->array_nl ? state->array_nl : rb_str_freeze(rb_utf8_str_new("", 0));
1170
1372
  }
1171
1373
 
1172
1374
  /*
@@ -1176,23 +1378,33 @@ static VALUE cState_array_nl(VALUE self)
1176
1378
  */
1177
1379
  static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
1178
1380
  {
1179
- unsigned long len;
1180
1381
  GET_STATE(self);
1181
- Check_Type(array_nl, T_STRING);
1182
- len = RSTRING_LEN(array_nl);
1183
- if (len == 0) {
1184
- if (state->array_nl) {
1185
- ruby_xfree(state->array_nl);
1186
- state->array_nl = NULL;
1187
- }
1188
- } else {
1189
- if (state->array_nl) ruby_xfree(state->array_nl);
1190
- state->array_nl = fstrndup(RSTRING_PTR(array_nl), len);
1191
- state->array_nl_len = len;
1192
- }
1382
+ RB_OBJ_WRITE(self, &state->array_nl, string_config(array_nl));
1193
1383
  return Qnil;
1194
1384
  }
1195
1385
 
1386
+ /*
1387
+ * call-seq: as_json()
1388
+ *
1389
+ * This string is put at the end of a line that holds a JSON array.
1390
+ */
1391
+ static VALUE cState_as_json(VALUE self)
1392
+ {
1393
+ GET_STATE(self);
1394
+ return state->as_json;
1395
+ }
1396
+
1397
+ /*
1398
+ * call-seq: as_json=(as_json)
1399
+ *
1400
+ * This string is put at the end of a line that holds a JSON array.
1401
+ */
1402
+ static VALUE cState_as_json_set(VALUE self, VALUE as_json)
1403
+ {
1404
+ GET_STATE(self);
1405
+ RB_OBJ_WRITE(self, &state->as_json, rb_convert_type(as_json, T_DATA, "Proc", "to_proc"));
1406
+ return Qnil;
1407
+ }
1196
1408
 
1197
1409
  /*
1198
1410
  * call-seq: check_circular?
@@ -1218,6 +1430,11 @@ static VALUE cState_max_nesting(VALUE self)
1218
1430
  return LONG2FIX(state->max_nesting);
1219
1431
  }
1220
1432
 
1433
+ static long long_config(VALUE num)
1434
+ {
1435
+ return RTEST(num) ? FIX2LONG(num) : 0;
1436
+ }
1437
+
1221
1438
  /*
1222
1439
  * call-seq: max_nesting=(depth)
1223
1440
  *
@@ -1227,8 +1444,7 @@ static VALUE cState_max_nesting(VALUE self)
1227
1444
  static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
1228
1445
  {
1229
1446
  GET_STATE(self);
1230
- Check_Type(depth, T_FIXNUM);
1231
- state->max_nesting = FIX2LONG(depth);
1447
+ state->max_nesting = long_config(depth);
1232
1448
  return Qnil;
1233
1449
  }
1234
1450
 
@@ -1356,8 +1572,7 @@ static VALUE cState_depth(VALUE self)
1356
1572
  static VALUE cState_depth_set(VALUE self, VALUE depth)
1357
1573
  {
1358
1574
  GET_STATE(self);
1359
- Check_Type(depth, T_FIXNUM);
1360
- state->depth = FIX2LONG(depth);
1575
+ state->depth = long_config(depth);
1361
1576
  return Qnil;
1362
1577
  }
1363
1578
 
@@ -1372,6 +1587,15 @@ static VALUE cState_buffer_initial_length(VALUE self)
1372
1587
  return LONG2FIX(state->buffer_initial_length);
1373
1588
  }
1374
1589
 
1590
+ static void buffer_initial_length_set(JSON_Generator_State *state, VALUE buffer_initial_length)
1591
+ {
1592
+ Check_Type(buffer_initial_length, T_FIXNUM);
1593
+ long initial_length = FIX2LONG(buffer_initial_length);
1594
+ if (initial_length > 0) {
1595
+ state->buffer_initial_length = initial_length;
1596
+ }
1597
+ }
1598
+
1375
1599
  /*
1376
1600
  * call-seq: buffer_initial_length=(length)
1377
1601
  *
@@ -1380,16 +1604,76 @@ static VALUE cState_buffer_initial_length(VALUE self)
1380
1604
  */
1381
1605
  static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_length)
1382
1606
  {
1383
- long initial_length;
1384
1607
  GET_STATE(self);
1385
- Check_Type(buffer_initial_length, T_FIXNUM);
1386
- initial_length = FIX2LONG(buffer_initial_length);
1387
- if (initial_length > 0) {
1388
- state->buffer_initial_length = initial_length;
1389
- }
1608
+ buffer_initial_length_set(state, buffer_initial_length);
1390
1609
  return Qnil;
1391
1610
  }
1392
1611
 
1612
+ static int configure_state_i(VALUE key, VALUE val, VALUE _arg)
1613
+ {
1614
+ JSON_Generator_State *state = (JSON_Generator_State *)_arg;
1615
+
1616
+ if (key == sym_indent) { state->indent = string_config(val); }
1617
+ else if (key == sym_space) { state->space = string_config(val); }
1618
+ else if (key == sym_space_before) { state->space_before = string_config(val); }
1619
+ else if (key == sym_object_nl) { state->object_nl = string_config(val); }
1620
+ else if (key == sym_array_nl) { state->array_nl = string_config(val); }
1621
+ else if (key == sym_max_nesting) { state->max_nesting = long_config(val); }
1622
+ else if (key == sym_allow_nan) { state->allow_nan = RTEST(val); }
1623
+ else if (key == sym_ascii_only) { state->ascii_only = RTEST(val); }
1624
+ else if (key == sym_depth) { state->depth = long_config(val); }
1625
+ else if (key == sym_buffer_initial_length) { buffer_initial_length_set(state, val); }
1626
+ else if (key == sym_script_safe) { state->script_safe = RTEST(val); }
1627
+ else if (key == sym_escape_slash) { state->script_safe = RTEST(val); }
1628
+ else if (key == sym_strict) { state->strict = RTEST(val); }
1629
+ else if (key == sym_as_json) { state->as_json = RTEST(val) ? rb_convert_type(val, T_DATA, "Proc", "to_proc") : Qfalse; }
1630
+ return ST_CONTINUE;
1631
+ }
1632
+
1633
+ static void configure_state(JSON_Generator_State *state, VALUE config)
1634
+ {
1635
+ if (!RTEST(config)) return;
1636
+
1637
+ Check_Type(config, T_HASH);
1638
+
1639
+ if (!RHASH_SIZE(config)) return;
1640
+
1641
+ // We assume in most cases few keys are set so it's faster to go over
1642
+ // the provided keys than to check all possible keys.
1643
+ rb_hash_foreach(config, configure_state_i, (VALUE)state);
1644
+ }
1645
+
1646
+ static VALUE cState_configure(VALUE self, VALUE opts)
1647
+ {
1648
+ GET_STATE(self);
1649
+ configure_state(state, opts);
1650
+ return self;
1651
+ }
1652
+
1653
+ static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io)
1654
+ {
1655
+ JSON_Generator_State state = {0};
1656
+ state_init(&state);
1657
+ configure_state(&state, opts);
1658
+
1659
+ char stack_buffer[FBUFFER_STACK_SIZE];
1660
+ FBuffer buffer = {
1661
+ .io = RTEST(io) ? io : Qfalse,
1662
+ };
1663
+ fbuffer_stack_init(&buffer, state.buffer_initial_length, stack_buffer, FBUFFER_STACK_SIZE);
1664
+
1665
+ struct generate_json_data data = {
1666
+ .buffer = &buffer,
1667
+ .vstate = Qfalse,
1668
+ .state = &state,
1669
+ .obj = obj,
1670
+ .func = generate_json,
1671
+ };
1672
+ rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data);
1673
+
1674
+ return fbuffer_finalize(&buffer);
1675
+ }
1676
+
1393
1677
  /*
1394
1678
  *
1395
1679
  */
@@ -1403,19 +1687,25 @@ void Init_generator(void)
1403
1687
  rb_require("json/common");
1404
1688
 
1405
1689
  mJSON = rb_define_module("JSON");
1690
+
1691
+ rb_global_variable(&cFragment);
1692
+ cFragment = rb_const_get(mJSON, rb_intern("Fragment"));
1693
+
1406
1694
  VALUE mExt = rb_define_module_under(mJSON, "Ext");
1407
1695
  VALUE mGenerator = rb_define_module_under(mExt, "Generator");
1408
1696
 
1697
+ rb_global_variable(&eGeneratorError);
1409
1698
  eGeneratorError = rb_path2class("JSON::GeneratorError");
1699
+
1700
+ rb_global_variable(&eNestingError);
1410
1701
  eNestingError = rb_path2class("JSON::NestingError");
1411
- rb_gc_register_mark_object(eGeneratorError);
1412
- rb_gc_register_mark_object(eNestingError);
1413
1702
 
1414
1703
  cState = rb_define_class_under(mGenerator, "State", rb_cObject);
1415
1704
  rb_define_alloc_func(cState, cState_s_allocate);
1416
1705
  rb_define_singleton_method(cState, "from_state", cState_from_state_s, 1);
1417
1706
  rb_define_method(cState, "initialize", cState_initialize, -1);
1418
1707
  rb_define_alias(cState, "initialize", "initialize"); // avoid method redefinition warnings
1708
+ rb_define_private_method(cState, "_configure", cState_configure, 1);
1419
1709
 
1420
1710
  rb_define_method(cState, "initialize_copy", cState_init_copy, 1);
1421
1711
  rb_define_method(cState, "indent", cState_indent, 0);
@@ -1428,6 +1718,8 @@ void Init_generator(void)
1428
1718
  rb_define_method(cState, "object_nl=", cState_object_nl_set, 1);
1429
1719
  rb_define_method(cState, "array_nl", cState_array_nl, 0);
1430
1720
  rb_define_method(cState, "array_nl=", cState_array_nl_set, 1);
1721
+ rb_define_method(cState, "as_json", cState_as_json, 0);
1722
+ rb_define_method(cState, "as_json=", cState_as_json_set, 1);
1431
1723
  rb_define_method(cState, "max_nesting", cState_max_nesting, 0);
1432
1724
  rb_define_method(cState, "max_nesting=", cState_max_nesting_set, 1);
1433
1725
  rb_define_method(cState, "script_safe", cState_script_safe, 0);
@@ -1448,7 +1740,10 @@ void Init_generator(void)
1448
1740
  rb_define_method(cState, "depth=", cState_depth_set, 1);
1449
1741
  rb_define_method(cState, "buffer_initial_length", cState_buffer_initial_length, 0);
1450
1742
  rb_define_method(cState, "buffer_initial_length=", cState_buffer_initial_length_set, 1);
1451
- rb_define_method(cState, "generate", cState_generate, 1);
1743
+ rb_define_method(cState, "generate", cState_generate, -1);
1744
+ rb_define_alias(cState, "generate_new", "generate"); // :nodoc:
1745
+
1746
+ rb_define_singleton_method(cState, "generate", cState_m_generate, 3);
1452
1747
 
1453
1748
  VALUE mGeneratorMethods = rb_define_module_under(mGenerator, "GeneratorMethods");
1454
1749
 
@@ -1504,6 +1799,21 @@ void Init_generator(void)
1504
1799
  i_extend = rb_intern("extend");
1505
1800
  i_encode = rb_intern("encode");
1506
1801
 
1802
+ sym_indent = ID2SYM(rb_intern("indent"));
1803
+ sym_space = ID2SYM(rb_intern("space"));
1804
+ sym_space_before = ID2SYM(rb_intern("space_before"));
1805
+ sym_object_nl = ID2SYM(rb_intern("object_nl"));
1806
+ sym_array_nl = ID2SYM(rb_intern("array_nl"));
1807
+ sym_max_nesting = ID2SYM(rb_intern("max_nesting"));
1808
+ sym_allow_nan = ID2SYM(rb_intern("allow_nan"));
1809
+ sym_ascii_only = ID2SYM(rb_intern("ascii_only"));
1810
+ sym_depth = ID2SYM(rb_intern("depth"));
1811
+ sym_buffer_initial_length = ID2SYM(rb_intern("buffer_initial_length"));
1812
+ sym_script_safe = ID2SYM(rb_intern("script_safe"));
1813
+ sym_escape_slash = ID2SYM(rb_intern("escape_slash"));
1814
+ sym_strict = ID2SYM(rb_intern("strict"));
1815
+ sym_as_json = ID2SYM(rb_intern("as_json"));
1816
+
1507
1817
  usascii_encindex = rb_usascii_encindex();
1508
1818
  utf8_encindex = rb_utf8_encindex();
1509
1819
  binary_encindex = rb_ascii8bit_encindex();