json 2.7.4 → 2.8.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
  *
@@ -403,7 +451,9 @@ static char *fstrndup(const char *ptr, unsigned long len) {
403
451
  */
404
452
  static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self)
405
453
  {
406
- GENERATE_JSON(object);
454
+ rb_check_arity(argc, 0, 1);
455
+ VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
456
+ return cState_partial_generate(Vstate, self, generate_json_object);
407
457
  }
408
458
 
409
459
  /*
@@ -415,7 +465,9 @@ static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self)
415
465
  * produced JSON string output further.
416
466
  */
417
467
  static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) {
418
- GENERATE_JSON(array);
468
+ rb_check_arity(argc, 0, 1);
469
+ VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
470
+ return cState_partial_generate(Vstate, self, generate_json_array);
419
471
  }
420
472
 
421
473
  #ifdef RUBY_INTEGER_UNIFICATION
@@ -426,7 +478,9 @@ static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) {
426
478
  */
427
479
  static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self)
428
480
  {
429
- GENERATE_JSON(integer);
481
+ rb_check_arity(argc, 0, 1);
482
+ VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
483
+ return cState_partial_generate(Vstate, self, generate_json_integer);
430
484
  }
431
485
 
432
486
  #else
@@ -437,7 +491,9 @@ static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self)
437
491
  */
438
492
  static VALUE mFixnum_to_json(int argc, VALUE *argv, VALUE self)
439
493
  {
440
- GENERATE_JSON(fixnum);
494
+ rb_check_arity(argc, 0, 1);
495
+ VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
496
+ return cState_partial_generate(Vstate, self, generate_json_fixnum);
441
497
  }
442
498
 
443
499
  /*
@@ -447,7 +503,9 @@ static VALUE mFixnum_to_json(int argc, VALUE *argv, VALUE self)
447
503
  */
448
504
  static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)
449
505
  {
450
- GENERATE_JSON(bignum);
506
+ rb_check_arity(argc, 0, 1);
507
+ VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
508
+ return cState_partial_generate(Vstate, self, generate_json_bignum);
451
509
  }
452
510
  #endif
453
511
 
@@ -458,7 +516,9 @@ static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)
458
516
  */
459
517
  static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self)
460
518
  {
461
- GENERATE_JSON(float);
519
+ rb_check_arity(argc, 0, 1);
520
+ VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
521
+ return cState_partial_generate(Vstate, self, generate_json_float);
462
522
  }
463
523
 
464
524
  /*
@@ -481,7 +541,9 @@ static VALUE mString_included_s(VALUE self, VALUE modul) {
481
541
  */
482
542
  static VALUE mString_to_json(int argc, VALUE *argv, VALUE self)
483
543
  {
484
- GENERATE_JSON(string);
544
+ rb_check_arity(argc, 0, 1);
545
+ VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
546
+ return cState_partial_generate(Vstate, self, generate_json_string);
485
547
  }
486
548
 
487
549
  /*
@@ -498,7 +560,7 @@ static VALUE mString_to_json_raw_object(VALUE self)
498
560
  VALUE result = rb_hash_new();
499
561
  rb_hash_aset(result, rb_funcall(mJSON, i_create_id, 0), rb_class_name(rb_obj_class(self)));
500
562
  ary = rb_funcall(self, i_unpack, 1, rb_str_new2("C*"));
501
- rb_hash_aset(result, rb_str_new2("raw"), ary);
563
+ rb_hash_aset(result, rb_utf8_str_new_lit("raw"), ary);
502
564
  return result;
503
565
  }
504
566
 
@@ -536,7 +598,8 @@ static VALUE mString_Extend_json_create(VALUE self, VALUE o)
536
598
  */
537
599
  static VALUE mTrueClass_to_json(int argc, VALUE *argv, VALUE self)
538
600
  {
539
- GENERATE_JSON(true);
601
+ rb_check_arity(argc, 0, 1);
602
+ return rb_utf8_str_new("true", 4);
540
603
  }
541
604
 
542
605
  /*
@@ -546,7 +609,8 @@ static VALUE mTrueClass_to_json(int argc, VALUE *argv, VALUE self)
546
609
  */
547
610
  static VALUE mFalseClass_to_json(int argc, VALUE *argv, VALUE self)
