json 2.7.5 → 2.8.2
Sign up to get free protection for your applications and to get access to all the features.
- 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();
|