json 2.7.4 → 2.8.1

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
  *
@@ -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();