548
611
  {
549
- GENERATE_JSON(false);
612
+ rb_check_arity(argc, 0, 1);
613
+ return rb_utf8_str_new("false", 5);
550
614
  }
551
615
 
552
616
  /*
@@ -556,7 +620,8 @@ static VALUE mFalseClass_to_json(int argc, VALUE *argv, VALUE self)
556
620
  */
557
621
  static VALUE mNilClass_to_json(int argc, VALUE *argv, VALUE self)
558
622
  {
559
- GENERATE_JSON(null);
623
+ rb_check_arity(argc, 0, 1);
624
+ return rb_utf8_str_new("null", 4);
560
625
  }
561
626
 
562
627
  /*
@@ -573,30 +638,38 @@ static VALUE mObject_to_json(int argc, VALUE *argv, VALUE self)
573
638
  rb_scan_args(argc, argv, "01", &state);
574
639
  Check_Type(string, T_STRING);
575
640
  state = cState_from_state_s(cState, state);
576
- return cState_partial_generate(state, string);
641
+ return cState_partial_generate(state, string, generate_json_string);
642
+ }
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);
577
662
  }
578
663
 
579
664
  static void State_free(void *ptr)
580
665
  {
581
666
  JSON_Generator_State *state = ptr;
582
- if (state->indent) ruby_xfree(state->indent);
583
- if (state->space) ruby_xfree(state->space);
584
- if (state->space_before) ruby_xfree(state->space_before);
585
- if (state->object_nl) ruby_xfree(state->object_nl);
586
- if (state->array_nl) ruby_xfree(state->array_nl);
587
667
  ruby_xfree(state);
588
668
  }
589
669
 
590
670
  static size_t State_memsize(const void *ptr)
591
671
  {
592
- const JSON_Generator_State *state = ptr;
593
- size_t size = sizeof(*state);
594
- if (state->indent) size += state->indent_len + 1;
595
- if (state->space) size += state->space_len + 1;
596
- if (state->space_before) size += state->space_before_len + 1;
597
- if (state->object_nl) size += state->object_nl_len + 1;
598
- if (state->array_nl) size += state->array_nl_len + 1;
599
- return size;
672
+ return sizeof(JSON_Generator_State);
600
673
  }
601
674
 
602
675
  #ifndef HAVE_RB_EXT_RACTOR_SAFE
@@ -606,24 +679,54 @@ static size_t State_memsize(const void *ptr)
606
679
 
607
680
  static const rb_data_type_t JSON_Generator_State_type = {
608
681
  "JSON/Generator/State",
609
- {NULL, State_free, State_memsize,},
682
+ {
683
+ .dmark = State_mark,
684
+ .dfree = State_free,
685
+ .dsize = State_memsize,
686
+ .dcompact = State_compact,
687
+ },
610
688
  0, 0,
611
689
  RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE,
612
690
  };
613
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
+
614
698
  static VALUE cState_s_allocate(VALUE klass)
615
699
  {
616
700
  JSON_Generator_State *state;
617
701
  VALUE obj = TypedData_Make_Struct(klass, JSON_Generator_State, &JSON_Generator_State_type, state);
618
- state->max_nesting = 100;
619
- state->buffer_initial_length = FBUFFER_INITIAL_LENGTH_DEFAULT;
702
+ state_init(state);
620
703
  return obj;
621
704
  }
622
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
+
623
728
  struct hash_foreach_arg {
624
- FBuffer *buffer;
625
- JSON_Generator_State *state;
626
- VALUE Vstate;
729
+ struct generate_json_data *data;
627
730
  int iter;
628
731
  };
629
732
 
@@ -631,27 +734,32 @@ static int
631
734
  json_object_i(VALUE key, VALUE val, VALUE _arg)
632
735
  {
633
736
  struct hash_foreach_arg *arg = (struct hash_foreach_arg *)_arg;
634
- FBuffer *buffer = arg->buffer;
635
- JSON_Generator_State *state = arg->state;
636
- 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;
637
741
 
638
742
  long depth = state->depth;
639
743
  int j;
640
744
 
641
745
  if (arg->iter > 0) fbuffer_append_char(buffer, ',');
642
746
  if (RB_UNLIKELY(state->object_nl)) {
643
- fbuffer_append(buffer, state->object_nl, state->object_nl_len);
747
+ fbuffer_append_str(buffer, state->object_nl);
644
748
  }
645
749
  if (RB_UNLIKELY(state->indent)) {
646
750
  for (j = 0; j < depth; j++) {
647
- fbuffer_append(buffer, state->indent, state->indent_len);
751
+ fbuffer_append_str(buffer, state->indent);
648
752
  }
649
753
  }
650
754
 
651
755
  VALUE key_to_s;
652
756
  switch(rb_type(key)) {
653
757
  case T_STRING:
654
- key_to_s = key;
758
+ if (RB_LIKELY(RBASIC_CLASS(key) == rb_cString)) {
759
+ key_to_s = key;
760
+ } else {
761
+ key_to_s = rb_funcall(key, i_to_s, 0);
762
+ }
655
763
  break;
656
764
  case T_SYMBOL:
657
765
  key_to_s = rb_sym2str(key);
@@ -661,47 +769,57 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
661
769
  break;
662
770
  }
663
771
 
664
- generate_json_string(buffer, Vstate, state, key_to_s);
665
- if (RB_UNLIKELY(state->space_before)) fbuffer_append(buffer, state->space_before, state->space_before_len);
772
+ if (RB_LIKELY(RBASIC_CLASS(key_to_s) == rb_cString)) {
773
+ generate_json_string(buffer, data, state, key_to_s);
774
+ } else {
775
+ generate_json(buffer, data, state, key_to_s);
776
+ }
777
+ if (RB_UNLIKELY(state->space_before)) fbuffer_append_str(buffer, state->space_before);
666
778
  fbuffer_append_char(buffer, ':');
667
- if (RB_UNLIKELY(state->space)) fbuffer_append(buffer, state->space, state->space_len);
668
- 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);
669
781
 
670
782
  arg->iter++;
671
783
  return ST_CONTINUE;
672
784
  }
673
785
 
674
- 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)
675
787
  {
676
788
  long max_nesting = state->max_nesting;
677
789
  long depth = ++state->depth;
678
790
  int j;
679
- struct hash_foreach_arg arg;
680
791
 
681
792
  if (max_nesting != 0 && depth > max_nesting) {
682
793
  rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
683
794
  }
795
+
796
+ if (RHASH_SIZE(obj) == 0) {
797
+ fbuffer_append(buffer, "{}", 2);
798
+ --state->depth;
799
+ return;
800
+ }
801
+
684
802
  fbuffer_append_char(buffer, '{');
685
803
 
686
- arg.buffer = buffer;
687
- arg.state = state;
688
- arg.Vstate = Vstate;
689
- arg.iter = 0;
804
+ struct hash_foreach_arg arg = {
805
+ .data = data,
806
+ .iter = 0,
807
+ };
690
808
  rb_hash_foreach(obj, json_object_i, (VALUE)&arg);
691
809
 
692
810
  depth = --state->depth;
693
811
  if (RB_UNLIKELY(state->object_nl)) {
694
- fbuffer_append(buffer, state->object_nl, state->object_nl_len);
812
+ fbuffer_append_str(buffer, state->object_nl);
695
813
  if (RB_UNLIKELY(state->indent)) {
696
814
  for (j = 0; j < depth; j++) {
697
- fbuffer_append(buffer, state->indent, state->indent_len);
815
+ fbuffer_append_str(buffer, state->indent);
698
816
  }
699
817
  }
700
818
  }
701
819
  fbuffer_append_char(buffer, '}');
702
820
  }
703
821
 
704
- 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)
705
823
  {
706
824
  long max_nesting = state->max_nesting;
707
825
  long depth = ++state->depth;
@@ -709,34 +827,39 @@ static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
709
827
  if (max_nesting != 0 && depth > max_nesting) {
710
828
  rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
711
829
  }
830
+
831
+ if (RARRAY_LEN(obj) == 0) {
832
+ fbuffer_append(buffer, "[]", 2);
833
+ --state->depth;
834
+ return;
835
+ }
836
+
712
837
  fbuffer_append_char(buffer, '[');
713
- 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);
714
839
  for(i = 0; i < RARRAY_LEN(obj); i++) {
715
840
  if (i > 0) {
716
841
  fbuffer_append_char(buffer, ',');
717
- 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);
718
843
  }
719
844
  if (RB_UNLIKELY(state->indent)) {
720
845
  for (j = 0; j < depth; j++) {
721
- fbuffer_append(buffer, state->indent, state->indent_len);
846
+ fbuffer_append_str(buffer, state->indent);
722
847
  }
723
848
  }
724
- generate_json(buffer, Vstate, state, RARRAY_AREF(obj, i));
849
+ generate_json(buffer, data, state, RARRAY_AREF(obj, i));
725
850
  }
726
851
  state->depth = --depth;
727
852
  if (RB_UNLIKELY(state->array_nl)) {
728
- fbuffer_append(buffer, state->array_nl, state->array_nl_len);
853
+ fbuffer_append_str(buffer, state->array_nl);
729
854
  if (RB_UNLIKELY(state->indent)) {
730
855
  for (j = 0; j < depth; j++) {
731
- fbuffer_append(buffer, state->indent, state->indent_len);
856
+ fbuffer_append_str(buffer, state->indent);
732
857
  }
733
858
  }
734
859
  }
735
860
  fbuffer_append_char(buffer, ']');
736
861
  }
737
862
 
738
- static int usascii_encindex, utf8_encindex, binary_encindex;
739
-
740
863
  static inline int enc_utf8_compatible_p(int enc_idx)
741
864
  {
742
865
  if (enc_idx == usascii_encindex) return 1;
@@ -750,13 +873,14 @@ static inline VALUE ensure_valid_encoding(VALUE str)
750
873
  VALUE utf8_string;
751
874
  if (RB_UNLIKELY(!enc_utf8_compatible_p(encindex))) {
752
875
  if (encindex == binary_encindex) {
753
- // For historical reason, we silently reinterpret binary strings as UTF-8 if it would work.
754
- // TODO: Deprecate in 2.8.0
755
- // TODO: Remove in 3.0.0
756
876
  utf8_string = rb_enc_associate_index(rb_str_dup(str), utf8_encindex);
757
877
  switch (rb_enc_str_coderange(utf8_string)) {
758
878
  case ENC_CODERANGE_7BIT:
879
+ return utf8_string;
759
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");
760
884
  return utf8_string;
761
885
  break;
762
886
  }
@@ -767,7 +891,7 @@ static inline VALUE ensure_valid_encoding(VALUE str)
767
891
  return str;
768
892
  }
769
893
 
770
- 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)
771
895
  {
772
896
  obj = ensure_valid_encoding(obj);
773
897
 
@@ -791,42 +915,43 @@ static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_S
791
915
  fbuffer_append_char(buffer, '"');
792
916
  }
793
917
 
794
- 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)
795
919
  {
796
920
  fbuffer_append(buffer, "null", 4);
797
921
  }
798
922
 
799
- 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)
800
924
  {
801
925
  fbuffer_append(buffer, "false", 5);
802
926
  }
803
927
 
804
- 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)
805
929
  {
806
930
  fbuffer_append(buffer, "true", 4);
807
931
  }
808
932
 
809
- 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)
810
934
  {
811
935
  fbuffer_append_long(buffer, FIX2LONG(obj));
812
936
  }
813
937
 
814
- 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)
815
939
  {
816
940
  VALUE tmp = rb_funcall(obj, i_to_s, 0);
817
941
  fbuffer_append_str(buffer, tmp);
818
942
  }
819
943
 
820
944
  #ifdef RUBY_INTEGER_UNIFICATION
821
- 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)
822
946
  {
823
947
  if (FIXNUM_P(obj))
824
- generate_json_fixnum(buffer, Vstate, state, obj);
948
+ generate_json_fixnum(buffer, data, state, obj);
825
949
  else
826
- generate_json_bignum(buffer, Vstate, state, obj);
950
+ generate_json_bignum(buffer, data, state, obj);
827
951
  }
828
952
  #endif
829
- static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
953
+
954
+ static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
830
955
  {
831
956
  double value = RFLOAT_VALUE(obj);
832
957
  char allow_nan = state->allow_nan;
@@ -841,20 +966,20 @@ static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
841
966
  fbuffer_append_str(buffer, tmp);
842
967
  }
843
968
 
844
- 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)
845
970
  {
846
971
  VALUE tmp;
847
972
  if (obj == Qnil) {
848
- generate_json_null(buffer, Vstate, state, obj);
973
+ generate_json_null(buffer, data, state, obj);
849
974
  } else if (obj == Qfalse) {
850
- generate_json_false(buffer, Vstate, state, obj);
975
+ generate_json_false(buffer, data, state, obj);
851
976
  } else if (obj == Qtrue) {
852
- generate_json_true(buffer, Vstate, state, obj);
977
+ generate_json_true(buffer, data, state, obj);
853
978
  } else if (RB_SPECIAL_CONST_P(obj)) {
854
979
  if (RB_FIXNUM_P(obj)) {
855
- generate_json_fixnum(buffer, Vstate, state, obj);
980
+ generate_json_fixnum(buffer, data, state, obj);
856
981
  } else if (RB_FLONUM_P(obj)) {
857
- generate_json_float(buffer, Vstate, state, obj);
982
+ generate_json_float(buffer, data, state, obj);
858
983
  } else {
859
984
  goto general;
860
985
  }
@@ -862,62 +987,46 @@ static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *s
862
987
  VALUE klass = RBASIC_CLASS(obj);
863
988
  switch (RB_BUILTIN_TYPE(obj)) {
864
989
  case T_BIGNUM:
865
- generate_json_bignum(buffer, Vstate, state, obj);
990
+ generate_json_bignum(buffer, data, state, obj);
866
991
  break;
867
992
  case T_HASH:
868
993
  if (klass != rb_cHash) goto general;
869
- generate_json_object(buffer, Vstate, state, obj);
994
+ generate_json_object(buffer, data, state, obj);
870
995
  break;
871
996
  case T_ARRAY:
872
997
  if (klass != rb_cArray) goto general;
873
- generate_json_array(buffer, Vstate, state, obj);
998
+ generate_json_array(buffer, data, state, obj);
874
999
  break;
875
1000
  case T_STRING:
876
1001
  if (klass != rb_cString) goto general;
877
- generate_json_string(buffer, Vstate, state, obj);
1002
+ generate_json_string(buffer, data, state, obj);
878
1003
  break;
879
1004
  case T_FLOAT:
880
1005
  if (klass != rb_cFloat) goto general;
881
- generate_json_float(buffer, Vstate, state, obj);
1006
+ generate_json_float(buffer, data, state, obj);
882
1007
  break;
883
1008
  default:
884
1009
  general:
885
1010
  if (state->strict) {
886
1011
  rb_raise(eGeneratorError, "%"PRIsVALUE" not allowed in JSON", CLASS_OF(obj));
887
1012
  } else if (rb_respond_to(obj, i_to_json)) {
888
- tmp = rb_funcall(obj, i_to_json, 1, Vstate);
1013
+ tmp = rb_funcall(obj, i_to_json, 1, vstate_get(data));
889
1014
  Check_Type(tmp, T_STRING);
890
1015
  fbuffer_append_str(buffer, tmp);
891
1016
  } else {
892
1017
  tmp = rb_funcall(obj, i_to_s, 0);
893
1018
  Check_Type(tmp, T_STRING);
894
- generate_json_string(buffer, Vstate, state, tmp);
1019
+ generate_json_string(buffer, data, state, tmp);
895
1020
  }
896
1021
  }
897
1022
  }
898
1023
  }
899
1024
 
900
- static FBuffer *cState_prepare_buffer(VALUE self)
901
- {
902
- FBuffer *buffer;
903
- GET_STATE(self);
904
- buffer = fbuffer_alloc(state->buffer_initial_length);
905
-
906
- return buffer;
907
- }
908
-
909
- struct generate_json_data {
910
- FBuffer *buffer;
911
- VALUE vstate;
912
- JSON_Generator_State *state;
913
- VALUE obj;
914
- };
915
-
916
1025
  static VALUE generate_json_try(VALUE d)
917
1026
  {
918
1027
  struct generate_json_data *data = (struct generate_json_data *)d;
919
1028
 
920
- generate_json(data->buffer, data->vstate, data->state, data->obj);
1029
+ data->func(data->buffer, data, data->state, data->obj);
921
1030
 
922
1031
  return Qnil;
923
1032
  }
@@ -927,25 +1036,33 @@ static VALUE generate_json_rescue(VALUE d, VALUE exc)
927
1036
  struct generate_json_data *data = (struct generate_json_data *)d;
928
1037
  fbuffer_free(data->buffer);
929
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
+
930
1043
  rb_exc_raise(exc);
931
1044
 
932
1045
  return Qundef;
933
1046
  }
934
1047
 
935
- static VALUE cState_partial_generate(VALUE self, VALUE obj)
1048
+ static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func)
936
1049
  {
937
- FBuffer *buffer = cState_prepare_buffer(self);
938
1050
  GET_STATE(self);
939
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
+
940
1056
  struct generate_json_data data = {
941
- .buffer = buffer,
1057
+ .buffer = &buffer,
942
1058
  .vstate = self,
943
1059
  .state = state,
944
- .obj = obj
1060
+ .obj = obj,
1061
+ .func = func
945
1062
  };
946
1063
  rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data);
947
1064
 
948
- return fbuffer_to_s(buffer);
1065
+ return fbuffer_to_s(&buffer);
949
1066
  }
950
1067
 
951
1068
  /*
@@ -957,7 +1074,7 @@ static VALUE cState_partial_generate(VALUE self, VALUE obj)
957
1074
  */
