json 2.7.5 → 2.8.2
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 +23 -0
- data/README.md +8 -77
- data/ext/json/ext/fbuffer/fbuffer.h +85 -47
- data/ext/json/ext/generator/generator.c +335 -204
- data/ext/json/ext/parser/extconf.rb +5 -27
- data/ext/json/ext/parser/parser.c +1598 -597
- data/ext/json/ext/parser/parser.rl +726 -258
- data/json.gemspec +4 -1
- data/lib/json/add/bigdecimal.rb +1 -1
- data/lib/json/common.rb +206 -64
- data/lib/json/ext/generator/state.rb +1 -31
- data/lib/json/ext.rb +2 -4
- data/lib/json/{pure → truffle_ruby}/generator.rb +158 -117
- data/lib/json/version.rb +1 -1
- data/lib/json.rb +15 -20
- metadata +4 -8
- data/ext/json/ext/generator/generator.h +0 -118
- 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
|
*
|
@@ -512,7 +560,7 @@ static VALUE mString_to_json_raw_object(VALUE self)
|
|
512
560
|
VALUE result = rb_hash_new();
|
513
561
|
rb_hash_aset(result, rb_funcall(mJSON, i_create_id, 0), rb_class_name(rb_obj_class(self)));
|
514
562
|
ary = rb_funcall(self, i_unpack, 1, rb_str_new2("C*"));
|
515
|
-
rb_hash_aset(result,
|
563
|
+
rb_hash_aset(result, rb_utf8_str_new_lit("raw"), ary);
|
516
564
|
return result;
|
517
565
|
}
|
518
566
|
|
@@ -593,27 +641,35 @@ static VALUE mObject_to_json(int argc, VALUE *argv, VALUE self)
|
|
593
641
|
return cState_partial_generate(state, string, generate_json_string);
|
594
642
|
}
|
595
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);
|
662
|
+
}
|
663
|
+
|
596
664
|
static void State_free(void *ptr)
|
597
665
|
{
|
598
666
|
JSON_Generator_State *state = ptr;
|
599
|
-
if (state->indent) ruby_xfree(state->indent);
|
600
|
-
if (state->space) ruby_xfree(state->space);
|
601
|
-
if (state->space_before) ruby_xfree(state->space_before);
|
602
|
-
if (state->object_nl) ruby_xfree(state->object_nl);
|
603
|
-
if (state->array_nl) ruby_xfree(state->array_nl);
|
604
667
|
ruby_xfree(state);
|
605
668
|
}
|
606
669
|
|
607
670
|
static size_t State_memsize(const void *ptr)
|
608
671
|
{
|
609
|
-
|
610
|
-
size_t size = sizeof(*state);
|
611
|
-
if (state->indent) size += state->indent_len + 1;
|
612
|
-
if (state->space) size += state->space_len + 1;
|
613
|
-
if (state->space_before) size += state->space_before_len + 1;
|
614
|
-
if (state->object_nl) size += state->object_nl_len + 1;
|
615
|
-
if (state->array_nl) size += state->array_nl_len + 1;
|
616
|
-
return size;
|
672
|
+
return sizeof(JSON_Generator_State);
|
617
673
|
}
|
618
674
|
|
619
675
|
#ifndef HAVE_RB_EXT_RACTOR_SAFE
|
@@ -623,24 +679,54 @@ static size_t State_memsize(const void *ptr)
|
|
623
679
|
|
624
680
|
static const rb_data_type_t JSON_Generator_State_type = {
|
625
681
|
"JSON/Generator/State",
|
626
|
-
{
|
682
|
+
{
|
683
|
+
.dmark = State_mark,
|
684
|
+
.dfree = State_free,
|
685
|
+
.dsize = State_memsize,
|
686
|
+
.dcompact = State_compact,
|
687
|
+
},
|
627
688
|
0, 0,
|
628
689
|
RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE,
|
629
690
|
};
|
630
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
|
+
|
631
698
|
static VALUE cState_s_allocate(VALUE klass)
|
632
699
|
{
|
633
700
|
JSON_Generator_State *state;
|
634
701
|
VALUE obj = TypedData_Make_Struct(klass, JSON_Generator_State, &JSON_Generator_State_type, state);
|
635
|
-
state
|
636
|
-
state->buffer_initial_length = FBUFFER_INITIAL_LENGTH_DEFAULT;
|
702
|
+
state_init(state);
|
637
703
|
return obj;
|
638
704
|
}
|
639
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
|
+
|
640
728
|
struct hash_foreach_arg {
|
641
|
-
|
642
|
-
JSON_Generator_State *state;
|
643
|
-
VALUE Vstate;
|
729
|
+
struct generate_json_data *data;
|
644
730
|
int iter;
|
645
731
|
};
|
646
732
|
|
@@ -648,27 +734,32 @@ static int
|
|
648
734
|
json_object_i(VALUE key, VALUE val, VALUE _arg)
|
649
735
|
{
|
650
736
|
struct hash_foreach_arg *arg = (struct hash_foreach_arg *)_arg;
|
651
|
-
|
652
|
-
|
653
|
-
|
737
|
+
struct generate_json_data *data = arg->data;
|
738
|
+
|
739
|
+
FBuffer *buffer = data->buffer;
|
740
|
+
JSON_Generator_State *state = data->state;
|
654
741
|
|
655
742
|
long depth = state->depth;
|
656
743
|
int j;
|
657
744
|
|
658
745
|
if (arg->iter > 0) fbuffer_append_char(buffer, ',');
|
659
746
|
if (RB_UNLIKELY(state->object_nl)) {
|
660
|
-
|
747
|
+
fbuffer_append_str(buffer, state->object_nl);
|
661
748
|
}
|
662
749
|
if (RB_UNLIKELY(state->indent)) {
|
663
750
|
for (j = 0; j < depth; j++) {
|
664
|
-
|
751
|
+
fbuffer_append_str(buffer, state->indent);
|
665
752
|
}
|
666
753
|
}
|
667
754
|
|
668
755
|
VALUE key_to_s;
|
669
756
|
switch(rb_type(key)) {
|
670
757
|
case T_STRING:
|
671
|
-
|
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
|
+
}
|
672
763
|
break;
|
673
764
|
case T_SYMBOL:
|
674
765
|
key_to_s = rb_sym2str(key);
|
@@ -678,47 +769,57 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
|
|
678
769
|
break;
|
679
770
|
}
|
680
771
|
|
681
|
-
|
682
|
-
|
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);
|
683
778
|
fbuffer_append_char(buffer, ':');
|
684
|
-
if (RB_UNLIKELY(state->space))
|
685
|
-
generate_json(buffer,
|
779
|
+
if (RB_UNLIKELY(state->space)) fbuffer_append_str(buffer, state->space);
|
780
|
+
generate_json(buffer, data, state, val);
|
686
781
|
|
687
782
|
arg->iter++;
|
688
783
|
return ST_CONTINUE;
|
689
784
|
}
|
690
785
|
|
691
|
-
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)
|
692
787
|
{
|
693
788
|
long max_nesting = state->max_nesting;
|
694
789
|
long depth = ++state->depth;
|
695
790
|
int j;
|
696
|
-
struct hash_foreach_arg arg;
|
697
791
|
|
698
792
|
if (max_nesting != 0 && depth > max_nesting) {
|
699
793
|
rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
|
700
794
|
}
|
795
|
+
|
796
|
+
if (RHASH_SIZE(obj) == 0) {
|
797
|
+
fbuffer_append(buffer, "{}", 2);
|
798
|
+
--state->depth;
|
799
|
+
return;
|
800
|
+
}
|
801
|
+
|
701
802
|
fbuffer_append_char(buffer, '{');
|
702
803
|
|
703
|
-
arg
|
704
|
-
|
705
|
-
|
706
|
-
|
804
|
+
struct hash_foreach_arg arg = {
|
805
|
+
.data = data,
|
806
|
+
.iter = 0,
|
807
|
+
};
|
707
808
|
rb_hash_foreach(obj, json_object_i, (VALUE)&arg);
|
708
809
|
|
709
810
|
depth = --state->depth;
|
710
811
|
if (RB_UNLIKELY(state->object_nl)) {
|
711
|
-
|
812
|
+
fbuffer_append_str(buffer, state->object_nl);
|
712
813
|
if (RB_UNLIKELY(state->indent)) {
|
713
814
|
for (j = 0; j < depth; j++) {
|
714
|
-
|
815
|
+
fbuffer_append_str(buffer, state->indent);
|
715
816
|
}
|
716
817
|
}
|
717
818
|
}
|
718
819
|
fbuffer_append_char(buffer, '}');
|
719
820
|
}
|
720
821
|
|
721
|
-
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)
|
722
823
|
{
|
723
824
|
long max_nesting = state->max_nesting;
|
724
825
|
long depth = ++state->depth;
|
@@ -726,34 +827,39 @@ static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
|
|
726
827
|
if (max_nesting != 0 && depth > max_nesting) {
|
727
828
|
rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
|
728
829
|
}
|
830
|
+
|
831
|
+
if (RARRAY_LEN(obj) == 0) {
|
832
|
+
fbuffer_append(buffer, "[]", 2);
|
833
|
+
--state->depth;
|
834
|
+
return;
|
835
|
+
}
|
836
|
+
|
729
837
|
fbuffer_append_char(buffer, '[');
|
730
|
-
if (RB_UNLIKELY(state->array_nl))
|
838
|
+
if (RB_UNLIKELY(state->array_nl)) fbuffer_append_str(buffer, state->array_nl);
|
731
839
|
for(i = 0; i < RARRAY_LEN(obj); i++) {
|
732
840
|
if (i > 0) {
|
733
841
|
fbuffer_append_char(buffer, ',');
|
734
|
-
if (RB_UNLIKELY(state->array_nl))
|
842
|
+
if (RB_UNLIKELY(state->array_nl)) fbuffer_append_str(buffer, state->array_nl);
|
735
843
|
}
|
736
844
|
if (RB_UNLIKELY(state->indent)) {
|
737
845
|
for (j = 0; j < depth; j++) {
|
738
|
-
|
846
|
+
fbuffer_append_str(buffer, state->indent);
|
739
847
|
}
|
740
848
|
}
|
741
|
-
generate_json(buffer,
|
849
|
+
generate_json(buffer, data, state, RARRAY_AREF(obj, i));
|
742
850
|
}
|
743
851
|
state->depth = --depth;
|
744
852
|
if (RB_UNLIKELY(state->array_nl)) {
|
745
|
-
|
853
|
+
fbuffer_append_str(buffer, state->array_nl);
|
746
854
|
if (RB_UNLIKELY(state->indent)) {
|
747
855
|
for (j = 0; j < depth; j++) {
|
748
|
-
|
856
|
+
fbuffer_append_str(buffer, state->indent);
|
749
857
|
}
|
750
858
|
}
|
751
859
|
}
|
752
860
|
fbuffer_append_char(buffer, ']');
|
753
861
|
}
|
754
862
|
|
755
|
-
static int usascii_encindex, utf8_encindex, binary_encindex;
|
756
|
-
|
757
863
|
static inline int enc_utf8_compatible_p(int enc_idx)
|
758
864
|
{
|
759
865
|
if (enc_idx == usascii_encindex) return 1;
|
@@ -767,13 +873,14 @@ static inline VALUE ensure_valid_encoding(VALUE str)
|
|
767
873
|
VALUE utf8_string;
|
768
874
|
if (RB_UNLIKELY(!enc_utf8_compatible_p(encindex))) {
|
769
875
|
if (encindex == binary_encindex) {
|
770
|
-
// For historical reason, we silently reinterpret binary strings as UTF-8 if it would work.
|
771
|
-
// TODO: Deprecate in 2.8.0
|
772
|
-
// TODO: Remove in 3.0.0
|
773
876
|
utf8_string = rb_enc_associate_index(rb_str_dup(str), utf8_encindex);
|
774
877
|
switch (rb_enc_str_coderange(utf8_string)) {
|
775
878
|
case ENC_CODERANGE_7BIT:
|
879
|
+
return utf8_string;
|
776
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");
|
777
884
|
return utf8_string;
|
778
885
|
break;
|
779
886
|
}
|
@@ -784,7 +891,7 @@ static inline VALUE ensure_valid_encoding(VALUE str)
|
|
784
891
|
return str;
|
785
892
|
}
|
786
893
|
|
787
|
-
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)
|
788
895
|
{
|
789
896
|
obj = ensure_valid_encoding(obj);
|
790
897
|
|
@@ -808,43 +915,43 @@ static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_S
|
|
808
915
|
fbuffer_append_char(buffer, '"');
|
809
916
|
}
|
810
917
|
|
811
|
-
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)
|
812
919
|
{
|
813
920
|
fbuffer_append(buffer, "null", 4);
|
814
921
|
}
|
815
922
|
|
816
|
-
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)
|
817
924
|
{
|
818
925
|
fbuffer_append(buffer, "false", 5);
|
819
926
|
}
|
820
927
|
|
821
|
-
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)
|
822
929
|
{
|
823
930
|
fbuffer_append(buffer, "true", 4);
|
824
931
|
}
|
825
932
|
|
826
|
-
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)
|
827
934
|
{
|
828
935
|
fbuffer_append_long(buffer, FIX2LONG(obj));
|
829
936
|
}
|
830
937
|
|
831
|
-
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)
|
832
939
|
{
|
833
940
|
VALUE tmp = rb_funcall(obj, i_to_s, 0);
|
834
941
|
fbuffer_append_str(buffer, tmp);
|
835
942
|
}
|
836
943
|
|
837
944
|
#ifdef RUBY_INTEGER_UNIFICATION
|
838
|
-
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)
|
839
946
|
{
|
840
947
|
if (FIXNUM_P(obj))
|
841
|
-
generate_json_fixnum(buffer,
|
948
|
+
generate_json_fixnum(buffer, data, state, obj);
|
842
949
|
else
|
843
|
-
generate_json_bignum(buffer,
|
950
|
+
generate_json_bignum(buffer, data, state, obj);
|
844
951
|
}
|
845
952
|
#endif
|
846
953
|
|
847
|
-
static void generate_json_float(FBuffer *buffer,
|
954
|
+
static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
848
955
|
{
|
849
956
|
double value = RFLOAT_VALUE(obj);
|
850
957
|
char allow_nan = state->allow_nan;
|
@@ -859,20 +966,20 @@ static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
|
|
859
966
|
fbuffer_append_str(buffer, tmp);
|
860
967
|
}
|
861
968
|
|
862
|
-
static void generate_json(FBuffer *buffer,
|
969
|
+
static void generate_json(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
863
970
|
{
|
864
971
|
VALUE tmp;
|
865
972
|
if (obj == Qnil) {
|
866
|
-
generate_json_null(buffer,
|
973
|
+
generate_json_null(buffer, data, state, obj);
|
867
974
|
} else if (obj == Qfalse) {
|
868
|
-
generate_json_false(buffer,
|
975
|
+
generate_json_false(buffer, data, state, obj);
|
869
976
|
} else if (obj == Qtrue) {
|
870
|
-
generate_json_true(buffer,
|
977
|
+
generate_json_true(buffer, data, state, obj);
|
871
978
|
} else if (RB_SPECIAL_CONST_P(obj)) {
|
872
979
|
if (RB_FIXNUM_P(obj)) {
|
873
|
-
generate_json_fixnum(buffer,
|
980
|
+
generate_json_fixnum(buffer, data, state, obj);
|
874
981
|
} else if (RB_FLONUM_P(obj)) {
|
875
|
-
generate_json_float(buffer,
|
982
|
+
generate_json_float(buffer, data, state, obj);
|
876
983
|
} else {
|
877
984
|
goto general;
|
878
985
|
}
|
@@ -880,63 +987,46 @@ static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *s
|
|
880
987
|
VALUE klass = RBASIC_CLASS(obj);
|
881
988
|
switch (RB_BUILTIN_TYPE(obj)) {
|
882
989
|
case T_BIGNUM:
|
883
|
-
generate_json_bignum(buffer,
|
990
|
+
generate_json_bignum(buffer, data, state, obj);
|
884
991
|
break;
|
885
992
|
case T_HASH:
|
886
993
|
if (klass != rb_cHash) goto general;
|
887
|
-
generate_json_object(buffer,
|
994
|
+
generate_json_object(buffer, data, state, obj);
|
888
995
|
break;
|
889
996
|
case T_ARRAY:
|
890
997
|
if (klass != rb_cArray) goto general;
|
891
|
-
generate_json_array(buffer,
|
998
|
+
generate_json_array(buffer, data, state, obj);
|
892
999
|
break;
|
893
1000
|
case T_STRING:
|
894
1001
|
if (klass != rb_cString) goto general;
|
895
|
-
generate_json_string(buffer,
|
1002
|
+
generate_json_string(buffer, data, state, obj);
|
896
1003
|
break;
|
897
1004
|
case T_FLOAT:
|
898
1005
|
if (klass != rb_cFloat) goto general;
|
899
|
-
generate_json_float(buffer,
|
1006
|
+
generate_json_float(buffer, data, state, obj);
|
900
1007
|
break;
|
901
1008
|
default:
|
902
1009
|
general:
|
903
1010
|
if (state->strict) {
|
904
1011
|
rb_raise(eGeneratorError, "%"PRIsVALUE" not allowed in JSON", CLASS_OF(obj));
|
905
1012
|
} else if (rb_respond_to(obj, i_to_json)) {
|
906
|
-
tmp = rb_funcall(obj, i_to_json, 1,
|
1013
|
+
tmp = rb_funcall(obj, i_to_json, 1, vstate_get(data));
|
907
1014
|
Check_Type(tmp, T_STRING);
|
908
1015
|
fbuffer_append_str(buffer, tmp);
|
909
1016
|
} else {
|
910
1017
|
tmp = rb_funcall(obj, i_to_s, 0);
|
911
1018
|
Check_Type(tmp, T_STRING);
|
912
|
-
generate_json_string(buffer,
|
1019
|
+
generate_json_string(buffer, data, state, tmp);
|
913
1020
|
}
|
914
1021
|
}
|
915
1022
|
}
|
916
1023
|
}
|
917
1024
|
|
918
|
-
static FBuffer *cState_prepare_buffer(VALUE self)
|
919
|
-
{
|
920
|
-
FBuffer *buffer;
|
921
|
-
GET_STATE(self);
|
922
|
-
buffer = fbuffer_alloc(state->buffer_initial_length);
|
923
|
-
|
924
|
-
return buffer;
|
925
|
-
}
|
926
|
-
|
927
|
-
struct generate_json_data {
|
928
|
-
FBuffer *buffer;
|
929
|
-
VALUE vstate;
|
930
|
-
JSON_Generator_State *state;
|
931
|
-
VALUE obj;
|
932
|
-
void (*func)(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj);
|
933
|
-
};
|
934
|
-
|
935
1025
|
static VALUE generate_json_try(VALUE d)
|
936
1026
|
{
|
937
1027
|
struct generate_json_data *data = (struct generate_json_data *)d;
|
938
1028
|
|
939
|
-
data->func(data->buffer, data
|
1029
|
+
data->func(data->buffer, data, data->state, data->obj);
|
940
1030
|
|
941
1031
|
return Qnil;
|
942
1032
|
}
|
@@ -946,18 +1036,25 @@ static VALUE generate_json_rescue(VALUE d, VALUE exc)
|
|
946
1036
|
struct generate_json_data *data = (struct generate_json_data *)d;
|
947
1037
|
fbuffer_free(data->buffer);
|
948
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
|
+
|
949
1043
|
rb_exc_raise(exc);
|
950
1044
|
|
951
1045
|
return Qundef;
|
952
1046
|
}
|
953
1047
|
|
954
|
-
static VALUE cState_partial_generate(VALUE self, VALUE obj,
|
1048
|
+
static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func)
|
955
1049
|
{
|
956
|
-
FBuffer *buffer = cState_prepare_buffer(self);
|
957
1050
|
GET_STATE(self);
|
958
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
|
+
|
959
1056
|
struct generate_json_data data = {
|
960
|
-
.buffer = buffer,
|
1057
|
+
.buffer = &buffer,
|
961
1058
|
.vstate = self,
|
962
1059
|
.state = state,
|
963
1060
|
.obj = obj,
|
@@ -965,7 +1062,7 @@ static VALUE cState_partial_generate(VALUE self, VALUE obj, void (*func)(FBuffer
|
|
965
1062
|
};
|
966
1063
|
rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data);
|
967
1064
|
|
968
|
-
return fbuffer_to_s(buffer);
|
1065
|
+
return fbuffer_to_s(&buffer);
|
969
1066
|
}
|
970
1067
|
|
971
1068
|
/*
|
@@ -1005,11 +1102,11 @@ static VALUE cState_init_copy(VALUE obj, VALUE orig)
|
|
1005
1102
|
if (!objState) rb_raise(rb_eArgError, "unallocated JSON::State");
|
1006
1103
|
|
1007
1104
|
MEMCPY(objState, origState, JSON_Generator_State, 1);
|
1008
|
-
objState->indent =
|
1009
|
-
objState->space =
|
1010
|
-
objState->space_before =
|
1011
|
-
objState->object_nl =
|
1012
|
-
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;
|
1013
1110
|
return obj;
|
1014
1111
|
}
|
1015
1112
|
|
@@ -1039,7 +1136,18 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
|
|
1039
1136
|
static VALUE cState_indent(VALUE self)
|
1040
1137
|
{
|
1041
1138
|
GET_STATE(self);
|
1042
|
-
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;
|
1043
1151
|
}
|
1044
1152
|
|
1045
1153
|
/*
|
@@ -1049,21 +1157,8 @@ static VALUE cState_indent(VALUE self)
|
|
1049
1157
|
*/
|
1050
1158
|
static VALUE cState_indent_set(VALUE self, VALUE indent)
|
1051
1159
|
{
|
1052
|
-
unsigned long len;
|
1053
1160
|
GET_STATE(self);
|
1054
|
-
|
1055
|
-
len = RSTRING_LEN(indent);
|
1056
|
-
if (len == 0) {
|
1057
|
-
if (state->indent) {
|
1058
|
-
ruby_xfree(state->indent);
|
1059
|
-
state->indent = NULL;
|
1060
|
-
state->indent_len = 0;
|
1061
|
-
}
|
1062
|
-
} else {
|
1063
|
-
if (state->indent) ruby_xfree(state->indent);
|
1064
|
-
state->indent = fstrndup(RSTRING_PTR(indent), len);
|
1065
|
-
state->indent_len = len;
|
1066
|
-
}
|
1161
|
+
RB_OBJ_WRITE(self, &state->indent, string_config(indent));
|
1067
1162
|
return Qnil;
|
1068
1163
|
}
|
1069
1164
|
|
@@ -1076,7 +1171,7 @@ static VALUE cState_indent_set(VALUE self, VALUE indent)
|
|
1076
1171
|
static VALUE cState_space(VALUE self)
|
1077
1172
|
{
|
1078
1173
|
GET_STATE(self);
|
1079
|
-
return state->space ?
|
1174
|
+
return state->space ? state->space : rb_str_freeze(rb_utf8_str_new("", 0));
|
1080
1175
|
}
|
1081
1176
|
|
1082
1177
|
/*
|
@@ -1087,21 +1182,8 @@ static VALUE cState_space(VALUE self)
|
|
1087
1182
|
*/
|
1088
1183
|
static VALUE cState_space_set(VALUE self, VALUE space)
|
1089
1184
|
{
|
1090
|
-
unsigned long len;
|
1091
1185
|
GET_STATE(self);
|
1092
|
-
|
1093
|
-
len = RSTRING_LEN(space);
|
1094
|
-
if (len == 0) {
|
1095
|
-
if (state->space) {
|
1096
|
-
ruby_xfree(state->space);
|
1097
|
-
state->space = NULL;
|
1098
|
-
state->space_len = 0;
|
1099
|
-
}
|
1100
|
-
} else {
|
1101
|
-
if (state->space) ruby_xfree(state->space);
|
1102
|
-
state->space = fstrndup(RSTRING_PTR(space), len);
|
1103
|
-
state->space_len = len;
|
1104
|
-
}
|
1186
|
+
RB_OBJ_WRITE(self, &state->space, string_config(space));
|
1105
1187
|
return Qnil;
|
1106
1188
|
}
|
1107
1189
|
|
@@ -1113,7 +1195,7 @@ static VALUE cState_space_set(VALUE self, VALUE space)
|
|
1113
1195
|
static VALUE cState_space_before(VALUE self)
|
1114
1196
|
{
|
1115
1197
|
GET_STATE(self);
|
1116
|
-
return state->space_before ?
|
1198
|
+
return state->space_before ? state->space_before : rb_str_freeze(rb_utf8_str_new("", 0));
|
1117
1199
|
}
|
1118
1200
|
|
1119
1201
|
/*
|
@@ -1123,21 +1205,8 @@ static VALUE cState_space_before(VALUE self)
|
|
1123
1205
|
*/
|
1124
1206
|
static VALUE cState_space_before_set(VALUE self, VALUE space_before)
|
1125
1207
|
{
|
1126
|
-
unsigned long len;
|
1127
1208
|
GET_STATE(self);
|
1128
|
-
|
1129
|
-
len = RSTRING_LEN(space_before);
|
1130
|
-
if (len == 0) {
|
1131
|
-
if (state->space_before) {
|
1132
|
-
ruby_xfree(state->space_before);
|
1133
|
-
state->space_before = NULL;
|
1134
|
-
state->space_before_len = 0;
|
1135
|
-
}
|
1136
|
-
} else {
|
1137
|
-
if (state->space_before) ruby_xfree(state->space_before);
|
1138
|
-
state->space_before = fstrndup(RSTRING_PTR(space_before), len);
|
1139
|
-
state->space_before_len = len;
|
1140
|
-
}
|
1209
|
+
RB_OBJ_WRITE(self, &state->space_before, string_config(space_before));
|
1141
1210
|
return Qnil;
|
1142
1211
|
}
|
1143
1212
|
|
@@ -1150,7 +1219,7 @@ static VALUE cState_space_before_set(VALUE self, VALUE space_before)
|
|
1150
1219
|
static VALUE cState_object_nl(VALUE self)
|
1151
1220
|
{
|
1152
1221
|
GET_STATE(self);
|
1153
|
-
return state->object_nl ?
|
1222
|
+
return state->object_nl ? state->object_nl : rb_str_freeze(rb_utf8_str_new("", 0));
|
1154
1223
|
}
|
1155
1224
|
|
1156
1225
|
/*
|
@@ -1161,20 +1230,8 @@ static VALUE cState_object_nl(VALUE self)
|
|
1161
1230
|
*/
|
1162
1231
|
static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
|
1163
1232
|
{
|
1164
|
-
unsigned long len;
|
1165
1233
|
GET_STATE(self);
|
1166
|
-
|
1167
|
-
len = RSTRING_LEN(object_nl);
|
1168
|
-
if (len == 0) {
|
1169
|
-
if (state->object_nl) {
|
1170
|
-
ruby_xfree(state->object_nl);
|
1171
|
-
state->object_nl = NULL;
|
1172
|
-
}
|
1173
|
-
} else {
|
1174
|
-
if (state->object_nl) ruby_xfree(state->object_nl);
|
1175
|
-
state->object_nl = fstrndup(RSTRING_PTR(object_nl), len);
|
1176
|
-
state->object_nl_len = len;
|
1177
|
-
}
|
1234
|
+
RB_OBJ_WRITE(self, &state->object_nl, string_config(object_nl));
|
1178
1235
|
return Qnil;
|
1179
1236
|
}
|
1180
1237
|
|
@@ -1186,7 +1243,7 @@ static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
|
|
1186
1243
|
static VALUE cState_array_nl(VALUE self)
|
1187
1244
|
{
|
1188
1245
|
GET_STATE(self);
|
1189
|
-
return state->array_nl ?
|
1246
|
+
return state->array_nl ? state->array_nl : rb_str_freeze(rb_utf8_str_new("", 0));
|
1190
1247
|
}
|
1191
1248
|
|
1192
1249
|
/*
|
@@ -1196,20 +1253,8 @@ static VALUE cState_array_nl(VALUE self)
|
|
1196
1253
|
*/
|
1197
1254
|
static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
|
1198
1255
|
{
|
1199
|
-
unsigned long len;
|
1200
1256
|
GET_STATE(self);
|
1201
|
-
|
1202
|
-
len = RSTRING_LEN(array_nl);
|
1203
|
-
if (len == 0) {
|
1204
|
-
if (state->array_nl) {
|
1205
|
-
ruby_xfree(state->array_nl);
|
1206
|
-
state->array_nl = NULL;
|
1207
|
-
}
|
1208
|
-
} else {
|
1209
|
-
if (state->array_nl) ruby_xfree(state->array_nl);
|
1210
|
-
state->array_nl = fstrndup(RSTRING_PTR(array_nl), len);
|
1211
|
-
state->array_nl_len = len;
|
1212
|
-
}
|
1257
|
+
RB_OBJ_WRITE(self, &state->array_nl, string_config(array_nl));
|
1213
1258
|
return Qnil;
|
1214
1259
|
}
|
1215
1260
|
|
@@ -1238,6 +1283,11 @@ static VALUE cState_max_nesting(VALUE self)
|
|
1238
1283
|
return LONG2FIX(state->max_nesting);
|
1239
1284
|
}
|
1240
1285
|
|
1286
|
+
static long long_config(VALUE num)
|
1287
|
+
{
|
1288
|
+
return RTEST(num) ? FIX2LONG(num) : 0;
|
1289
|
+
}
|
1290
|
+
|
1241
1291
|
/*
|
1242
1292
|
* call-seq: max_nesting=(depth)
|
1243
1293
|
*
|
@@ -1247,8 +1297,7 @@ static VALUE cState_max_nesting(VALUE self)
|
|
1247
1297
|
static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
|
1248
1298
|
{
|
1249
1299
|
GET_STATE(self);
|
1250
|
-
|
1251
|
-
state->max_nesting = FIX2LONG(depth);
|
1300
|
+
state->max_nesting = long_config(depth);
|
1252
1301
|
return Qnil;
|
1253
1302
|
}
|
1254
1303
|
|
@@ -1376,8 +1425,7 @@ static VALUE cState_depth(VALUE self)
|
|
1376
1425
|
static VALUE cState_depth_set(VALUE self, VALUE depth)
|
1377
1426
|
{
|
1378
1427
|
GET_STATE(self);
|
1379
|
-
|
1380
|
-
state->depth = FIX2LONG(depth);
|
1428
|
+
state->depth = long_config(depth);
|
1381
1429
|
return Qnil;
|
1382
1430
|
}
|
1383
1431
|
|
@@ -1392,6 +1440,15 @@ static VALUE cState_buffer_initial_length(VALUE self)
|
|
1392
1440
|
return LONG2FIX(state->buffer_initial_length);
|
1393
1441
|
}
|
1394
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
|
+
|
1395
1452
|
/*
|
1396
1453
|
* call-seq: buffer_initial_length=(length)
|
1397
1454
|
*
|
@@ -1400,16 +1457,73 @@ static VALUE cState_buffer_initial_length(VALUE self)
|
|
1400
1457
|
*/
|
1401
1458
|
static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_length)
|
1402
1459
|
{
|
1403
|
-
long initial_length;
|
1404
1460
|
GET_STATE(self);
|
1405
|
-
|
1406
|
-
initial_length = FIX2LONG(buffer_initial_length);
|
1407
|
-
if (initial_length > 0) {
|
1408
|
-
state->buffer_initial_length = initial_length;
|
1409
|
-
}
|
1461
|
+
buffer_initial_length_set(state, buffer_initial_length);
|
1410
1462
|
return Qnil;
|
1411
1463
|
}
|
1412
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
|
+
|
1413
1527
|
/*
|
1414
1528
|
*
|
1415
1529
|
*/
|
@@ -1436,6 +1550,7 @@ void Init_generator(void)
|
|
1436
1550
|
rb_define_singleton_method(cState, "from_state", cState_from_state_s, 1);
|
1437
1551
|
rb_define_method(cState, "initialize", cState_initialize, -1);
|
1438
1552
|
rb_define_alias(cState, "initialize", "initialize"); // avoid method redefinition warnings
|
1553
|
+
rb_define_private_method(cState, "_configure", cState_configure, 1);
|
1439
1554
|
|
1440
1555
|
rb_define_method(cState, "initialize_copy", cState_init_copy, 1);
|
1441
1556
|
rb_define_method(cState, "indent", cState_indent, 0);
|
@@ -1470,6 +1585,8 @@ void Init_generator(void)
|
|
1470
1585
|
rb_define_method(cState, "buffer_initial_length=", cState_buffer_initial_length_set, 1);
|
1471
1586
|
rb_define_method(cState, "generate", cState_generate, 1);
|
1472
1587
|
|
1588
|
+
rb_define_singleton_method(cState, "generate", cState_m_generate, 2);
|
1589
|
+
|
1473
1590
|
VALUE mGeneratorMethods = rb_define_module_under(mGenerator, "GeneratorMethods");
|
1474
1591
|
|
1475
1592
|
VALUE mObject = rb_define_module_under(mGeneratorMethods, "Object");
|
@@ -1524,6 +1641,20 @@ void Init_generator(void)
|
|
1524
1641
|
i_extend = rb_intern("extend");
|
1525
1642
|
i_encode = rb_intern("encode");
|
1526
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
|
+
|
1527
1658
|
usascii_encindex = rb_usascii_encindex();
|
1528
1659
|
utf8_encindex = rb_utf8_encindex();
|
1529
1660
|
binary_encindex = rb_ascii8bit_encindex();
|