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.
@@ -1,5 +1,27 @@
1
+ #include "ruby.h"
1
2
  #include "../fbuffer/fbuffer.h"
2
- #include "generator.h"
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] = hexdig[ch >> 12];
63
- scratch[3] = hexdig[(ch >> 8) & 0xf];
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] = hexdig[ch >> 12];
185
- scratch[3] = hexdig[(ch >> 8) & 0xf];
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] = hexdig[ch >> 12];
236
- scratch[3] = hexdig[(ch >> 8) & 0xf];
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, rb_str_new2("raw"), ary);
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
- const JSON_Generator_State *state = ptr;
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
- {NULL, State_free, State_memsize,},
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->max_nesting = 100;
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
- FBuffer *buffer;
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
- FBuffer *buffer = arg->buffer;
652
- JSON_Generator_State *state = arg->state;
653
- VALUE Vstate = arg->Vstate;
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
- fbuffer_append(buffer, state->object_nl, state->object_nl_len);
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
- fbuffer_append(buffer, state->indent, state->indent_len);
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, Vstate, state, key_to_s);
773
+ generate_json_string(buffer, data, state, key_to_s);
687
774
  } else {
688
- generate_json(buffer, Vstate, state, key_to_s);
775
+ generate_json(buffer, data, state, key_to_s);
689
776
  }
690
- if (RB_UNLIKELY(state->space_before)) fbuffer_append(buffer, state->space_before, state->space_before_len);
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)) fbuffer_append(buffer, state->space, state->space_len);
693
- generate_json(buffer, Vstate, state, val);
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, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
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.buffer = buffer;
712
- arg.state = state;
713
- arg.Vstate = Vstate;
714
- arg.iter = 0;
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
- fbuffer_append(buffer, state->object_nl, state->object_nl_len);
812
+ fbuffer_append_str(buffer, state->object_nl);
720
813
  if (RB_UNLIKELY(state->indent)) {
721
814
  for (j = 0; j < depth; j++) {
722
- fbuffer_append(buffer, state->indent, state->indent_len);
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, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
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)) fbuffer_append(buffer, state->array_nl, state->array_nl_len);
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)) fbuffer_append(buffer, state->array_nl, state->array_nl_len);
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
- fbuffer_append(buffer, state->indent, state->indent_len);
846
+ fbuffer_append_str(buffer, state->indent);
747
847
  }
748
848
  }
749
- generate_json(buffer, Vstate, state, RARRAY_AREF(obj, i));
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
- fbuffer_append(buffer, state->array_nl, state->array_nl_len);
853
+ fbuffer_append_str(buffer, state->array_nl);
754
854
  if (RB_UNLIKELY(state->indent)) {
755
855
  for (j = 0; j < depth; j++) {
756
- fbuffer_append(buffer, state->indent, state->indent_len);
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, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
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, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
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, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
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, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
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, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
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, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
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, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
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, Vstate, state, obj);
948
+ generate_json_fixnum(buffer, data, state, obj);
850
949
  else
851
- generate_json_bignum(buffer, Vstate, state, obj);
950
+ generate_json_bignum(buffer, data, state, obj);
852
951
  }
853
952
  #endif
854
953
 
855
- static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
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, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
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, Vstate, state, obj);
973
+ generate_json_null(buffer, data, state, obj);
875
974
  } else if (obj == Qfalse) {
876
- generate_json_false(buffer, Vstate, state, obj);
975
+ generate_json_false(buffer, data, state, obj);
877
976
  } else if (obj == Qtrue) {
878
- generate_json_true(buffer, Vstate, state, obj);
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, Vstate, state, obj);
980
+ generate_json_fixnum(buffer, data, state, obj);
882
981
  } else if (RB_FLONUM_P(obj)) {
883
- generate_json_float(buffer, Vstate, state, obj);
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, Vstate, state, obj);
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, Vstate, state, obj);
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, Vstate, state, obj);
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, Vstate, state, obj);
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, Vstate, state, obj);
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, Vstate);
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, Vstate, state, tmp);
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->vstate, data->state, data->obj);
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, void (*func)(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, 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 = fstrndup(origState->indent, origState->indent_len);
1017
- objState->space = fstrndup(origState->space, origState->space_len);
1018
- objState->space_before = fstrndup(origState->space_before, origState->space_before_len);
1019
- objState->object_nl = fstrndup(origState->object_nl, origState->object_nl_len);
1020
- objState->array_nl = fstrndup(origState->array_nl, origState->array_nl_len);
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 ? rb_str_new(state->indent, state->indent_len) : rb_str_new2("");
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
- Check_Type(indent, T_STRING);
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 ? rb_str_new(state->space, state->space_len) : rb_str_new2("");
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
- Check_Type(space, T_STRING);
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 ? rb_str_new(state->space_before, state->space_before_len) : rb_str_new2("");
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
- Check_Type(space_before, T_STRING);
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 ? rb_str_new(state->object_nl, state->object_nl_len) : rb_str_new2("");
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
- Check_Type(object_nl, T_STRING);
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 ? rb_str_new(state->array_nl, state->array_nl_len) : rb_str_new2("");
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
- Check_Type(array_nl, T_STRING);
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
- Check_Type(depth, T_FIXNUM);
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
- Check_Type(depth, T_FIXNUM);
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
- Check_Type(buffer_initial_length, T_FIXNUM);
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();