958
1075
  static VALUE cState_generate(VALUE self, VALUE obj)
959
1076
  {
960
- VALUE result = cState_partial_generate(self, obj);
1077
+ VALUE result = cState_partial_generate(self, obj, generate_json);
961
1078
  GET_STATE(self);
962
1079
  (void)state;
963
1080
  return result;
@@ -985,11 +1102,11 @@ static VALUE cState_init_copy(VALUE obj, VALUE orig)
985
1102
  if (!objState) rb_raise(rb_eArgError, "unallocated JSON::State");
986
1103
 
987
1104
  MEMCPY(objState, origState, JSON_Generator_State, 1);
988
- objState->indent = fstrndup(origState->indent, origState->indent_len);
989
- objState->space = fstrndup(origState->space, origState->space_len);
990
- objState->space_before = fstrndup(origState->space_before, origState->space_before_len);
991
- objState->object_nl = fstrndup(origState->object_nl, origState->object_nl_len);
992
- 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;
993
1110
  return obj;
994
1111
  }
995
1112
 
@@ -1019,7 +1136,18 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
1019
1136
  static VALUE cState_indent(VALUE self)
1020
1137
  {
1021
1138
  GET_STATE(self);
1022
- 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;
1023
1151
  }
1024
1152
 
1025
1153
  /*
@@ -1029,21 +1157,8 @@ static VALUE cState_indent(VALUE self)
1029
1157
  */
