json 2.7.6 → 2.8.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES.md +15 -0
- data/README.md +8 -77
- data/ext/json/ext/fbuffer/fbuffer.h +85 -51
- data/ext/json/ext/generator/generator.c +327 -204
- 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 -59
- data/lib/json/ext/generator/state.rb +1 -31
- data/lib/json/ext.rb +2 -4
- data/lib/json/{pure → truffle_ruby}/generator.rb +150 -128
- 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,20 +734,21 @@ 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
|
|
@@ -683,50 +770,56 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
|
|
683
770
|
}
|
684
771
|
|
685
772
|
if (RB_LIKELY(RBASIC_CLASS(key_to_s) == rb_cString)) {
|
686
|
-
generate_json_string(buffer,
|
773
|
+
generate_json_string(buffer, data, state, key_to_s);
|
687
774
|
} else {
|
688
|
-
generate_json(buffer,
|
775
|
+
generate_json(buffer, data, state, key_to_s);
|
689
776
|
}
|
690
|
-
if (RB_UNLIKELY(state->space_before))
|
777
|
+
if (RB_UNLIKELY(state->space_before)) fbuffer_append_str(buffer, state->space_before);
|
691
778
|
fbuffer_append_char(buffer, ':');
|
692
|
-
if (RB_UNLIKELY(state->space))
|
693
|
-
generate_json(buffer,
|
779
|
+
if (RB_UNLIKELY(state->space)) fbuffer_append_str(buffer, state->space);
|
780
|
+
generate_json(buffer, data, state, val);
|
694
781
|
|
695
782
|
arg->iter++;
|
696
783
|
return ST_CONTINUE;
|
697
784
|
}
|
698
785
|
|
699
|
-
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)
|
700
787
|
{
|
701
788
|
long max_nesting = state->max_nesting;
|
702
789
|
long depth = ++state->depth;
|
703
790
|
int j;
|
704
|
-
struct hash_foreach_arg arg;
|
705
791
|
|
706
792
|
if (max_nesting != 0 && depth > max_nesting) {
|
707
793
|
rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
|
708
794
|
}
|
795
|
+
|
796
|
+
if (RHASH_SIZE(obj) == 0) {
|
797
|
+
fbuffer_append(buffer, "{}", 2);
|
798
|
+
--state->depth;
|
799
|
+
return;
|
800
|
+
}
|
801
|
+
|
709
802
|
fbuffer_append_char(buffer, '{');
|
710
803
|
|
711
|
-
arg
|
712
|
-
|
713
|
-
|
714
|
-
|
804
|
+
struct hash_foreach_arg arg = {
|
805
|
+
.data = data,
|
806
|
+
.iter = 0,
|
807
|
+
};
|
715
808
|
rb_hash_foreach(obj, json_object_i, (VALUE)&arg);
|
716
809
|
|
717
810
|
depth = --state->depth;
|
718
811
|
if (RB_UNLIKELY(state->object_nl)) {
|
719
|
-
|
812
|
+
fbuffer_append_str(buffer, state->object_nl);
|
720
813
|
if (RB_UNLIKELY(state->indent)) {
|
721
814
|
for (j = 0; j < depth; j++) {
|
722
|
-
|
815
|
+
fbuffer_append_str(buffer, state->indent);
|
723
816
|
}
|
724
817
|
}
|
725
818
|
}
|
726
819
|
fbuffer_append_char(buffer, '}');
|
727
820
|
}
|
728
821
|
|
729
|
-
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)
|
730
823
|
{
|
731
824
|
long max_nesting = state->max_nesting;
|
732
825
|
long depth = ++state->depth;
|
@@ -734,34 +827,39 @@ static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
|
|
734
827
|
if (max_nesting != 0 && depth > max_nesting) {
|
735
828
|
rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
|
736
829
|
}
|
830
|
+
|
831
|
+
if (RARRAY_LEN(obj) == 0) {
|
832
|
+
fbuffer_append(buffer, "[]", 2);
|
833
|
+
--state->depth;
|
834
|
+
return;
|
835
|
+
}
|
836
|
+
|
737
837
|
fbuffer_append_char(buffer, '[');
|
738
|
-
if (RB_UNLIKELY(state->array_nl))
|
838
|
+
if (RB_UNLIKELY(state->array_nl)) fbuffer_append_str(buffer, state->array_nl);
|
739
839
|
for(i = 0; i < RARRAY_LEN(obj); i++) {
|
740
840
|
if (i > 0) {
|
741
841
|
fbuffer_append_char(buffer, ',');
|
742
|
-
if (RB_UNLIKELY(state->array_nl))
|
842
|
+
if (RB_UNLIKELY(state->array_nl)) fbuffer_append_str(buffer, state->array_nl);
|
743
843
|
}
|
744
844
|
if (RB_UNLIKELY(state->indent)) {
|
745
845
|
for (j = 0; j < depth; j++) {
|
746
|
-
|
846
|
+
fbuffer_append_str(buffer, state->indent);
|
747
847
|
}
|
748
848
|
}
|
749
|
-
generate_json(buffer,
|
849
|
+
generate_json(buffer, data, state, RARRAY_AREF(obj, i));
|
750
850
|
}
|
751
851
|
state->depth = --depth;
|
752
852
|
if (RB_UNLIKELY(state->array_nl)) {
|
753
|
-
|
853
|
+
fbuffer_append_str(buffer, state->array_nl);
|
754
854
|
if (RB_UNLIKELY(state->indent)) {
|
755
855
|
for (j = 0; j < depth; j++) {
|
756
|
-
|
856
|
+
fbuffer_append_str(buffer, state->indent);
|
757
857
|
}
|
758
858
|
}
|
759
859
|
}
|
760
860
|
fbuffer_append_char(buffer, ']');
|
761
861
|
}
|
762
862
|
|
763
|
-
static int usascii_encindex, utf8_encindex, binary_encindex;
|
764
|
-
|
765
863
|
static inline int enc_utf8_compatible_p(int enc_idx)
|
766
864
|
{
|
767
865
|
if (enc_idx == usascii_encindex) return 1;
|
@@ -775,13 +873,14 @@ static inline VALUE ensure_valid_encoding(VALUE str)
|
|
775
873
|
VALUE utf8_string;
|
776
874
|
if (RB_UNLIKELY(!enc_utf8_compatible_p(encindex))) {
|
777
875
|
if (encindex == binary_encindex) {
|
778
|
-
// For historical reason, we silently reinterpret binary strings as UTF-8 if it would work.
|
779
|
-
// TODO: Deprecate in 2.8.0
|
780
|
-
// TODO: Remove in 3.0.0
|
781
876
|
utf8_string = rb_enc_associate_index(rb_str_dup(str), utf8_encindex);
|
782
877
|
switch (rb_enc_str_coderange(utf8_string)) {
|
783
878
|
case ENC_CODERANGE_7BIT:
|
879
|
+
return utf8_string;
|
784
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");
|
785
884
|
return utf8_string;
|
786
885
|
break;
|
787
886
|
}
|
@@ -792,7 +891,7 @@ static inline VALUE ensure_valid_encoding(VALUE str)
|
|
792
891
|
return str;
|
793
892
|
}
|
794
893
|
|
795
|
-
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)
|
796
895
|
{
|
797
896
|
obj = ensure_valid_encoding(obj);
|
798
897
|
|
@@ -816,43 +915,43 @@ static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_S
|
|
816
915
|
fbuffer_append_char(buffer, '"');
|
817
916
|
}
|
818
917
|
|
819
|
-
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)
|
820
919
|
{
|
821
920
|
fbuffer_append(buffer, "null", 4);
|
822
921
|
}
|
823
922
|
|
824
|
-
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)
|
825
924
|
{
|
826
925
|
fbuffer_append(buffer, "false", 5);
|
827
926
|
}
|
828
927
|
|
829
|
-
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)
|
830
929
|
{
|
831
930
|
fbuffer_append(buffer, "true", 4);
|
832
931
|
}
|
833
932
|
|
834
|
-
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)
|
835
934
|
{
|
836
935
|
fbuffer_append_long(buffer, FIX2LONG(obj));
|
837
936
|
}
|
838
937
|
|
839
|
-
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)
|
840
939
|
{
|
841
940
|
VALUE tmp = rb_funcall(obj, i_to_s, 0);
|
842
941
|
fbuffer_append_str(buffer, tmp);
|
843
942
|
}
|
844
943
|
|
845
944
|
#ifdef RUBY_INTEGER_UNIFICATION
|
846
|
-
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)
|
847
946
|
{
|
848
947
|
if (FIXNUM_P(obj))
|
849
|
-
generate_json_fixnum(buffer,
|
948
|
+
generate_json_fixnum(buffer, data, state, obj);
|
850
949
|
else
|
851
|
-
generate_json_bignum(buffer,
|
950
|
+
generate_json_bignum(buffer, data, state, obj);
|
852
951
|
}
|
853
952
|
#endif
|
854
953
|
|
855
|
-
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)
|
856
955
|
{
|
857
956
|
double value = RFLOAT_VALUE(obj);
|
858
957
|
char allow_nan = state->allow_nan;
|
@@ -867,20 +966,20 @@ static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
|
|
867
966
|
fbuffer_append_str(buffer, tmp);
|
868
967
|
}
|
869
968
|
|
870
|
-
static void generate_json(FBuffer *buffer,
|
969
|
+
static void generate_json(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
871
970
|
{
|
872
971
|
VALUE tmp;
|
873
972
|
if (obj == Qnil) {
|
874
|
-
generate_json_null(buffer,
|
973
|
+
generate_json_null(buffer, data, state, obj);
|
875
974
|
} else if (obj == Qfalse) {
|
876
|
-
generate_json_false(buffer,
|
975
|
+
generate_json_false(buffer, data, state, obj);
|
877
976
|
} else if (obj == Qtrue) {
|
878
|
-
generate_json_true(buffer,
|
977
|
+
generate_json_true(buffer, data, state, obj);
|
879
978
|
} else if (RB_SPECIAL_CONST_P(obj)) {
|
880
979
|
if (RB_FIXNUM_P(obj)) {
|
881
|
-
generate_json_fixnum(buffer,
|
980
|
+
generate_json_fixnum(buffer, data, state, obj);
|
882
981
|
} else if (RB_FLONUM_P(obj)) {
|
883
|
-
generate_json_float(buffer,
|
982
|
+
generate_json_float(buffer, data, state, obj);
|
884
983
|
} else {
|
885
984
|
goto general;
|
886
985
|
}
|
@@ -888,63 +987,46 @@ static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *s
|
|
888
987
|
VALUE klass = RBASIC_CLASS(obj);
|
889
988
|
switch (RB_BUILTIN_TYPE(obj)) {
|
890
989
|
case T_BIGNUM:
|
891
|
-
generate_json_bignum(buffer,
|
990
|
+
generate_json_bignum(buffer, data, state, obj);
|
892
991
|
break;
|
893
992
|
case T_HASH:
|
894
993
|
if (klass != rb_cHash) goto general;
|
895
|
-
generate_json_object(buffer,
|
994
|
+
generate_json_object(buffer, data, state, obj);
|
896
995
|
break;
|
897
996
|
case T_ARRAY:
|
898
997
|
if (klass != rb_cArray) goto general;
|
899
|
-
generate_json_array(buffer,
|
998
|
+
generate_json_array(buffer, data, state, obj);
|
900
999
|
break;
|
901
1000
|
case T_STRING:
|
902
1001
|
if (klass != rb_cString) goto general;
|
903
|
-
generate_json_string(buffer,
|
1002
|
+
generate_json_string(buffer, data, state, obj);
|
904
1003
|
break;
|
905
1004
|
case T_FLOAT:
|
906
1005
|
if (klass != rb_cFloat) goto general;
|
907
|
-
generate_json_float(buffer,
|
1006
|
+
generate_json_float(buffer, data, state, obj);
|
908
1007
|
break;
|
909
1008
|
default:
|
910
1009
|
general:
|
911
1010
|
if (state->strict) {
|
912
1011
|
rb_raise(eGeneratorError, "%"PRIsVALUE" not allowed in JSON", CLASS_OF(obj));
|
913
1012
|
} else if (rb_respond_to(obj, i_to_json)) {
|
914
|
-
tmp = rb_funcall(obj, i_to_json, 1,
|
1013
|
+
tmp = rb_funcall(obj, i_to_json, 1, vstate_get(data));
|
915
1014
|
Check_Type(tmp, T_STRING);
|
916
1015
|
fbuffer_append_str(buffer, tmp);
|
917
1016
|
} else {
|
918
1017
|
tmp = rb_funcall(obj, i_to_s, 0);
|
919
1018
|
Check_Type(tmp, T_STRING);
|
920
|
-
generate_json_string(buffer,
|
1019
|
+
generate_json_string(buffer, data, state, tmp);
|
921
1020
|
}
|
922
1021
|
}
|
923
1022
|
}
|
924
1023
|
}
|
925
1024
|
|
926
|
-
static FBuffer *cState_prepare_buffer(VALUE self)
|
927
|
-
{
|
928
|
-
FBuffer *buffer;
|
929
|
-
GET_STATE(self);
|
930
|
-
buffer = fbuffer_alloc(state->buffer_initial_length);
|
931
|
-
|
932
|
-
return buffer;
|
933
|
-
}
|
934
|
-
|
935
|
-
struct generate_json_data {
|
936
|
-
FBuffer *buffer;
|
937
|
-
VALUE vstate;
|
938
|
-
JSON_Generator_State *state;
|
939
|
-
VALUE obj;
|
940
|
-
void (*func)(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj);
|
941
|
-
};
|
942
|
-
|
943
1025
|
static VALUE generate_json_try(VALUE d)
|
944
1026
|
{
|
945
1027
|
struct generate_json_data *data = (struct generate_json_data *)d;
|
946
1028
|
|
947
|
-
data->func(data->buffer, data
|
1029
|
+
data->func(data->buffer, data, data->state, data->obj);
|
948
1030
|
|
949
1031
|
return Qnil;
|
950
1032
|
}
|
@@ -954,18 +1036,25 @@ static VALUE generate_json_rescue(VALUE d, VALUE exc)
|
|
954
1036
|
struct generate_json_data *data = (struct generate_json_data *)d;
|
955
1037
|
fbuffer_free(data->buffer);
|
956
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
|
+
|
957
1043
|
rb_exc_raise(exc);
|
958
1044
|
|
959
1045
|
return Qundef;
|
960
1046
|
}
|
961
1047
|
|
962
|
-
static VALUE cState_partial_generate(VALUE self, VALUE obj,
|
1048
|
+
static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func)
|
963
1049
|
{
|
964
|
-
FBuffer *buffer = cState_prepare_buffer(self);
|
965
1050
|
GET_STATE(self);
|
966
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
|
+
|
967
1056
|
struct generate_json_data data = {
|
968
|
-
.buffer = buffer,
|
1057
|
+
.buffer = &buffer,
|
969
1058
|
.vstate = self,
|
970
1059
|
.state = state,
|
971
1060
|
.obj = obj,
|
@@ -973,7 +1062,7 @@ static VALUE cState_partial_generate(VALUE self, VALUE obj, void (*func)(FBuffer
|
|
973
1062
|
};
|
974
1063
|
rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data);
|
975
1064
|
|
976
|
-
return fbuffer_to_s(buffer);
|
1065
|
+
return fbuffer_to_s(&buffer);
|
977
1066
|
}
|
978
1067
|
|
979
1068
|
/*
|
@@ -1013,11 +1102,11 @@ static VALUE cState_init_copy(VALUE obj, VALUE orig)
|
|
1013
1102
|
if (!objState) rb_raise(rb_eArgError, "unallocated JSON::State");
|
1014
1103
|
|
1015
1104
|
MEMCPY(objState, origState, JSON_Generator_State, 1);
|
1016
|
-
objState->indent =
|
1017
|
-
objState->space =
|
1018
|
-
objState->space_before =
|
1019
|
-
objState->object_nl =
|
1020
|
-
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;
|
1021
1110
|
return obj;
|
1022
1111
|
}
|
1023
1112
|
|
@@ -1047,7 +1136,18 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
|
|
1047
1136
|
static VALUE cState_indent(VALUE self)
|
1048
1137
|
{
|
1049
1138
|
GET_STATE(self);
|
1050
|
-
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;
|
1051
1151
|
}
|
1052
1152
|
|
1053
1153
|
/*
|
@@ -1057,21 +1157,8 @@ static VALUE cState_indent(VALUE self)
|
|
1057
1157
|
*/
|
1058
1158
|
static VALUE cState_indent_set(VALUE self, VALUE indent)
|
1059
1159
|
{
|
1060
|
-
unsigned long len;
|
1061
1160
|
GET_STATE(self);
|
1062
|
-
|
1063
|
-
len = RSTRING_LEN(indent);
|
1064
|
-
if (len == 0) {
|
1065
|
-
if (state->indent) {
|
1066
|
-
ruby_xfree(state->indent);
|
1067
|
-
state->indent = NULL;
|
1068
|
-
state->indent_len = 0;
|
1069
|
-
}
|
1070
|
-
} else {
|
1071
|
-
if (state->indent) ruby_xfree(state->indent);
|
1072
|
-
state->indent = fstrndup(RSTRING_PTR(indent), len);
|
1073
|
-
state->indent_len = len;
|
1074
|
-
}
|
1161
|
+
RB_OBJ_WRITE(self, &state->indent, string_config(indent));
|
1075
1162
|
return Qnil;
|
1076
1163
|
}
|
1077
1164
|
|
@@ -1084,7 +1171,7 @@ static VALUE cState_indent_set(VALUE self, VALUE indent)
|
|
1084
1171
|
static VALUE cState_space(VALUE self)
|
1085
1172
|
{
|
1086
1173
|
GET_STATE(self);
|
1087
|
-
return state->space ?
|
1174
|
+
return state->space ? state->space : rb_str_freeze(rb_utf8_str_new("", 0));
|
1088
1175
|
}
|
1089
1176
|
|
1090
1177
|
/*
|
@@ -1095,21 +1182,8 @@ static VALUE cState_space(VALUE self)
|
|
1095
1182
|
*/
|
1096
1183
|
static VALUE cState_space_set(VALUE self, VALUE space)
|
1097
1184
|
{
|
1098
|
-
unsigned long len;
|
1099
1185
|
GET_STATE(self);
|
1100
|
-
|
1101
|
-
len = RSTRING_LEN(space);
|
1102
|
-
if (len == 0) {
|
1103
|
-
if (state->space) {
|
1104
|
-
ruby_xfree(state->space);
|
1105
|
-
state->space = NULL;
|
1106
|
-
state->space_len = 0;
|
1107
|
-
}
|
1108
|
-
} else {
|
1109
|
-
if (state->space) ruby_xfree(state->space);
|
1110
|
-
state->space = fstrndup(RSTRING_PTR(space), len);
|
1111
|
-
state->space_len = len;
|
1112
|
-
}
|
1186
|
+
RB_OBJ_WRITE(self, &state->space, string_config(space));
|
1113
1187
|
return Qnil;
|
1114
1188
|
}
|
1115
1189
|
|
@@ -1121,7 +1195,7 @@ static VALUE cState_space_set(VALUE self, VALUE space)
|
|
1121
1195
|
static VALUE cState_space_before(VALUE self)
|
1122
1196
|
{
|
1123
1197
|
GET_STATE(self);
|
1124
|
-
return state->space_before ?
|
1198
|
+
return state->space_before ? state->space_before : rb_str_freeze(rb_utf8_str_new("", 0));
|
1125
1199
|
}
|
1126
1200
|
|
1127
1201
|
/*
|
@@ -1131,21 +1205,8 @@ static VALUE cState_space_before(VALUE self)
|
|
1131
1205
|
*/
|
1132
1206
|
static VALUE cState_space_before_set(VALUE self, VALUE space_before)
|
1133
1207
|
{
|
1134
|
-
unsigned long len;
|
1135
1208
|
GET_STATE(self);
|
1136
|
-
|
1137
|
-
len = RSTRING_LEN(space_before);
|
1138
|
-
if (len == 0) {
|
1139
|
-
if (state->space_before) {
|
1140
|
-
ruby_xfree(state->space_before);
|
1141
|
-
state->space_before = NULL;
|
1142
|
-
state->space_before_len = 0;
|
1143
|
-
}
|
1144
|
-
} else {
|
1145
|
-
if (state->space_before) ruby_xfree(state->space_before);
|
1146
|
-
state->space_before = fstrndup(RSTRING_PTR(space_before), len);
|
1147
|
-
state->space_before_len = len;
|
1148
|
-
}
|
1209
|
+
RB_OBJ_WRITE(self, &state->space_before, string_config(space_before));
|
1149
1210
|
return Qnil;
|
1150
1211
|
}
|
1151
1212
|
|
@@ -1158,7 +1219,7 @@ static VALUE cState_space_before_set(VALUE self, VALUE space_before)
|
|
1158
1219
|
static VALUE cState_object_nl(VALUE self)
|
1159
1220
|
{
|
1160
1221
|
GET_STATE(self);
|
1161
|
-
return state->object_nl ?
|
1222
|
+
return state->object_nl ? state->object_nl : rb_str_freeze(rb_utf8_str_new("", 0));
|
1162
1223
|
}
|
1163
1224
|
|
1164
1225
|
/*
|
@@ -1169,20 +1230,8 @@ static VALUE cState_object_nl(VALUE self)
|
|
1169
1230
|
*/
|
1170
1231
|
static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
|
1171
1232
|
{
|
1172
|
-
unsigned long len;
|
1173
1233
|
GET_STATE(self);
|
1174
|
-
|
1175
|
-
len = RSTRING_LEN(object_nl);
|
1176
|
-
if (len == 0) {
|
1177
|
-
if (state->object_nl) {
|
1178
|
-
ruby_xfree(state->object_nl);
|
1179
|
-
state->object_nl = NULL;
|
1180
|
-
}
|
1181
|
-
} else {
|
1182
|
-
if (state->object_nl) ruby_xfree(state->object_nl);
|
1183
|
-
state->object_nl = fstrndup(RSTRING_PTR(object_nl), len);
|
1184
|
-
state->object_nl_len = len;
|
1185
|
-
}
|
1234
|
+
RB_OBJ_WRITE(self, &state->object_nl, string_config(object_nl));
|
1186
1235
|
return Qnil;
|
1187
1236
|
}
|
1188
1237
|
|
@@ -1194,7 +1243,7 @@ static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
|
|
1194
1243
|
static VALUE cState_array_nl(VALUE self)
|
1195
1244
|
{
|
1196
1245
|
GET_STATE(self);
|
1197
|
-
return state->array_nl ?
|
1246
|
+
return state->array_nl ? state->array_nl : rb_str_freeze(rb_utf8_str_new("", 0));
|
1198
1247
|
}
|
1199
1248
|
|
1200
1249
|
/*
|
@@ -1204,20 +1253,8 @@ static VALUE cState_array_nl(VALUE self)
|
|
1204
1253
|
*/
|
1205
1254
|
static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
|
1206
1255
|
{
|
1207
|
-
unsigned long len;
|
1208
1256
|
GET_STATE(self);
|
1209
|
-
|
1210
|
-
len = RSTRING_LEN(array_nl);
|
1211
|
-
if (len == 0) {
|
1212
|
-
if (state->array_nl) {
|
1213
|
-
ruby_xfree(state->array_nl);
|
1214
|
-
state->array_nl = NULL;
|
1215
|
-
}
|
1216
|
-
} else {
|
1217
|
-
if (state->array_nl) ruby_xfree(state->array_nl);
|
1218
|
-
state->array_nl = fstrndup(RSTRING_PTR(array_nl), len);
|
1219
|
-
state->array_nl_len = len;
|
1220
|
-
}
|
1257
|
+
RB_OBJ_WRITE(self, &state->array_nl, string_config(array_nl));
|
1221
1258
|
return Qnil;
|
1222
1259
|
}
|
1223
1260
|
|
@@ -1246,6 +1283,11 @@ static VALUE cState_max_nesting(VALUE self)
|
|
1246
1283
|
return LONG2FIX(state->max_nesting);
|
1247
1284
|
}
|
1248
1285
|
|
1286
|
+
static long long_config(VALUE num)
|
1287
|
+
{
|
1288
|
+
return RTEST(num) ? FIX2LONG(num) : 0;
|
1289
|
+
}
|
1290
|
+
|
1249
1291
|
/*
|
1250
1292
|
* call-seq: max_nesting=(depth)
|
1251
1293
|
*
|
@@ -1255,8 +1297,7 @@ static VALUE cState_max_nesting(VALUE self)
|
|
1255
1297
|
static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
|
1256
1298
|
{
|
1257
1299
|
GET_STATE(self);
|
1258
|
-
|
1259
|
-
state->max_nesting = FIX2LONG(depth);
|
1300
|
+
state->max_nesting = long_config(depth);
|
1260
1301
|
return Qnil;
|
1261
1302
|
}
|
1262
1303
|
|
@@ -1384,8 +1425,7 @@ static VALUE cState_depth(VALUE self)
|
|
1384
1425
|
static VALUE cState_depth_set(VALUE self, VALUE depth)
|
1385
1426
|
{
|
1386
1427
|
GET_STATE(self);
|
1387
|
-
|
1388
|
-
state->depth = FIX2LONG(depth);
|
1428
|
+
state->depth = long_config(depth);
|
1389
1429
|
return Qnil;
|
1390
1430
|
}
|
1391
1431
|
|
@@ -1400,6 +1440,15 @@ static VALUE cState_buffer_initial_length(VALUE self)
|
|
1400
1440
|
return LONG2FIX(state->buffer_initial_length);
|
1401
1441
|
}
|
1402
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
|
+
|
1403
1452
|
/*
|
1404
1453
|
* call-seq: buffer_initial_length=(length)
|
1405
1454
|
*
|
@@ -1408,16 +1457,73 @@ static VALUE cState_buffer_initial_length(VALUE self)
|
|
1408
1457
|
*/
|
1409
1458
|
static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_length)
|
1410
1459
|
{
|
1411
|
-
long initial_length;
|
1412
1460
|
GET_STATE(self);
|
1413
|
-
|
1414
|
-
initial_length = FIX2LONG(buffer_initial_length);
|
1415
|
-
if (initial_length > 0) {
|
1416
|
-
state->buffer_initial_length = initial_length;
|
1417
|
-
}
|
1461
|
+
buffer_initial_length_set(state, buffer_initial_length);
|
1418
1462
|
return Qnil;
|
1419
1463
|
}
|
1420
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
|
+
|
1421
1527
|
/*
|
1422
1528
|
*
|
1423
1529
|
*/
|
@@ -1444,6 +1550,7 @@ void Init_generator(void)
|
|
1444
1550
|
rb_define_singleton_method(cState, "from_state", cState_from_state_s, 1);
|
1445
1551
|
rb_define_method(cState, "initialize", cState_initialize, -1);
|
1446
1552
|
rb_define_alias(cState, "initialize", "initialize"); // avoid method redefinition warnings
|
1553
|
+
rb_define_private_method(cState, "_configure", cState_configure, 1);
|
1447
1554
|
|
1448
1555
|
rb_define_method(cState, "initialize_copy", cState_init_copy, 1);
|
1449
1556
|
rb_define_method(cState, "indent", cState_indent, 0);
|
@@ -1478,6 +1585,8 @@ void Init_generator(void)
|
|
1478
1585
|
rb_define_method(cState, "buffer_initial_length=", cState_buffer_initial_length_set, 1);
|
1479
1586
|
rb_define_method(cState, "generate", cState_generate, 1);
|
1480
1587
|
|
1588
|
+
rb_define_singleton_method(cState, "generate", cState_m_generate, 2);
|
1589
|
+
|
1481
1590
|
VALUE mGeneratorMethods = rb_define_module_under(mGenerator, "GeneratorMethods");
|
1482
1591
|
|
1483
1592
|
VALUE mObject = rb_define_module_under(mGeneratorMethods, "Object");
|
@@ -1532,6 +1641,20 @@ void Init_generator(void)
|
|
1532
1641
|
i_extend = rb_intern("extend");
|
1533
1642
|
i_encode = rb_intern("encode");
|
1534
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
|
+
|
1535
1658
|
usascii_encindex = rb_usascii_encindex();
|
1536
1659
|
utf8_encindex = rb_utf8_encindex();
|
1537
1660
|
binary_encindex = rb_ascii8bit_encindex();
|