json 2.7.4 → 2.8.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.
- checksums.yaml +4 -4
- data/CHANGES.md +25 -0
- data/README.md +8 -77
- data/ext/json/ext/fbuffer/fbuffer.h +85 -47
- data/ext/json/ext/generator/generator.c +367 -216
- data/ext/json/ext/parser/extconf.rb +5 -27
- data/ext/json/ext/parser/parser.c +1536 -474
- data/ext/json/ext/parser/parser.rl +717 -243
- data/json.gemspec +4 -1
- data/lib/json/add/bigdecimal.rb +1 -1
- data/lib/json/common.rb +200 -54
- data/lib/json/ext/generator/state.rb +1 -31
- data/lib/json/ext.rb +2 -4
- data/lib/json/{pure → truffle_ruby}/generator.rb +165 -124
- data/lib/json/version.rb +1 -1
- data/lib/json.rb +15 -20
- metadata +4 -8
- data/ext/json/ext/generator/generator.h +0 -129
- data/ext/json/ext/parser/parser.h +0 -60
- data/lib/json/pure/parser.rb +0 -331
- data/lib/json/pure.rb +0 -16
@@ -1,5 +1,27 @@
|
|
1
|
+
#include "ruby.h"
|
1
2
|
#include "../fbuffer/fbuffer.h"
|
2
|
-
|
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
|
+
|
16
|
+
long max_nesting;
|
17
|
+
long depth;
|
18
|
+
long buffer_initial_length;
|
19
|
+
|
20
|
+
bool allow_nan;
|
21
|
+
bool ascii_only;
|
22
|
+
bool script_safe;
|
23
|
+
bool strict;
|
24
|
+
} JSON_Generator_State;
|
3
25
|
|
4
26
|
#ifndef RB_UNLIKELY
|
5
27
|
#define RB_UNLIKELY(cond) (cond)
|
@@ -8,6 +30,46 @@
|
|
8
30
|
static VALUE mJSON, cState, mString_Extend, eGeneratorError, eNestingError, Encoding_UTF_8;
|
9
31
|
|
10
32
|
static ID i_to_s, i_to_json, i_new, i_pack, i_unpack, i_create_id, i_extend, i_encode;
|
33
|
+
static ID sym_indent, sym_space, sym_space_before, sym_object_nl, sym_array_nl, sym_max_nesting, sym_allow_nan,
|
34
|
+
sym_ascii_only, sym_depth, sym_buffer_initial_length, sym_script_safe, sym_escape_slash, sym_strict;
|
35
|
+
|
36
|
+
|
37
|
+
#define GET_STATE_TO(self, state) \
|
38
|
+
TypedData_Get_Struct(self, JSON_Generator_State, &JSON_Generator_State_type, state)
|
39
|
+
|
40
|
+
#define GET_STATE(self) \
|
41
|
+
JSON_Generator_State *state; \
|
42
|
+
GET_STATE_TO(self, state)
|
43
|
+
|
44
|
+
struct generate_json_data;
|
45
|
+
|
46
|
+
typedef void (*generator_func)(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
47
|
+
|
48
|
+
struct generate_json_data {
|
49
|
+
FBuffer *buffer;
|
50
|
+
VALUE vstate;
|
51
|
+
JSON_Generator_State *state;
|
52
|
+
VALUE obj;
|
53
|
+
generator_func func;
|
54
|
+
};
|
55
|
+
|
56
|
+
static VALUE cState_from_state_s(VALUE self, VALUE opts);
|
57
|
+
static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func);
|
58
|
+
static void generate_json(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
59
|
+
static void generate_json_object(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
60
|
+
static void generate_json_array(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
61
|
+
static void generate_json_string(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
62
|
+
static void generate_json_null(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
63
|
+
static void generate_json_false(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
64
|
+
static void generate_json_true(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
65
|
+
#ifdef RUBY_INTEGER_UNIFICATION
|
66
|
+
static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
67
|
+
#endif
|
68
|
+
static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
69
|
+
static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
70
|
+
static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
71
|
+
|
72
|
+
static int usascii_encindex, utf8_encindex, binary_encindex;
|
11
73
|
|
12
74
|
/* Converts in_string to a JSON string (without the wrapping '"'
|
13
75
|
* characters) in FBuffer out_buffer.
|
@@ -44,9 +106,6 @@ static void convert_UTF8_to_JSON(FBuffer *out_buffer, VALUE str, const char esca
|
|
44
106
|
|
45
107
|
if (RB_UNLIKELY(ch_len)) {
|
46
108
|
switch (ch_len) {
|
47
|
-
case 0:
|
48
|
-
pos++;
|
49
|
-
break;
|
50
109
|
case 1: {
|
51
110
|
FLUSH_POS(1);
|
52
111
|
switch (ch) {
|
@@ -59,8 +118,8 @@ static void convert_UTF8_to_JSON(FBuffer *out_buffer, VALUE str, const char esca
|
|
59
118
|
case '\r': fbuffer_append(out_buffer, "\\r", 2); break;
|
60
119
|
case '\t': fbuffer_append(out_buffer, "\\t", 2); break;
|
61
120
|
default: {
|
62
|
-
scratch[2] =
|
63
|
-
scratch[3] =
|
121
|
+
scratch[2] = '0';
|
122
|
+
scratch[3] = '0';
|
64
123
|
scratch[4] = hexdig[(ch >> 4) & 0xf];
|
65
124
|
scratch[5] = hexdig[ch & 0xf];
|
66
125
|
fbuffer_append(out_buffer, scratch, 6);
|
@@ -181,8 +240,8 @@ static void convert_ASCII_to_JSON(FBuffer *out_buffer, VALUE str, const char esc
|
|
181
240
|
case '\r': fbuffer_append(out_buffer, "\\r", 2); break;
|
182
241
|
case '\t': fbuffer_append(out_buffer, "\\t", 2); break;
|
183
242
|
default:
|
184
|
-
scratch[2] =
|
185
|
-
scratch[3] =
|
243
|
+
scratch[2] = '0';
|
244
|
+
scratch[3] = '0';
|
186
245
|
scratch[4] = hexdig[(ch >> 4) & 0xf];
|
187
246
|
scratch[5] = hexdig[ch & 0xf];
|
188
247
|
fbuffer_append(out_buffer, scratch, 6);
|
@@ -217,9 +276,6 @@ static void convert_UTF8_to_ASCII_only_JSON(FBuffer *out_buffer, VALUE str, cons
|
|
217
276
|
|
218
277
|
if (RB_UNLIKELY(ch_len)) {
|
219
278
|
switch (ch_len) {
|
220
|
-
case 0:
|
221
|
-
pos++;
|
222
|
-
break;
|
223
279
|
case 1: {
|
224
280
|
FLUSH_POS(1);
|
225
281
|
switch (ch) {
|
@@ -232,8 +288,8 @@ static void convert_UTF8_to_ASCII_only_JSON(FBuffer *out_buffer, VALUE str, cons
|
|
232
288
|
case '\r': fbuffer_append(out_buffer, "\\r", 2); break;
|
233
289
|
case '\t': fbuffer_append(out_buffer, "\\t", 2); break;
|
234
290
|
default: {
|
235
|
-
scratch[2] =
|
236
|
-
scratch[3] =
|
291
|
+
scratch[2] = '0';
|
292
|
+
scratch[3] = '0';
|
237
293
|
scratch[4] = hexdig[(ch >> 4) & 0xf];
|
238
294
|
scratch[5] = hexdig[ch & 0xf];
|
239
295
|
fbuffer_append(out_buffer, scratch, 6);
|
@@ -303,14 +359,6 @@ static void convert_UTF8_to_ASCII_only_JSON(FBuffer *out_buffer, VALUE str, cons
|
|
303
359
|
RB_GC_GUARD(str);
|
304
360
|
}
|
305
361
|
|
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;
|
312
|
-
}
|
313
|
-
|
314
362
|
/*
|
315
363
|
* Document-module: JSON::Ext::Generator
|
316
364
|
*
|
@@ -403,7 +451,9 @@ static char *fstrndup(const char *ptr, unsigned long len) {
|
|
403
451
|
*/
|
404
452
|
static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self)
|
405
453
|
{
|
406
|
-
|
454
|
+
rb_check_arity(argc, 0, 1);
|
455
|
+
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
456
|
+
return cState_partial_generate(Vstate, self, generate_json_object);
|
407
457
|
}
|
408
458
|
|
409
459
|
/*
|
@@ -415,7 +465,9 @@ static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self)
|
|
415
465
|
* produced JSON string output further.
|
416
466
|
*/
|
417
467
|
static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) {
|
418
|
-
|
468
|
+
rb_check_arity(argc, 0, 1);
|
469
|
+
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
470
|
+
return cState_partial_generate(Vstate, self, generate_json_array);
|
419
471
|
}
|
420
472
|
|
421
473
|
#ifdef RUBY_INTEGER_UNIFICATION
|
@@ -426,7 +478,9 @@ static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) {
|
|
426
478
|
*/
|
427
479
|
static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self)
|
428
480
|
{
|
429
|
-
|
481
|
+
rb_check_arity(argc, 0, 1);
|
482
|
+
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
483
|
+
return cState_partial_generate(Vstate, self, generate_json_integer);
|
430
484
|
}
|
431
485
|
|
432
486
|
#else
|
@@ -437,7 +491,9 @@ static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self)
|
|
437
491
|
*/
|
438
492
|
static VALUE mFixnum_to_json(int argc, VALUE *argv, VALUE self)
|
439
493
|
{
|
440
|
-
|
494
|
+
rb_check_arity(argc, 0, 1);
|
495
|
+
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
496
|
+
return cState_partial_generate(Vstate, self, generate_json_fixnum);
|
441
497
|
}
|
442
498
|
|
443
499
|
/*
|
@@ -447,7 +503,9 @@ static VALUE mFixnum_to_json(int argc, VALUE *argv, VALUE self)
|
|
447
503
|
*/
|
448
504
|
static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)
|
449
505
|
{
|
450
|
-
|
506
|
+
rb_check_arity(argc, 0, 1);
|
507
|
+
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
508
|
+
return cState_partial_generate(Vstate, self, generate_json_bignum);
|
451
509
|
}
|
452
510
|
#endif
|
453
511
|
|
@@ -458,7 +516,9 @@ static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)
|
|
458
516
|
*/
|
459
517
|
static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self)
|
460
518
|
{
|
461
|
-
|
519
|
+
rb_check_arity(argc, 0, 1);
|
520
|
+
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
521
|
+
return cState_partial_generate(Vstate, self, generate_json_float);
|
462
522
|
}
|
463
523
|
|
464
524
|
/*
|
@@ -481,7 +541,9 @@ static VALUE mString_included_s(VALUE self, VALUE modul) {
|
|
481
541
|
*/
|
482
542
|
static VALUE mString_to_json(int argc, VALUE *argv, VALUE self)
|
483
543
|
{
|
484
|
-
|
544
|
+
rb_check_arity(argc, 0, 1);
|
545
|
+
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
546
|
+
return cState_partial_generate(Vstate, self, generate_json_string);
|
485
547
|
}
|
486
548
|
|
487
549
|
/*
|
@@ -498,7 +560,7 @@ static VALUE mString_to_json_raw_object(VALUE self)
|
|
498
560
|
VALUE result = rb_hash_new();
|
499
561
|
rb_hash_aset(result, rb_funcall(mJSON, i_create_id, 0), rb_class_name(rb_obj_class(self)));
|
500
562
|
ary = rb_funcall(self, i_unpack, 1, rb_str_new2("C*"));
|
501
|
-
rb_hash_aset(result,
|
563
|
+
rb_hash_aset(result, rb_utf8_str_new_lit("raw"), ary);
|
502
564
|
return result;
|
503
565
|
}
|
504
566
|
|
@@ -536,7 +598,8 @@ static VALUE mString_Extend_json_create(VALUE self, VALUE o)
|
|
536
598
|
*/
|
537
599
|
static VALUE mTrueClass_to_json(int argc, VALUE *argv, VALUE self)
|
538
600
|
{
|
539
|
-
|
601
|
+
rb_check_arity(argc, 0, 1);
|
602
|
+
return rb_utf8_str_new("true", 4);
|
540
603
|
}
|
541
604
|
|
542
605
|
/*
|
@@ -546,7 +609,8 @@ static VALUE mTrueClass_to_json(int argc, VALUE *argv, VALUE self)
|
|
546
609
|
*/
|
547
610
|
static VALUE mFalseClass_to_json(int argc, VALUE *argv, VALUE self)
|
548
611
|
{
|
549
|
-
|
612
|
+
rb_check_arity(argc, 0, 1);
|
613
|
+
return rb_utf8_str_new("false", 5);
|
550
614
|
}
|
551
615
|
|
552
616
|
/*
|
@@ -556,7 +620,8 @@ static VALUE mFalseClass_to_json(int argc, VALUE *argv, VALUE self)
|
|
556
620
|
*/
|
557
621
|
static VALUE mNilClass_to_json(int argc, VALUE *argv, VALUE self)
|
558
622
|
{
|
559
|
-
|
623
|
+
rb_check_arity(argc, 0, 1);
|
624
|
+
return rb_utf8_str_new("null", 4);
|
560
625
|
}
|
561
626
|
|
562
627
|
/*
|
@@ -573,30 +638,38 @@ static VALUE mObject_to_json(int argc, VALUE *argv, VALUE self)
|
|
573
638
|
rb_scan_args(argc, argv, "01", &state);
|
574
639
|
Check_Type(string, T_STRING);
|
575
640
|
state = cState_from_state_s(cState, state);
|
576
|
-
return cState_partial_generate(state, string);
|
641
|
+
return cState_partial_generate(state, string, generate_json_string);
|
642
|
+
}
|
643
|
+
|
644
|
+
static void State_mark(void *ptr)
|
645
|
+
{
|
646
|
+
JSON_Generator_State *state = ptr;
|
647
|
+
rb_gc_mark_movable(state->indent);
|
648
|
+
rb_gc_mark_movable(state->space);
|
649
|
+
rb_gc_mark_movable(state->space_before);
|
650
|
+
rb_gc_mark_movable(state->object_nl);
|
651
|
+
rb_gc_mark_movable(state->array_nl);
|
652
|
+
}
|
653
|
+
|
654
|
+
static void State_compact(void *ptr)
|
655
|
+
{
|
656
|
+
JSON_Generator_State *state = ptr;
|
657
|
+
state->indent = rb_gc_location(state->indent);
|
658
|
+
state->space = rb_gc_location(state->space);
|
659
|
+
state->space_before = rb_gc_location(state->space_before);
|
660
|
+
state->object_nl = rb_gc_location(state->object_nl);
|
661
|
+
state->array_nl = rb_gc_location(state->array_nl);
|
577
662
|
}
|
578
663
|
|
579
664
|
static void State_free(void *ptr)
|
580
665
|
{
|
581
666
|
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
667
|
ruby_xfree(state);
|
588
668
|
}
|
589
669
|
|
590
670
|
static size_t State_memsize(const void *ptr)
|
591
671
|
{
|
592
|
-
|
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;
|
672
|
+
return sizeof(JSON_Generator_State);
|
600
673
|
}
|
601
674
|
|
602
675
|
#ifndef HAVE_RB_EXT_RACTOR_SAFE
|
@@ -606,24 +679,54 @@ static size_t State_memsize(const void *ptr)
|
|
606
679
|
|
607
680
|
static const rb_data_type_t JSON_Generator_State_type = {
|
608
681
|
"JSON/Generator/State",
|
609
|
-
{
|
682
|
+
{
|
683
|
+
.dmark = State_mark,
|
684
|
+
.dfree = State_free,
|
685
|
+
.dsize = State_memsize,
|
686
|
+
.dcompact = State_compact,
|
687
|
+
},
|
610
688
|
0, 0,
|
611
689
|
RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE,
|
612
690
|
};
|
613
691
|
|
692
|
+
static void state_init(JSON_Generator_State *state)
|
693
|
+
{
|
694
|
+
state->max_nesting = 100;
|
695
|
+
state->buffer_initial_length = FBUFFER_INITIAL_LENGTH_DEFAULT;
|
696
|
+
}
|
697
|
+
|
614
698
|
static VALUE cState_s_allocate(VALUE klass)
|
615
699
|
{
|
616
700
|
JSON_Generator_State *state;
|
617
701
|
VALUE obj = TypedData_Make_Struct(klass, JSON_Generator_State, &JSON_Generator_State_type, state);
|
618
|
-
state
|
619
|
-
state->buffer_initial_length = FBUFFER_INITIAL_LENGTH_DEFAULT;
|
702
|
+
state_init(state);
|
620
703
|
return obj;
|
621
704
|
}
|
622
705
|
|
706
|
+
static void vstate_spill(struct generate_json_data *data)
|
707
|
+
{
|
708
|
+
VALUE vstate = cState_s_allocate(cState);
|
709
|
+
GET_STATE(vstate);
|
710
|
+
MEMCPY(state, data->state, JSON_Generator_State, 1);
|
711
|
+
data->state = state;
|
712
|
+
data->vstate = vstate;
|
713
|
+
RB_OBJ_WRITTEN(vstate, Qundef, state->indent);
|
714
|
+
RB_OBJ_WRITTEN(vstate, Qundef, state->space);
|
715
|
+
RB_OBJ_WRITTEN(vstate, Qundef, state->space_before);
|
716
|
+
RB_OBJ_WRITTEN(vstate, Qundef, state->object_nl);
|
717
|
+
RB_OBJ_WRITTEN(vstate, Qundef, state->array_nl);
|
718
|
+
}
|
719
|
+
|
720
|
+
static inline VALUE vstate_get(struct generate_json_data *data)
|
721
|
+
{
|
722
|
+
if (RB_UNLIKELY(!data->vstate)) {
|
723
|
+
vstate_spill(data);
|
724
|
+
}
|
725
|
+
return data->vstate;
|
726
|
+
}
|
727
|
+
|
623
728
|
struct hash_foreach_arg {
|
624
|
-
|
625
|
-
JSON_Generator_State *state;
|
626
|
-
VALUE Vstate;
|
729
|
+
struct generate_json_data *data;
|
627
730
|
int iter;
|
628
731
|
};
|
629
732
|
|
@@ -631,27 +734,32 @@ static int
|
|
631
734
|
json_object_i(VALUE key, VALUE val, VALUE _arg)
|
632
735
|
{
|
633
736
|
struct hash_foreach_arg *arg = (struct hash_foreach_arg *)_arg;
|
634
|
-
|
635
|
-
|
636
|
-
|
737
|
+
struct generate_json_data *data = arg->data;
|
738
|
+
|
739
|
+
FBuffer *buffer = data->buffer;
|
740
|
+
JSON_Generator_State *state = data->state;
|
637
741
|
|
638
742
|
long depth = state->depth;
|
639
743
|
int j;
|
640
744
|
|
641
745
|
if (arg->iter > 0) fbuffer_append_char(buffer, ',');
|
642
746
|
if (RB_UNLIKELY(state->object_nl)) {
|
643
|
-
|
747
|
+
fbuffer_append_str(buffer, state->object_nl);
|
644
748
|
}
|
645
749
|
if (RB_UNLIKELY(state->indent)) {
|
646
750
|
for (j = 0; j < depth; j++) {
|
647
|
-
|
751
|
+
fbuffer_append_str(buffer, state->indent);
|
648
752
|
}
|
649
753
|
}
|
650
754
|
|
651
755
|
VALUE key_to_s;
|
652
756
|
switch(rb_type(key)) {
|
653
757
|
case T_STRING:
|
654
|
-
|
758
|
+
if (RB_LIKELY(RBASIC_CLASS(key) == rb_cString)) {
|
759
|
+
key_to_s = key;
|
760
|
+
} else {
|
761
|
+
key_to_s = rb_funcall(key, i_to_s, 0);
|
762
|
+
}
|
655
763
|
break;
|
656
764
|
case T_SYMBOL:
|
657
765
|
key_to_s = rb_sym2str(key);
|
@@ -661,47 +769,57 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
|
|
661
769
|
break;
|
662
770
|
}
|
663
771
|
|
664
|
-
|
665
|
-
|
772
|
+
if (RB_LIKELY(RBASIC_CLASS(key_to_s) == rb_cString)) {
|
773
|
+
generate_json_string(buffer, data, state, key_to_s);
|
774
|
+
} else {
|
775
|
+
generate_json(buffer, data, state, key_to_s);
|
776
|
+
}
|
777
|
+
if (RB_UNLIKELY(state->space_before)) fbuffer_append_str(buffer, state->space_before);
|
666
778
|
fbuffer_append_char(buffer, ':');
|
667
|
-
if (RB_UNLIKELY(state->space))
|
668
|
-
generate_json(buffer,
|
779
|
+
if (RB_UNLIKELY(state->space)) fbuffer_append_str(buffer, state->space);
|
780
|
+
generate_json(buffer, data, state, val);
|
669
781
|
|
670
782
|
arg->iter++;
|
671
783
|
return ST_CONTINUE;
|
672
784
|
}
|
673
785
|
|
674
|
-
static void generate_json_object(FBuffer *buffer,
|
786
|
+
static void generate_json_object(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
675
787
|
{
|
676
788
|
long max_nesting = state->max_nesting;
|
677
789
|
long depth = ++state->depth;
|
678
790
|
int j;
|
679
|
-
struct hash_foreach_arg arg;
|
680
791
|
|
681
792
|
if (max_nesting != 0 && depth > max_nesting) {
|
682
793
|
rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
|
683
794
|
}
|
795
|
+
|
796
|
+
if (RHASH_SIZE(obj) == 0) {
|
797
|
+
fbuffer_append(buffer, "{}", 2);
|
798
|
+
--state->depth;
|
799
|
+
return;
|
800
|
+
}
|
801
|
+
|
684
802
|
fbuffer_append_char(buffer, '{');
|
685
803
|
|
686
|
-
arg
|
687
|
-
|
688
|
-
|
689
|
-
|
804
|
+
struct hash_foreach_arg arg = {
|
805
|
+
.data = data,
|
806
|
+
.iter = 0,
|
807
|
+
};
|
690
808
|
rb_hash_foreach(obj, json_object_i, (VALUE)&arg);
|
691
809
|
|
692
810
|
depth = --state->depth;
|
693
811
|
if (RB_UNLIKELY(state->object_nl)) {
|
694
|
-
|
812
|
+
fbuffer_append_str(buffer, state->object_nl);
|
695
813
|
if (RB_UNLIKELY(state->indent)) {
|
696
814
|
for (j = 0; j < depth; j++) {
|
697
|
-
|
815
|
+
fbuffer_append_str(buffer, state->indent);
|
698
816
|
}
|
699
817
|
}
|
700
818
|
}
|
701
819
|
fbuffer_append_char(buffer, '}');
|
702
820
|
}
|
703
821
|
|
704
|
-
static void generate_json_array(FBuffer *buffer,
|
822
|
+
static void generate_json_array(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
705
823
|
{
|
706
824
|
long max_nesting = state->max_nesting;
|
707
825
|
long depth = ++state->depth;
|
@@ -709,34 +827,39 @@ static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
|
|
709
827
|
if (max_nesting != 0 && depth > max_nesting) {
|
710
828
|
rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
|
711
829
|
}
|
830
|
+
|
831
|
+
if (RARRAY_LEN(obj) == 0) {
|
832
|
+
fbuffer_append(buffer, "[]", 2);
|
833
|
+
--state->depth;
|
834
|
+
return;
|
835
|
+
}
|
836
|
+
|
712
837
|
fbuffer_append_char(buffer, '[');
|
713
|
-
if (RB_UNLIKELY(state->array_nl))
|
838
|
+
if (RB_UNLIKELY(state->array_nl)) fbuffer_append_str(buffer, state->array_nl);
|
714
839
|
for(i = 0; i < RARRAY_LEN(obj); i++) {
|
715
840
|
if (i > 0) {
|
716
841
|
fbuffer_append_char(buffer, ',');
|
717
|
-
if (RB_UNLIKELY(state->array_nl))
|
842
|
+
if (RB_UNLIKELY(state->array_nl)) fbuffer_append_str(buffer, state->array_nl);
|
718
843
|
}
|
719
844
|
if (RB_UNLIKELY(state->indent)) {
|
720
845
|
for (j = 0; j < depth; j++) {
|
721
|
-
|
846
|
+
fbuffer_append_str(buffer, state->indent);
|
722
847
|
}
|
723
848
|
}
|
724
|
-
generate_json(buffer,
|
849
|
+
generate_json(buffer, data, state, RARRAY_AREF(obj, i));
|
725
850
|
}
|
726
851
|
state->depth = --depth;
|
727
852
|
if (RB_UNLIKELY(state->array_nl)) {
|
728
|
-
|
853
|
+
fbuffer_append_str(buffer, state->array_nl);
|
729
854
|
if (RB_UNLIKELY(state->indent)) {
|
730
855
|
for (j = 0; j < depth; j++) {
|
731
|
-
|
856
|
+
fbuffer_append_str(buffer, state->indent);
|
732
857
|
}
|
733
858
|
}
|
734
859
|
}
|
735
860
|
fbuffer_append_char(buffer, ']');
|
736
861
|
}
|
737
862
|
|
738
|
-
static int usascii_encindex, utf8_encindex, binary_encindex;
|
739
|
-
|
740
863
|
static inline int enc_utf8_compatible_p(int enc_idx)
|
741
864
|
{
|
742
865
|
if (enc_idx == usascii_encindex) return 1;
|
@@ -750,13 +873,14 @@ static inline VALUE ensure_valid_encoding(VALUE str)
|
|
750
873
|
VALUE utf8_string;
|
751
874
|
if (RB_UNLIKELY(!enc_utf8_compatible_p(encindex))) {
|
752
875
|
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
876
|
utf8_string = rb_enc_associate_index(rb_str_dup(str), utf8_encindex);
|
757
877
|
switch (rb_enc_str_coderange(utf8_string)) {
|
758
878
|
case ENC_CODERANGE_7BIT:
|
879
|
+
return utf8_string;
|
759
880
|
case ENC_CODERANGE_VALID:
|
881
|
+
// For historical reason, we silently reinterpret binary strings as UTF-8 if it would work.
|
882
|
+
// TODO: Raise in 3.0.0
|
883
|
+
rb_warn("JSON.generate: UTF-8 string passed as BINARY, this will raise an encoding error in json 3.0");
|
760
884
|
return utf8_string;
|
761
885
|
break;
|
762
886
|
}
|
@@ -767,7 +891,7 @@ static inline VALUE ensure_valid_encoding(VALUE str)
|
|
767
891
|
return str;
|
768
892
|
}
|
769
893
|
|
770
|
-
static void generate_json_string(FBuffer *buffer,
|
894
|
+
static void generate_json_string(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
771
895
|
{
|
772
896
|
obj = ensure_valid_encoding(obj);
|
773
897
|
|
@@ -791,42 +915,43 @@ static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_S
|
|
791
915
|
fbuffer_append_char(buffer, '"');
|
792
916
|
}
|
793
917
|
|
794
|
-
static void generate_json_null(FBuffer *buffer,
|
918
|
+
static void generate_json_null(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
795
919
|
{
|
796
920
|
fbuffer_append(buffer, "null", 4);
|
797
921
|
}
|
798
922
|
|
799
|
-
static void generate_json_false(FBuffer *buffer,
|
923
|
+
static void generate_json_false(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
800
924
|
{
|
801
925
|
fbuffer_append(buffer, "false", 5);
|
802
926
|
}
|
803
927
|
|
804
|
-
static void generate_json_true(FBuffer *buffer,
|
928
|
+
static void generate_json_true(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
805
929
|
{
|
806
930
|
fbuffer_append(buffer, "true", 4);
|
807
931
|
}
|
808
932
|
|
809
|
-
static void generate_json_fixnum(FBuffer *buffer,
|
933
|
+
static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
810
934
|
{
|
811
935
|
fbuffer_append_long(buffer, FIX2LONG(obj));
|
812
936
|
}
|
813
937
|
|
814
|
-
static void generate_json_bignum(FBuffer *buffer,
|
938
|
+
static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
815
939
|
{
|
816
940
|
VALUE tmp = rb_funcall(obj, i_to_s, 0);
|
817
941
|
fbuffer_append_str(buffer, tmp);
|
818
942
|
}
|
819
943
|
|
820
944
|
#ifdef RUBY_INTEGER_UNIFICATION
|
821
|
-
static void generate_json_integer(FBuffer *buffer,
|
945
|
+
static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
822
946
|
{
|
823
947
|
if (FIXNUM_P(obj))
|
824
|
-
generate_json_fixnum(buffer,
|
948
|
+
generate_json_fixnum(buffer, data, state, obj);
|
825
949
|
else
|
826
|
-
generate_json_bignum(buffer,
|
950
|
+
generate_json_bignum(buffer, data, state, obj);
|
827
951
|
}
|
828
952
|
#endif
|
829
|
-
|
953
|
+
|
954
|
+
static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
830
955
|
{
|
831
956
|
double value = RFLOAT_VALUE(obj);
|
832
957
|
char allow_nan = state->allow_nan;
|
@@ -841,20 +966,20 @@ static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
|
|
841
966
|
fbuffer_append_str(buffer, tmp);
|
842
967
|
}
|
843
968
|
|
844
|
-
static void generate_json(FBuffer *buffer,
|
969
|
+
static void generate_json(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
845
970
|
{
|
846
971
|
VALUE tmp;
|
847
972
|
if (obj == Qnil) {
|
848
|
-
generate_json_null(buffer,
|
973
|
+
generate_json_null(buffer, data, state, obj);
|
849
974
|
} else if (obj == Qfalse) {
|
850
|
-
generate_json_false(buffer,
|
975
|
+
generate_json_false(buffer, data, state, obj);
|
851
976
|
} else if (obj == Qtrue) {
|
852
|
-
generate_json_true(buffer,
|
977
|
+
generate_json_true(buffer, data, state, obj);
|
853
978
|
} else if (RB_SPECIAL_CONST_P(obj)) {
|
854
979
|
if (RB_FIXNUM_P(obj)) {
|
855
|
-
generate_json_fixnum(buffer,
|
980
|
+
generate_json_fixnum(buffer, data, state, obj);
|
856
981
|
} else if (RB_FLONUM_P(obj)) {
|
857
|
-
generate_json_float(buffer,
|
982
|
+
generate_json_float(buffer, data, state, obj);
|
858
983
|
} else {
|
859
984
|
goto general;
|
860
985
|
}
|
@@ -862,62 +987,46 @@ static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *s
|
|
862
987
|
VALUE klass = RBASIC_CLASS(obj);
|
863
988
|
switch (RB_BUILTIN_TYPE(obj)) {
|
864
989
|
case T_BIGNUM:
|
865
|
-
generate_json_bignum(buffer,
|
990
|
+
generate_json_bignum(buffer, data, state, obj);
|
866
991
|
break;
|
867
992
|
case T_HASH:
|
868
993
|
if (klass != rb_cHash) goto general;
|
869
|
-
generate_json_object(buffer,
|
994
|
+
generate_json_object(buffer, data, state, obj);
|
870
995
|
break;
|
871
996
|
case T_ARRAY:
|
872
997
|
if (klass != rb_cArray) goto general;
|
873
|
-
generate_json_array(buffer,
|
998
|
+
generate_json_array(buffer, data, state, obj);
|
874
999
|
break;
|
875
1000
|
case T_STRING:
|
876
1001
|
if (klass != rb_cString) goto general;
|
877
|
-
generate_json_string(buffer,
|
1002
|
+
generate_json_string(buffer, data, state, obj);
|
878
1003
|
break;
|
879
1004
|
case T_FLOAT:
|
880
1005
|
if (klass != rb_cFloat) goto general;
|
881
|
-
generate_json_float(buffer,
|
1006
|
+
generate_json_float(buffer, data, state, obj);
|
882
1007
|
break;
|
883
1008
|
default:
|
884
1009
|
general:
|
885
1010
|
if (state->strict) {
|
886
1011
|
rb_raise(eGeneratorError, "%"PRIsVALUE" not allowed in JSON", CLASS_OF(obj));
|
887
1012
|
} else if (rb_respond_to(obj, i_to_json)) {
|
888
|
-
tmp = rb_funcall(obj, i_to_json, 1,
|
1013
|
+
tmp = rb_funcall(obj, i_to_json, 1, vstate_get(data));
|
889
1014
|
Check_Type(tmp, T_STRING);
|
890
1015
|
fbuffer_append_str(buffer, tmp);
|
891
1016
|
} else {
|
892
1017
|
tmp = rb_funcall(obj, i_to_s, 0);
|
893
1018
|
Check_Type(tmp, T_STRING);
|
894
|
-
generate_json_string(buffer,
|
1019
|
+
generate_json_string(buffer, data, state, tmp);
|
895
1020
|
}
|
896
1021
|
}
|
897
1022
|
}
|
898
1023
|
}
|
899
1024
|
|
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
1025
|
static VALUE generate_json_try(VALUE d)
|
917
1026
|
{
|
918
1027
|
struct generate_json_data *data = (struct generate_json_data *)d;
|
919
1028
|
|
920
|
-
|
1029
|
+
data->func(data->buffer, data, data->state, data->obj);
|
921
1030
|
|
922
1031
|
return Qnil;
|
923
1032
|
}
|
@@ -927,25 +1036,33 @@ static VALUE generate_json_rescue(VALUE d, VALUE exc)
|
|
927
1036
|
struct generate_json_data *data = (struct generate_json_data *)d;
|
928
1037
|
fbuffer_free(data->buffer);
|
929
1038
|
|
1039
|
+
if (RBASIC_CLASS(exc) == rb_path2class("Encoding::UndefinedConversionError")) {
|
1040
|
+
exc = rb_exc_new_str(eGeneratorError, rb_funcall(exc, rb_intern("message"), 0));
|
1041
|
+
}
|
1042
|
+
|
930
1043
|
rb_exc_raise(exc);
|
931
1044
|
|
932
1045
|
return Qundef;
|
933
1046
|
}
|
934
1047
|
|
935
|
-
static VALUE cState_partial_generate(VALUE self, VALUE obj)
|
1048
|
+
static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func)
|
936
1049
|
{
|
937
|
-
FBuffer *buffer = cState_prepare_buffer(self);
|
938
1050
|
GET_STATE(self);
|
939
1051
|
|
1052
|
+
char stack_buffer[FBUFFER_STACK_SIZE];
|
1053
|
+
FBuffer buffer = {0};
|
1054
|
+
fbuffer_stack_init(&buffer, state->buffer_initial_length, stack_buffer, FBUFFER_STACK_SIZE);
|
1055
|
+
|
940
1056
|
struct generate_json_data data = {
|
941
|
-
.buffer = buffer,
|
1057
|
+
.buffer = &buffer,
|
942
1058
|
.vstate = self,
|
943
1059
|
.state = state,
|
944
|
-
.obj = obj
|
1060
|
+
.obj = obj,
|
1061
|
+
.func = func
|
945
1062
|
};
|
946
1063
|
rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data);
|
947
1064
|
|
948
|
-
return fbuffer_to_s(buffer);
|
1065
|
+
return fbuffer_to_s(&buffer);
|
949
1066
|
}
|
950
1067
|
|
951
1068
|
/*
|
@@ -957,7 +1074,7 @@ static VALUE cState_partial_generate(VALUE self, VALUE obj)
|
|
957
1074
|
*/
|
958
1075
|
static VALUE cState_generate(VALUE self, VALUE obj)
|
959
1076
|
{
|
960
|
-
VALUE result = cState_partial_generate(self, obj);
|
1077
|
+
VALUE result = cState_partial_generate(self, obj, generate_json);
|
961
1078
|
GET_STATE(self);
|
962
1079
|
(void)state;
|
963
1080
|
return result;
|
@@ -985,11 +1102,11 @@ static VALUE cState_init_copy(VALUE obj, VALUE orig)
|
|
985
1102
|
if (!objState) rb_raise(rb_eArgError, "unallocated JSON::State");
|
986
1103
|
|
987
1104
|
MEMCPY(objState, origState, JSON_Generator_State, 1);
|
988
|
-
objState->indent =
|
989
|
-
objState->space =
|
990
|
-
objState->space_before =
|
991
|
-
objState->object_nl =
|
992
|
-
objState->array_nl =
|
1105
|
+
objState->indent = origState->indent;
|
1106
|
+
objState->space = origState->space;
|
1107
|
+
objState->space_before = origState->space_before;
|
1108
|
+
objState->object_nl = origState->object_nl;
|
1109
|
+
objState->array_nl = origState->array_nl;
|
993
1110
|
return obj;
|
994
1111
|
}
|
995
1112
|
|
@@ -1019,7 +1136,18 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
|
|
1019
1136
|
static VALUE cState_indent(VALUE self)
|
1020
1137
|
{
|
1021
1138
|
GET_STATE(self);
|
1022
|
-
return state->indent ?
|
1139
|
+
return state->indent ? state->indent : rb_str_freeze(rb_utf8_str_new("", 0));
|
1140
|
+
}
|
1141
|
+
|
1142
|
+
static VALUE string_config(VALUE config)
|
1143
|
+
{
|
1144
|
+
if (RTEST(config)) {
|
1145
|
+
Check_Type(config, T_STRING);
|
1146
|
+
if (RSTRING_LEN(config)) {
|
1147
|
+
return rb_str_new_frozen(config);
|
1148
|
+
}
|
1149
|
+
}
|
1150
|
+
return Qfalse;
|
1023
1151
|
}
|
1024
1152
|
|
1025
1153
|
/*
|
@@ -1029,21 +1157,8 @@ static VALUE cState_indent(VALUE self)
|
|
1029
1157
|
*/
|
1030
1158
|
static VALUE cState_indent_set(VALUE self, VALUE indent)
|
1031
1159
|
{
|
1032
|
-
unsigned long len;
|
1033
1160
|
GET_STATE(self);
|
1034
|
-
|
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
|
-
}
|
1161
|
+
RB_OBJ_WRITE(self, &state->indent, string_config(indent));
|
1047
1162
|
return Qnil;
|
1048
1163
|
}
|
1049
1164
|
|
@@ -1056,7 +1171,7 @@ static VALUE cState_indent_set(VALUE self, VALUE indent)
|
|
1056
1171
|
static VALUE cState_space(VALUE self)
|
1057
1172
|
{
|
1058
1173
|
GET_STATE(self);
|
1059
|
-
return state->space ?
|
1174
|
+
return state->space ? state->space : rb_str_freeze(rb_utf8_str_new("", 0));
|
1060
1175
|
}
|
1061
1176
|
|
1062
1177
|
/*
|
@@ -1067,21 +1182,8 @@ static VALUE cState_space(VALUE self)
|
|
1067
1182
|
*/
|
1068
1183
|
static VALUE cState_space_set(VALUE self, VALUE space)
|
1069
1184
|
{
|
1070
|
-
unsigned long len;
|
1071
1185
|
GET_STATE(self);
|
1072
|
-
|
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
|
-
}
|
1186
|
+
RB_OBJ_WRITE(self, &state->space, string_config(space));
|
1085
1187
|
return Qnil;
|
1086
1188
|
}
|
1087
1189
|
|
@@ -1093,7 +1195,7 @@ static VALUE cState_space_set(VALUE self, VALUE space)
|
|
1093
1195
|
static VALUE cState_space_before(VALUE self)
|
1094
1196
|
{
|
1095
1197
|
GET_STATE(self);
|
1096
|
-
return state->space_before ?
|
1198
|
+
return state->space_before ? state->space_before : rb_str_freeze(rb_utf8_str_new("", 0));
|
1097
1199
|
}
|
1098
1200
|
|
1099
1201
|
/*
|
@@ -1103,21 +1205,8 @@ static VALUE cState_space_before(VALUE self)
|
|
1103
1205
|
*/
|
1104
1206
|
static VALUE cState_space_before_set(VALUE self, VALUE space_before)
|
1105
1207
|
{
|
1106
|
-
unsigned long len;
|
1107
1208
|
GET_STATE(self);
|
1108
|
-
|
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
|
-
}
|
1209
|
+
RB_OBJ_WRITE(self, &state->space_before, string_config(space_before));
|
1121
1210
|
return Qnil;
|
1122
1211
|
}
|
1123
1212
|
|
@@ -1130,7 +1219,7 @@ static VALUE cState_space_before_set(VALUE self, VALUE space_before)
|
|
1130
1219
|
static VALUE cState_object_nl(VALUE self)
|
1131
1220
|
{
|
1132
1221
|
GET_STATE(self);
|
1133
|
-
return state->object_nl ?
|
1222
|
+
return state->object_nl ? state->object_nl : rb_str_freeze(rb_utf8_str_new("", 0));
|
1134
1223
|
}
|
1135
1224
|
|
1136
1225
|
/*
|
@@ -1141,20 +1230,8 @@ static VALUE cState_object_nl(VALUE self)
|
|
1141
1230
|
*/
|
1142
1231
|
static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
|
1143
1232
|
{
|
1144
|
-
unsigned long len;
|
1145
1233
|
GET_STATE(self);
|
1146
|
-
|
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
|
-
}
|
1234
|
+
RB_OBJ_WRITE(self, &state->object_nl, string_config(object_nl));
|
1158
1235
|
return Qnil;
|
1159
1236
|
}
|
1160
1237
|
|
@@ -1166,7 +1243,7 @@ static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
|
|
1166
1243
|
static VALUE cState_array_nl(VALUE self)
|
1167
1244
|
{
|
1168
1245
|
GET_STATE(self);
|
1169
|
-
return state->array_nl ?
|
1246
|
+
return state->array_nl ? state->array_nl : rb_str_freeze(rb_utf8_str_new("", 0));
|
1170
1247
|
}
|
1171
1248
|
|
1172
1249
|
/*
|
@@ -1176,20 +1253,8 @@ static VALUE cState_array_nl(VALUE self)
|
|
1176
1253
|
*/
|
1177
1254
|
static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
|
1178
1255
|
{
|
1179
|
-
unsigned long len;
|
1180
1256
|
GET_STATE(self);
|
1181
|
-
|
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
|
-
}
|
1257
|
+
RB_OBJ_WRITE(self, &state->array_nl, string_config(array_nl));
|
1193
1258
|
return Qnil;
|
1194
1259
|
}
|
1195
1260
|
|
@@ -1218,6 +1283,11 @@ static VALUE cState_max_nesting(VALUE self)
|
|
1218
1283
|
return LONG2FIX(state->max_nesting);
|
1219
1284
|
}
|
1220
1285
|
|
1286
|
+
static long long_config(VALUE num)
|
1287
|
+
{
|
1288
|
+
return RTEST(num) ? FIX2LONG(num) : 0;
|
1289
|
+
}
|
1290
|
+
|
1221
1291
|
/*
|
1222
1292
|
* call-seq: max_nesting=(depth)
|
1223
1293
|
*
|
@@ -1227,8 +1297,7 @@ static VALUE cState_max_nesting(VALUE self)
|
|
1227
1297
|
static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
|
1228
1298
|
{
|
1229
1299
|
GET_STATE(self);
|
1230
|
-
|
1231
|
-
state->max_nesting = FIX2LONG(depth);
|
1300
|
+
state->max_nesting = long_config(depth);
|
1232
1301
|
return Qnil;
|
1233
1302
|
}
|
1234
1303
|
|
@@ -1356,8 +1425,7 @@ static VALUE cState_depth(VALUE self)
|
|
1356
1425
|
static VALUE cState_depth_set(VALUE self, VALUE depth)
|
1357
1426
|
{
|
1358
1427
|
GET_STATE(self);
|
1359
|
-
|
1360
|
-
state->depth = FIX2LONG(depth);
|
1428
|
+
state->depth = long_config(depth);
|
1361
1429
|
return Qnil;
|
1362
1430
|
}
|
1363
1431
|
|
@@ -1372,6 +1440,15 @@ static VALUE cState_buffer_initial_length(VALUE self)
|
|
1372
1440
|
return LONG2FIX(state->buffer_initial_length);
|
1373
1441
|
}
|
1374
1442
|
|
1443
|
+
static void buffer_initial_length_set(JSON_Generator_State *state, VALUE buffer_initial_length)
|
1444
|
+
{
|
1445
|
+
Check_Type(buffer_initial_length, T_FIXNUM);
|
1446
|
+
long initial_length = FIX2LONG(buffer_initial_length);
|
1447
|
+
if (initial_length > 0) {
|
1448
|
+
state->buffer_initial_length = initial_length;
|
1449
|
+
}
|
1450
|
+
}
|
1451
|
+
|
1375
1452
|
/*
|
1376
1453
|
* call-seq: buffer_initial_length=(length)
|
1377
1454
|
*
|
@@ -1380,16 +1457,73 @@ static VALUE cState_buffer_initial_length(VALUE self)
|
|
1380
1457
|
*/
|
1381
1458
|
static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_length)
|
1382
1459
|
{
|
1383
|
-
long initial_length;
|
1384
1460
|
GET_STATE(self);
|
1385
|
-
|
1386
|
-
initial_length = FIX2LONG(buffer_initial_length);
|
1387
|
-
if (initial_length > 0) {
|
1388
|
-
state->buffer_initial_length = initial_length;
|
1389
|
-
}
|
1461
|
+
buffer_initial_length_set(state, buffer_initial_length);
|
1390
1462
|
return Qnil;
|
1391
1463
|
}
|
1392
1464
|
|
1465
|
+
static int configure_state_i(VALUE key, VALUE val, VALUE _arg)
|
1466
|
+
{
|
1467
|
+
JSON_Generator_State *state = (JSON_Generator_State *)_arg;
|
1468
|
+
|
1469
|
+
if (key == sym_indent) { state->indent = string_config(val); }
|
1470
|
+
else if (key == sym_space) { state->space = string_config(val); }
|
1471
|
+
else if (key == sym_space_before) { state->space_before = string_config(val); }
|
1472
|
+
else if (key == sym_object_nl) { state->object_nl = string_config(val); }
|
1473
|
+
else if (key == sym_array_nl) { state->array_nl = string_config(val); }
|
1474
|
+
else if (key == sym_max_nesting) { state->max_nesting = long_config(val); }
|
1475
|
+
else if (key == sym_allow_nan) { state->allow_nan = RTEST(val); }
|
1476
|
+
else if (key == sym_ascii_only) { state->ascii_only = RTEST(val); }
|
1477
|
+
else if (key == sym_depth) { state->depth = long_config(val); }
|
1478
|
+
else if (key == sym_buffer_initial_length) { buffer_initial_length_set(state, val); }
|
1479
|
+
else if (key == sym_script_safe) { state->script_safe = RTEST(val); }
|
1480
|
+
else if (key == sym_escape_slash) { state->script_safe = RTEST(val); }
|
1481
|
+
else if (key == sym_strict) { state->strict = RTEST(val); }
|
1482
|
+
return ST_CONTINUE;
|
1483
|
+
}
|
1484
|
+
|
1485
|
+
static void configure_state(JSON_Generator_State *state, VALUE config)
|
1486
|
+
{
|
1487
|
+
if (!RTEST(config)) return;
|
1488
|
+
|
1489
|
+
Check_Type(config, T_HASH);
|
1490
|
+
|
1491
|
+
if (!RHASH_SIZE(config)) return;
|
1492
|
+
|
1493
|
+
// We assume in most cases few keys are set so it's faster to go over
|
1494
|
+
// the provided keys than to check all possible keys.
|
1495
|
+
rb_hash_foreach(config, configure_state_i, (VALUE)state);
|
1496
|
+
}
|
1497
|
+
|
1498
|
+
static VALUE cState_configure(VALUE self, VALUE opts)
|
1499
|
+
{
|
1500
|
+
GET_STATE(self);
|
1501
|
+
configure_state(state, opts);
|
1502
|
+
return self;
|
1503
|
+
}
|
1504
|
+
|
1505
|
+
static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts)
|
1506
|
+
{
|
1507
|
+
JSON_Generator_State state = {0};
|
1508
|
+
state_init(&state);
|
1509
|
+
configure_state(&state, opts);
|
1510
|
+
|
1511
|
+
char stack_buffer[FBUFFER_STACK_SIZE];
|
1512
|
+
FBuffer buffer = {0};
|
1513
|
+
fbuffer_stack_init(&buffer, state.buffer_initial_length, stack_buffer, FBUFFER_STACK_SIZE);
|
1514
|
+
|
1515
|
+
struct generate_json_data data = {
|
1516
|
+
.buffer = &buffer,
|
1517
|
+
.vstate = Qfalse,
|
1518
|
+
.state = &state,
|
1519
|
+
.obj = obj,
|
1520
|
+
.func = generate_json,
|
1521
|
+
};
|
1522
|
+
rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data);
|
1523
|
+
|
1524
|
+
return fbuffer_to_s(&buffer);
|
1525
|
+
}
|
1526
|
+
|
1393
1527
|
/*
|
1394
1528
|
*
|
1395
1529
|
*/
|
@@ -1416,6 +1550,7 @@ void Init_generator(void)
|
|
1416
1550
|
rb_define_singleton_method(cState, "from_state", cState_from_state_s, 1);
|
1417
1551
|
rb_define_method(cState, "initialize", cState_initialize, -1);
|
1418
1552
|
rb_define_alias(cState, "initialize", "initialize"); // avoid method redefinition warnings
|
1553
|
+
rb_define_private_method(cState, "_configure", cState_configure, 1);
|
1419
1554
|
|
1420
1555
|
rb_define_method(cState, "initialize_copy", cState_init_copy, 1);
|
1421
1556
|
rb_define_method(cState, "indent", cState_indent, 0);
|
@@ -1450,6 +1585,8 @@ void Init_generator(void)
|
|
1450
1585
|
rb_define_method(cState, "buffer_initial_length=", cState_buffer_initial_length_set, 1);
|
1451
1586
|
rb_define_method(cState, "generate", cState_generate, 1);
|
1452
1587
|
|
1588
|
+
rb_define_singleton_method(cState, "generate", cState_m_generate, 2);
|
1589
|
+
|
1453
1590
|
VALUE mGeneratorMethods = rb_define_module_under(mGenerator, "GeneratorMethods");
|
1454
1591
|
|
1455
1592
|
VALUE mObject = rb_define_module_under(mGeneratorMethods, "Object");
|
@@ -1504,6 +1641,20 @@ void Init_generator(void)
|
|
1504
1641
|
i_extend = rb_intern("extend");
|
1505
1642
|
i_encode = rb_intern("encode");
|
1506
1643
|
|
1644
|
+
sym_indent = ID2SYM(rb_intern("indent"));
|
1645
|
+
sym_space = ID2SYM(rb_intern("space"));
|
1646
|
+
sym_space_before = ID2SYM(rb_intern("space_before"));
|
1647
|
+
sym_object_nl = ID2SYM(rb_intern("object_nl"));
|
1648
|
+
sym_array_nl = ID2SYM(rb_intern("array_nl"));
|
1649
|
+
sym_max_nesting = ID2SYM(rb_intern("max_nesting"));
|
1650
|
+
sym_allow_nan = ID2SYM(rb_intern("allow_nan"));
|
1651
|
+
sym_ascii_only = ID2SYM(rb_intern("ascii_only"));
|
1652
|
+
sym_depth = ID2SYM(rb_intern("depth"));
|
1653
|
+
sym_buffer_initial_length = ID2SYM(rb_intern("buffer_initial_length"));
|
1654
|
+
sym_script_safe = ID2SYM(rb_intern("script_safe"));
|
1655
|
+
sym_escape_slash = ID2SYM(rb_intern("escape_slash"));
|
1656
|
+
sym_strict = ID2SYM(rb_intern("strict"));
|
1657
|
+
|
1507
1658
|
usascii_encindex = rb_usascii_encindex();
|
1508
1659
|
utf8_encindex = rb_utf8_encindex();
|
1509
1660
|
binary_encindex = rb_ascii8bit_encindex();
|