1030
1158
  static VALUE cState_indent_set(VALUE self, VALUE indent)
1031
1159
  {
1032
- unsigned long len;
1033
1160
  GET_STATE(self);
1034
- Check_Type(indent, T_STRING);
1035
- len = RSTRING_LEN(indent);
1036
- if (len == 0) {
1037
- if (state->indent) {
1038
- ruby_xfree(state->indent);
1039
- state->indent = NULL;
1040
- state->indent_len = 0;
1041
- }
1042
- } else {
1043
- if (state->indent) ruby_xfree(state->indent);
1044
- state->indent = fstrndup(RSTRING_PTR(indent), len);
1045
- state->indent_len = len;
1046
- }
1161
+ RB_OBJ_WRITE(self, &state->indent, string_config(indent));
1047
1162
  return Qnil;
1048
1163
  }
1049
1164
 
@@ -1056,7 +1171,7 @@ static VALUE cState_indent_set(VALUE self, VALUE indent)
1056
1171
  static VALUE cState_space(VALUE self)
1057
1172
  {
1058
1173
  GET_STATE(self);
1059
- 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));
1060
1175
  }
1061
1176
 
1062
1177
  /*
@@ -1067,21 +1182,8 @@ static VALUE cState_space(VALUE self)
1067
1182
  */
