json 2.7.6 → 2.8.0.alpha1
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 +8 -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 +3 -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();
|