1068
1183
  static VALUE cState_space_set(VALUE self, VALUE space)
1069
1184
  {
1070
- unsigned long len;
1071
1185
  GET_STATE(self);
1072
- Check_Type(space, T_STRING);
1073
- len = RSTRING_LEN(space);
1074
- if (len == 0) {
1075
- if (state->space) {
1076
- ruby_xfree(state->space);
1077
- state->space = NULL;
1078
- state->space_len = 0;
1079
- }
1080
- } else {
1081
- if (state->space) ruby_xfree(state->space);
1082
- state->space = fstrndup(RSTRING_PTR(space), len);
1083
- state->space_len = len;
1084
- }
1186
+ RB_OBJ_WRITE(self, &state->space, string_config(space));
1085
1187
  return Qnil;
1086
1188
  }
1087
1189
 
@@ -1093,7 +1195,7 @@ static VALUE cState_space_set(VALUE self, VALUE space)
1093
1195
  static VALUE cState_space_before(VALUE self)
1094
1196
  {
1095
1197
  GET_STATE(self);
1096
- 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));
1097
1199
  }
1098
1200
 
1099
1201
  /*
@@ -1103,21 +1205,8 @@ static VALUE cState_space_before(VALUE self)
1103
1205
  */
1104
1206
  static VALUE cState_space_before_set(VALUE self, VALUE space_before)
1105
1207
  {
1106
- unsigned long len;
1107
1208
  GET_STATE(self);
1108
- Check_Type(space_before, T_STRING);
1109
- len = RSTRING_LEN(space_before);
1110
- if (len == 0) {
1111
- if (state->space_before) {
1112
- ruby_xfree(state->space_before);
1113
- state->space_before = NULL;
1114
- state->space_before_len = 0;
1115
- }
1116
- } else {
1117
- if (state->space_before) ruby_xfree(state->space_before);
1118
- state->space_before = fstrndup(RSTRING_PTR(space_before), len);
1119
- state->space_before_len = len;
1120
- }
1209
+ RB_OBJ_WRITE(self, &state->space_before, string_config(space_before));
1121
1210
  return Qnil;
1122
1211
  }
1123
1212
 
@@ -1130,7 +1219,7 @@ static VALUE cState_space_before_set(VALUE self, VALUE space_before)
1130
1219
  static VALUE cState_object_nl(VALUE self)
1131
1220
  {
1132
1221
  GET_STATE(self);
1133
- 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));
1134
1223
  }
1135
1224
 
1136
1225
  /*
@@ -1141,20 +1230,8 @@ static VALUE cState_object_nl(VALUE self)
1141
1230
  */
1142
1231
  static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
1143
1232
  {
1144
- unsigned long len;
1145
1233
  GET_STATE(self);
1146
- Check_Type(object_nl, T_STRING);
1147
- len = RSTRING_LEN(object_nl);
1148
- if (len == 0) {
1149
- if (state->object_nl) {
1150
- ruby_xfree(state->object_nl);
1151
- state->object_nl = NULL;
1152
- }
1153
- } else {
1154
- if (state->object_nl) ruby_xfree(state->object_nl);
1155
- state->object_nl = fstrndup(RSTRING_PTR(object_nl), len);
1156
- state->object_nl_len = len;
1157
- }
1234
+ RB_OBJ_WRITE(self, &state->object_nl, string_config(object_nl));
1158
1235
  return Qnil;
1159
1236
  }
1160
1237
 
@@ -1166,7 +1243,7 @@ static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
1166
1243
  static VALUE cState_array_nl(VALUE self)
1167
1244
  {
1168
1245
  GET_STATE(self);
1169
- 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));
1170
1247
  }
1171
1248
 
1172
1249
  /*
@@ -1176,20 +1253,8 @@ static VALUE cState_array_nl(VALUE self)
1176
1253
  */
1177
1254
  static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
1178
1255
  {
1179
- unsigned long len;
1180
1256
  GET_STATE(self);
1181
- Check_Type(array_nl, T_STRING);
1182
- len = RSTRING_LEN(array_nl);
1183
- if (len == 0) {
1184
- if (state->array_nl) {
1185
- ruby_xfree(state->array_nl);
1186
- state->array_nl = NULL;
1187
- }
1188
- } else {
1189
- if (state->array_nl) ruby_xfree(state->array_nl);
1190
- state->array_nl = fstrndup(RSTRING_PTR(array_nl), len);
1191
- state->array_nl_len = len;
1192
- }
1257
+ RB_OBJ_WRITE(self, &state->array_nl, string_config(array_nl));
1193
1258
  return Qnil;
1194
1259
  }
1195
1260
 
@@ -1218,6 +1283,11 @@ static VALUE cState_max_nesting(VALUE self)
1218
1283
  return LONG2FIX(state->max_nesting);
1219
1284
  }
1220
1285
 
1286
+ static long long_config(VALUE num)
1287
+ {
1288
+ return RTEST(num) ? FIX2LONG(num) : 0;
1289
+ }
1290
+
1221
1291
  /*
1222
1292
  * call-seq: max_nesting=(depth)
1223
1293
  *
@@ -1227,8 +1297,7 @@ static VALUE cState_max_nesting(VALUE self)
1227
1297
  static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
1228
1298
  {
1229
1299
  GET_STATE(self);
1230
- Check_Type(depth, T_FIXNUM);
1231
- state->max_nesting = FIX2LONG(depth);
1300
+ state->max_nesting = long_config(depth);
1232
1301
  return Qnil;
1233
1302
  }
1234
1303
 
@@ -1356,8 +1425,7 @@ static VALUE cState_depth(VALUE self)
1356
1425
  static VALUE cState_depth_set(VALUE self, VALUE depth)
1357
1426
  {
1358
1427
  GET_STATE(self);
1359
- Check_Type(depth, T_FIXNUM);
1360
- state->depth = FIX2LONG(depth);
1428
+ state->depth = long_config(depth);
1361
1429
  return Qnil;
1362
1430
  }
1363
1431
 
@@ -1372,6 +1440,15 @@ static VALUE cState_buffer_initial_length(VALUE self)
1372
1440
  return LONG2FIX(state->buffer_initial_length);
1373
1441
  }
1374
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
+
1375
1452
  /*
1376
1453
  * call-seq: buffer_initial_length=(length)
1377
1454
  *
@@ -1380,16 +1457,73 @@ static VALUE cState_buffer_initial_length(VALUE self)
1380
1457
  */
1381
1458
  static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_length)
1382
1459
  {
1383
- long initial_length;
1384
1460
  GET_STATE(self);
1385
- Check_Type(buffer_initial_length, T_FIXNUM);
1386
- initial_length = FIX2LONG(buffer_initial_length);
1387
- if (initial_length > 0) {
1388
- state->buffer_initial_length = initial_length;
1389
- }
1461
+ buffer_initial_length_set(state, buffer_initial_length);
1390
1462
  return Qnil;
1391
1463
  }
1392
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
+
1393
1527
  /*
1394
1528
  *
1395
1529
  */
@@ -1416,6 +1550,7 @@ void Init_generator(void)
1416
1550
  rb_define_singleton_method(cState, "from_state", cState_from_state_s, 1);
1417
1551
  rb_define_method(cState, "initialize", cState_initialize, -1);
1418
1552
  rb_define_alias(cState, "initialize", "initialize"); // avoid method redefinition warnings
1553
+ rb_define_private_method(cState, "_configure", cState_configure, 1);
1419
1554
 
1420
1555
  rb_define_method(cState, "initialize_copy", cState_init_copy, 1);
1421
1556
  rb_define_method(cState, "indent", cState_indent, 0);
@@ -1450,6 +1585,8 @@ void Init_generator(void)
1450
1585
  rb_define_method(cState, "buffer_initial_length=", cState_buffer_initial_length_set, 1);
1451
1586
  rb_define_method(cState, "generate", cState_generate, 1);
1452
1587
 
1588
+ rb_define_singleton_method(cState, "generate", cState_m_generate, 2);
1589
+
1453
1590
  VALUE mGeneratorMethods = rb_define_module_under(mGenerator, "GeneratorMethods");
1454
1591
 
1455
1592
  VALUE mObject = rb_define_module_under(mGeneratorMethods, "Object");
@@ -1504,6 +1641,20 @@ void Init_generator(void)
1504
1641
  i_extend = rb_intern("extend");
1505
1642
  i_encode = rb_intern("encode");
1506
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
+
1507
1658
  usascii_encindex = rb_usascii_encindex();
1508
1659
  utf8_encindex = rb_utf8_encindex();
1509
1660
  binary_encindex = rb_ascii8bit_encindex();