json 2.7.5 → 2.9.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,71 @@
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, VALUE io);
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;
73
+
74
+ #ifdef RBIMPL_ATTR_NORETURN
75
+ RBIMPL_ATTR_NORETURN()
76
+ #endif
77
+ static void raise_generator_error_str(VALUE invalid_object, VALUE str)
78
+ {
79
+ VALUE exc = rb_exc_new_str(eGeneratorError, str);
80
+ rb_ivar_set(exc, rb_intern("@invalid_object"), invalid_object);
81
+ rb_exc_raise(exc);
82
+ }
83
+
84
+ #ifdef RBIMPL_ATTR_NORETURN
85
+ RBIMPL_ATTR_NORETURN()
86
+ #endif
87
+ #ifdef RBIMPL_ATTR_FORMAT
88
+ RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 2, 3)
89
+ #endif
90
+ static void raise_generator_error(VALUE invalid_object, const char *fmt, ...)
91
+ {
92
+ va_list args;
93
+ va_start(args, fmt);
94
+ VALUE str = rb_vsprintf(fmt, args);
95
+ va_end(args);
96
+ raise_generator_error_str(invalid_object, str);
97
+ }
11
98
 
12
99
  /* Converts in_string to a JSON string (without the wrapping '"'
13
100
  * characters) in FBuffer out_buffer.
@@ -44,9 +131,6 @@ static void convert_UTF8_to_JSON(FBuffer *out_buffer, VALUE str, const char esca
44
131
 
45
132
  if (RB_UNLIKELY(ch_len)) {
46
133
  switch (ch_len) {
47
- case 0:
48
- pos++;
49
- break;
50
134
  case 1: {
51
135
  FLUSH_POS(1);
52
136
  switch (ch) {
@@ -59,8 +143,8 @@ static void convert_UTF8_to_JSON(FBuffer *out_buffer, VALUE str, const char esca
59
143
  case '\r': fbuffer_append(out_buffer, "\\r", 2); break;
60
144
  case '\t': fbuffer_append(out_buffer, "\\t", 2); break;
61
145
  default: {
62
- scratch[2] = hexdig[ch >> 12];
63
- scratch[3] = hexdig[(ch >> 8) & 0xf];
146
+ scratch[2] = '0';
147
+ scratch[3] = '0';
64
148
  scratch[4] = hexdig[(ch >> 4) & 0xf];
65
149
  scratch[5] = hexdig[ch & 0xf];
66
150
  fbuffer_append(out_buffer, scratch, 6);
@@ -71,7 +155,7 @@ static void convert_UTF8_to_JSON(FBuffer *out_buffer, VALUE str, const char esca
71
155
  }
72
156
  case 3: {
73
157
  unsigned char b2 = ptr[pos + 1];
74
- if (RB_UNLIKELY(out_script_safe && b2 == 0x80)) {
158
+ if (RB_UNLIKELY(out_script_safe && ch == 0xE2 && b2 == 0x80)) {
75
159
  unsigned char b3 = ptr[pos + 2];
76
160
  if (b3 == 0xA8) {
77
161
  FLUSH_POS(3);
@@ -181,8 +265,8 @@ static void convert_ASCII_to_JSON(FBuffer *out_buffer, VALUE str, const char esc
181
265
  case '\r': fbuffer_append(out_buffer, "\\r", 2); break;
182
266
  case '\t': fbuffer_append(out_buffer, "\\t", 2); break;
183
267
  default:
184
- scratch[2] = hexdig[ch >> 12];
185
- scratch[3] = hexdig[(ch >> 8) & 0xf];
268
+ scratch[2] = '0';
269
+ scratch[3] = '0';
186
270
  scratch[4] = hexdig[(ch >> 4) & 0xf];
187
271
  scratch[5] = hexdig[ch & 0xf];
188
272
  fbuffer_append(out_buffer, scratch, 6);
@@ -217,9 +301,6 @@ static void convert_UTF8_to_ASCII_only_JSON(FBuffer *out_buffer, VALUE str, cons
217
301
 
218
302
  if (RB_UNLIKELY(ch_len)) {
219
303
  switch (ch_len) {
220
- case 0:
221
- pos++;
222
- break;
223
304
  case 1: {
224
305
  FLUSH_POS(1);
225
306
  switch (ch) {
@@ -232,8 +313,8 @@ static void convert_UTF8_to_ASCII_only_JSON(FBuffer *out_buffer, VALUE str, cons
232
313
  case '\r': fbuffer_append(out_buffer, "\\r", 2); break;
233
314
  case '\t': fbuffer_append(out_buffer, "\\t", 2); break;
234
315
  default: {
235
- scratch[2] = hexdig[ch >> 12];
236
- scratch[3] = hexdig[(ch >> 8) & 0xf];
316
+ scratch[2] = '0';
317
+ scratch[3] = '0';
237
318
  scratch[4] = hexdig[(ch >> 4) & 0xf];
238
319
  scratch[5] = hexdig[ch & 0xf];
239
320
  fbuffer_append(out_buffer, scratch, 6);
@@ -303,14 +384,6 @@ static void convert_UTF8_to_ASCII_only_JSON(FBuffer *out_buffer, VALUE str, cons
303
384
  RB_GC_GUARD(str);
304
385
  }
305
386
 
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
387
  /*
315
388
  * Document-module: JSON::Ext::Generator
316
389
  *
@@ -405,7 +478,7 @@ static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self)
405
478
  {
406
479
  rb_check_arity(argc, 0, 1);
407
480
  VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
408
- return cState_partial_generate(Vstate, self, generate_json_object);
481
+ return cState_partial_generate(Vstate, self, generate_json_object, Qfalse);
409
482
  }
410
483
 
411
484
  /*
@@ -419,7 +492,7 @@ static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self)
419
492
  static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) {
420
493
  rb_check_arity(argc, 0, 1);
421
494
  VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
422
- return cState_partial_generate(Vstate, self, generate_json_array);
495
+ return cState_partial_generate(Vstate, self, generate_json_array, Qfalse);
423
496
  }
424
497
 
425
498
  #ifdef RUBY_INTEGER_UNIFICATION
@@ -432,7 +505,7 @@ static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self)
432
505
  {
433
506
  rb_check_arity(argc, 0, 1);
434
507
  VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
435
- return cState_partial_generate(Vstate, self, generate_json_integer);
508
+ return cState_partial_generate(Vstate, self, generate_json_integer, Qfalse);
436
509
  }
437
510
 
438
511
  #else
@@ -445,7 +518,7 @@ static VALUE mFixnum_to_json(int argc, VALUE *argv, VALUE self)
445
518
  {
446
519
  rb_check_arity(argc, 0, 1);
447
520
  VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
448
- return cState_partial_generate(Vstate, self, generate_json_fixnum);
521
+ return cState_partial_generate(Vstate, self, generate_json_fixnum, Qfalse);
449
522
  }
450
523
 
451
524
  /*
@@ -457,7 +530,7 @@ static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)
457
530
  {
458
531
  rb_check_arity(argc, 0, 1);
459
532
  VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
460
- return cState_partial_generate(Vstate, self, generate_json_bignum);
533
+ return cState_partial_generate(Vstate, self, generate_json_bignum, Qfalse);
461
534
  }
462
535
  #endif
463
536
 
@@ -470,7 +543,7 @@ static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self)
470
543
  {
471
544
  rb_check_arity(argc, 0, 1);
472
545
  VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
473
- return cState_partial_generate(Vstate, self, generate_json_float);
546
+ return cState_partial_generate(Vstate, self, generate_json_float, Qfalse);
474
547
  }
475
548
 
476
549
  /*
@@ -495,7 +568,7 @@ static VALUE mString_to_json(int argc, VALUE *argv, VALUE self)
495
568
  {
496
569
  rb_check_arity(argc, 0, 1);
497
570
  VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
498
- return cState_partial_generate(Vstate, self, generate_json_string);
571
+ return cState_partial_generate(Vstate, self, generate_json_string, Qfalse);
499
572
  }
500
573
 
501
574
  /*
@@ -512,7 +585,7 @@ static VALUE mString_to_json_raw_object(VALUE self)
512
585
  VALUE result = rb_hash_new();
513
586
  rb_hash_aset(result, rb_funcall(mJSON, i_create_id, 0), rb_class_name(rb_obj_class(self)));
514
587
  ary = rb_funcall(self, i_unpack, 1, rb_str_new2("C*"));
515
- rb_hash_aset(result, rb_str_new2("raw"), ary);
588
+ rb_hash_aset(result, rb_utf8_str_new_lit("raw"), ary);
516
589
  return result;
517
590
  }
518
591
 
@@ -590,30 +663,38 @@ static VALUE mObject_to_json(int argc, VALUE *argv, VALUE self)
590
663
  rb_scan_args(argc, argv, "01", &state);
591
664
  Check_Type(string, T_STRING);
592
665
  state = cState_from_state_s(cState, state);
593
- return cState_partial_generate(state, string, generate_json_string);
666
+ return cState_partial_generate(state, string, generate_json_string, Qfalse);
667
+ }
668
+
669
+ static void State_mark(void *ptr)
670
+ {
671
+ JSON_Generator_State *state = ptr;
672
+ rb_gc_mark_movable(state->indent);
673
+ rb_gc_mark_movable(state->space);
674
+ rb_gc_mark_movable(state->space_before);
675
+ rb_gc_mark_movable(state->object_nl);
676
+ rb_gc_mark_movable(state->array_nl);
677
+ }
678
+
679
+ static void State_compact(void *ptr)
680
+ {
681
+ JSON_Generator_State *state = ptr;
682
+ state->indent = rb_gc_location(state->indent);
683
+ state->space = rb_gc_location(state->space);
684
+ state->space_before = rb_gc_location(state->space_before);
685
+ state->object_nl = rb_gc_location(state->object_nl);
686
+ state->array_nl = rb_gc_location(state->array_nl);
594
687
  }
595
688
 
596
689
  static void State_free(void *ptr)
597
690
  {
598
691
  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
692
  ruby_xfree(state);
605
693
  }
606
694
 
607
695
  static size_t State_memsize(const void *ptr)
608
696
  {
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;
697
+ return sizeof(JSON_Generator_State);
617
698
  }
618
699
 
619
700
  #ifndef HAVE_RB_EXT_RACTOR_SAFE
@@ -623,24 +704,54 @@ static size_t State_memsize(const void *ptr)
623
704
 
624
705
  static const rb_data_type_t JSON_Generator_State_type = {
625
706
  "JSON/Generator/State",
626
- {NULL, State_free, State_memsize,},
707
+ {
708
+ .dmark = State_mark,
709
+ .dfree = State_free,
710
+ .dsize = State_memsize,
711
+ .dcompact = State_compact,
712
+ },
627
713
  0, 0,
628
714
  RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE,
629
715
  };
630
716
 
717
+ static void state_init(JSON_Generator_State *state)
718
+ {
719
+ state->max_nesting = 100;
720
+ state->buffer_initial_length = FBUFFER_INITIAL_LENGTH_DEFAULT;
721
+ }
722
+
631
723
  static VALUE cState_s_allocate(VALUE klass)
632
724
  {
633
725
  JSON_Generator_State *state;
634
726
  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;
727
+ state_init(state);
637
728
  return obj;
638
729
  }
639
730
 
731
+ static void vstate_spill(struct generate_json_data *data)
732
+ {
733
+ VALUE vstate = cState_s_allocate(cState);
734
+ GET_STATE(vstate);
735
+ MEMCPY(state, data->state, JSON_Generator_State, 1);
736
+ data->state = state;
737
+ data->vstate = vstate;
738
+ RB_OBJ_WRITTEN(vstate, Qundef, state->indent);
739
+ RB_OBJ_WRITTEN(vstate, Qundef, state->space);
740
+ RB_OBJ_WRITTEN(vstate, Qundef, state->space_before);
741
+ RB_OBJ_WRITTEN(vstate, Qundef, state->object_nl);
742
+ RB_OBJ_WRITTEN(vstate, Qundef, state->array_nl);
743
+ }
744
+
745
+ static inline VALUE vstate_get(struct generate_json_data *data)
746
+ {
747
+ if (RB_UNLIKELY(!data->vstate)) {
748
+ vstate_spill(data);
749
+ }
750
+ return data->vstate;
751
+ }
752
+
640
753
  struct hash_foreach_arg {
641
- FBuffer *buffer;
642
- JSON_Generator_State *state;
643
- VALUE Vstate;
754
+ struct generate_json_data *data;
644
755
  int iter;
645
756
  };
646
757
 
@@ -648,27 +759,32 @@ static int
648
759
  json_object_i(VALUE key, VALUE val, VALUE _arg)
649
760
  {
650
761
  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;
762
+ struct generate_json_data *data = arg->data;
763
+
764
+ FBuffer *buffer = data->buffer;
765
+ JSON_Generator_State *state = data->state;
654
766
 
655
767
  long depth = state->depth;
656
768
  int j;
657
769
 
658
770
  if (arg->iter > 0) fbuffer_append_char(buffer, ',');
659
771
  if (RB_UNLIKELY(state->object_nl)) {
660
- fbuffer_append(buffer, state->object_nl, state->object_nl_len);
772
+ fbuffer_append_str(buffer, state->object_nl);
661
773
  }
662
774
  if (RB_UNLIKELY(state->indent)) {
663
775
  for (j = 0; j < depth; j++) {
664
- fbuffer_append(buffer, state->indent, state->indent_len);
776
+ fbuffer_append_str(buffer, state->indent);
665
777
  }
666
778
  }
667
779
 
668
780
  VALUE key_to_s;
669
781
  switch(rb_type(key)) {
670
782
  case T_STRING:
671
- key_to_s = key;
783
+ if (RB_LIKELY(RBASIC_CLASS(key) == rb_cString)) {
784
+ key_to_s = key;
785
+ } else {
786
+ key_to_s = rb_funcall(key, i_to_s, 0);
787
+ }
672
788
  break;
673
789
  case T_SYMBOL:
674
790
  key_to_s = rb_sym2str(key);
@@ -678,47 +794,57 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
678
794
  break;
679
795
  }
680
796
 
681
- generate_json_string(buffer, Vstate, state, key_to_s);
682
- if (RB_UNLIKELY(state->space_before)) fbuffer_append(buffer, state->space_before, state->space_before_len);
797
+ if (RB_LIKELY(RBASIC_CLASS(key_to_s) == rb_cString)) {
798
+ generate_json_string(buffer, data, state, key_to_s);
799
+ } else {
800
+ generate_json(buffer, data, state, key_to_s);
801
+ }
802
+ if (RB_UNLIKELY(state->space_before)) fbuffer_append_str(buffer, state->space_before);
683
803
  fbuffer_append_char(buffer, ':');
684
- if (RB_UNLIKELY(state->space)) fbuffer_append(buffer, state->space, state->space_len);
685
- generate_json(buffer, Vstate, state, val);
804
+ if (RB_UNLIKELY(state->space)) fbuffer_append_str(buffer, state->space);
805
+ generate_json(buffer, data, state, val);
686
806
 
687
807
  arg->iter++;
688
808
  return ST_CONTINUE;
689
809
  }
690
810
 
691
- static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
811
+ static void generate_json_object(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
692
812
  {
693
813
  long max_nesting = state->max_nesting;
694
814
  long depth = ++state->depth;
695
815
  int j;
696
- struct hash_foreach_arg arg;
697
816
 
698
817
  if (max_nesting != 0 && depth > max_nesting) {
699
818
  rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
700
819
  }
820
+
821
+ if (RHASH_SIZE(obj) == 0) {
822
+ fbuffer_append(buffer, "{}", 2);
823
+ --state->depth;
824
+ return;
825
+ }
826
+
701
827
  fbuffer_append_char(buffer, '{');
702
828
 
703
- arg.buffer = buffer;
704
- arg.state = state;
705
- arg.Vstate = Vstate;
706
- arg.iter = 0;
829
+ struct hash_foreach_arg arg = {
830
+ .data = data,
831
+ .iter = 0,
832
+ };
707
833
  rb_hash_foreach(obj, json_object_i, (VALUE)&arg);
708
834
 
709
835
  depth = --state->depth;
710
836
  if (RB_UNLIKELY(state->object_nl)) {
711
- fbuffer_append(buffer, state->object_nl, state->object_nl_len);
837
+ fbuffer_append_str(buffer, state->object_nl);
712
838
  if (RB_UNLIKELY(state->indent)) {
713
839
  for (j = 0; j < depth; j++) {
714
- fbuffer_append(buffer, state->indent, state->indent_len);
840
+ fbuffer_append_str(buffer, state->indent);
715
841
  }
716
842
  }
717
843
  }
718
844
  fbuffer_append_char(buffer, '}');
719
845
  }
720
846
 
721
- static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
847
+ static void generate_json_array(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
722
848
  {
723
849
  long max_nesting = state->max_nesting;
724
850
  long depth = ++state->depth;
@@ -726,34 +852,39 @@ static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
726
852
  if (max_nesting != 0 && depth > max_nesting) {
727
853
  rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
728
854
  }
855
+
856
+ if (RARRAY_LEN(obj) == 0) {
857
+ fbuffer_append(buffer, "[]", 2);
858
+ --state->depth;
859
+ return;
860
+ }
861
+
729
862
  fbuffer_append_char(buffer, '[');
730
- if (RB_UNLIKELY(state->array_nl)) fbuffer_append(buffer, state->array_nl, state->array_nl_len);
863
+ if (RB_UNLIKELY(state->array_nl)) fbuffer_append_str(buffer, state->array_nl);
731
864
  for(i = 0; i < RARRAY_LEN(obj); i++) {
732
865
  if (i > 0) {
733
866
  fbuffer_append_char(buffer, ',');
734
- if (RB_UNLIKELY(state->array_nl)) fbuffer_append(buffer, state->array_nl, state->array_nl_len);
867
+ if (RB_UNLIKELY(state->array_nl)) fbuffer_append_str(buffer, state->array_nl);
735
868
  }
736
869
  if (RB_UNLIKELY(state->indent)) {
737
870
  for (j = 0; j < depth; j++) {
738
- fbuffer_append(buffer, state->indent, state->indent_len);
871
+ fbuffer_append_str(buffer, state->indent);
739
872
  }
740
873
  }
741
- generate_json(buffer, Vstate, state, RARRAY_AREF(obj, i));
874
+ generate_json(buffer, data, state, RARRAY_AREF(obj, i));
742
875
  }
743
876
  state->depth = --depth;
744
877
  if (RB_UNLIKELY(state->array_nl)) {
745
- fbuffer_append(buffer, state->array_nl, state->array_nl_len);
878
+ fbuffer_append_str(buffer, state->array_nl);
746
879
  if (RB_UNLIKELY(state->indent)) {
747
880
  for (j = 0; j < depth; j++) {
748
- fbuffer_append(buffer, state->indent, state->indent_len);
881
+ fbuffer_append_str(buffer, state->indent);
749
882
  }
750
883
  }
751
884
  }
752
885
  fbuffer_append_char(buffer, ']');
753
886
  }
754
887
 
755
- static int usascii_encindex, utf8_encindex, binary_encindex;
756
-
757
888
  static inline int enc_utf8_compatible_p(int enc_idx)
758
889
  {
759
890
  if (enc_idx == usascii_encindex) return 1;
@@ -761,30 +892,42 @@ static inline int enc_utf8_compatible_p(int enc_idx)
761
892
  return 0;
762
893
  }
763
894
 
895
+ static VALUE encode_json_string_try(VALUE str)
896
+ {
897
+ return rb_funcall(str, i_encode, 1, Encoding_UTF_8);
898
+ }
899
+
900
+ static VALUE encode_json_string_rescue(VALUE str, VALUE exception)
901
+ {
902
+ raise_generator_error_str(str, rb_funcall(exception, rb_intern("message"), 0));
903
+ return Qundef;
904
+ }
905
+
764
906
  static inline VALUE ensure_valid_encoding(VALUE str)
765
907
  {
766
908
  int encindex = RB_ENCODING_GET(str);
767
909
  VALUE utf8_string;
768
910
  if (RB_UNLIKELY(!enc_utf8_compatible_p(encindex))) {
769
911
  if (encindex == binary_encindex) {
770
- // For historical reason, we silently reinterpret binary strings as UTF-8 if it would work.
771
- // TODO: Deprecate in 2.8.0
772
- // TODO: Remove in 3.0.0
773
912
  utf8_string = rb_enc_associate_index(rb_str_dup(str), utf8_encindex);
774
913
  switch (rb_enc_str_coderange(utf8_string)) {
775
914
  case ENC_CODERANGE_7BIT:
915
+ return utf8_string;
776
916
  case ENC_CODERANGE_VALID:
917
+ // For historical reason, we silently reinterpret binary strings as UTF-8 if it would work.
918
+ // TODO: Raise in 3.0.0
919
+ rb_warn("JSON.generate: UTF-8 string passed as BINARY, this will raise an encoding error in json 3.0");
777
920
  return utf8_string;
778
921
  break;
779
922
  }
780
923
  }
781
924
 
782
- str = rb_funcall(str, i_encode, 1, Encoding_UTF_8);
925
+ str = rb_rescue(encode_json_string_try, str, encode_json_string_rescue, str);
783
926
  }
784
927
  return str;
785
928
  }
786
929
 
787
- static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
930
+ static void generate_json_string(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
788
931
  {
789
932
  obj = ensure_valid_encoding(obj);
790
933
 
@@ -802,77 +945,75 @@ static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_S
802
945
  }
803
946
  break;
804
947
  default:
805
- rb_raise(rb_path2class("JSON::GeneratorError"), "source sequence is illegal/malformed utf-8");
948
+ raise_generator_error(obj, "source sequence is illegal/malformed utf-8");
806
949
  break;
807
950
  }
808
951
  fbuffer_append_char(buffer, '"');
809
952
  }
810
953
 
811
- static void generate_json_null(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
954
+ static void generate_json_null(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
812
955
  {
813
956
  fbuffer_append(buffer, "null", 4);
814
957
  }
815
958
 
816
- static void generate_json_false(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
959
+ static void generate_json_false(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
817
960
  {
818
961
  fbuffer_append(buffer, "false", 5);
819
962
  }
820
963
 
821
- static void generate_json_true(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
964
+ static void generate_json_true(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
822
965
  {
823
966
  fbuffer_append(buffer, "true", 4);
824
967
  }
825
968
 
826
- static void generate_json_fixnum(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
969
+ static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
827
970
  {
828
971
  fbuffer_append_long(buffer, FIX2LONG(obj));
829
972
  }
830
973
 
831
- static void generate_json_bignum(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
974
+ static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
832
975
  {
833
976
  VALUE tmp = rb_funcall(obj, i_to_s, 0);
834
977
  fbuffer_append_str(buffer, tmp);
835
978
  }
836
979
 
837
980
  #ifdef RUBY_INTEGER_UNIFICATION
838
- static void generate_json_integer(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
981
+ static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
839
982
  {
840
983
  if (FIXNUM_P(obj))
841
- generate_json_fixnum(buffer, Vstate, state, obj);
984
+ generate_json_fixnum(buffer, data, state, obj);
842
985
  else
843
- generate_json_bignum(buffer, Vstate, state, obj);
986
+ generate_json_bignum(buffer, data, state, obj);
844
987
  }
845
988
  #endif
846
989
 
847
- static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
990
+ static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
848
991
  {
849
992
  double value = RFLOAT_VALUE(obj);
850
993
  char allow_nan = state->allow_nan;
851
994
  VALUE tmp = rb_funcall(obj, i_to_s, 0);
852
995
  if (!allow_nan) {
853
- if (isinf(value)) {
854
- rb_raise(eGeneratorError, "%"PRIsVALUE" not allowed in JSON", tmp);
855
- } else if (isnan(value)) {
856
- rb_raise(eGeneratorError, "%"PRIsVALUE" not allowed in JSON", tmp);
996
+ if (isinf(value) || isnan(value)) {
997
+ raise_generator_error(obj, "%"PRIsVALUE" not allowed in JSON", tmp);
857
998
  }
858
999
  }
859
1000
  fbuffer_append_str(buffer, tmp);
860
1001
  }
861
1002
 
862
- static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
1003
+ static void generate_json(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
863
1004
  {
864
1005
  VALUE tmp;
865
1006
  if (obj == Qnil) {
866
- generate_json_null(buffer, Vstate, state, obj);
1007
+ generate_json_null(buffer, data, state, obj);
867
1008
  } else if (obj == Qfalse) {
868
- generate_json_false(buffer, Vstate, state, obj);
1009
+ generate_json_false(buffer, data, state, obj);
869
1010
  } else if (obj == Qtrue) {
870
- generate_json_true(buffer, Vstate, state, obj);
1011
+ generate_json_true(buffer, data, state, obj);
871
1012
  } else if (RB_SPECIAL_CONST_P(obj)) {
872
1013
  if (RB_FIXNUM_P(obj)) {
873
- generate_json_fixnum(buffer, Vstate, state, obj);
1014
+ generate_json_fixnum(buffer, data, state, obj);
874
1015
  } else if (RB_FLONUM_P(obj)) {
875
- generate_json_float(buffer, Vstate, state, obj);
1016
+ generate_json_float(buffer, data, state, obj);
876
1017
  } else {
877
1018
  goto general;
878
1019
  }
@@ -880,63 +1021,46 @@ static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *s
880
1021
  VALUE klass = RBASIC_CLASS(obj);
881
1022
  switch (RB_BUILTIN_TYPE(obj)) {
882
1023
  case T_BIGNUM:
883
- generate_json_bignum(buffer, Vstate, state, obj);
1024
+ generate_json_bignum(buffer, data, state, obj);
884
1025
  break;
885
1026
  case T_HASH:
886
1027
  if (klass != rb_cHash) goto general;
887
- generate_json_object(buffer, Vstate, state, obj);
1028
+ generate_json_object(buffer, data, state, obj);
888
1029
  break;
889
1030
  case T_ARRAY:
890
1031
  if (klass != rb_cArray) goto general;
891
- generate_json_array(buffer, Vstate, state, obj);
1032
+ generate_json_array(buffer, data, state, obj);
892
1033
  break;
893
1034
  case T_STRING:
894
1035
  if (klass != rb_cString) goto general;
895
- generate_json_string(buffer, Vstate, state, obj);
1036
+ generate_json_string(buffer, data, state, obj);
896
1037
  break;
897
1038
  case T_FLOAT:
898
1039
  if (klass != rb_cFloat) goto general;
899
- generate_json_float(buffer, Vstate, state, obj);
1040
+ generate_json_float(buffer, data, state, obj);
900
1041
  break;
901
1042
  default:
902
1043
  general:
903
1044
  if (state->strict) {
904
- rb_raise(eGeneratorError, "%"PRIsVALUE" not allowed in JSON", CLASS_OF(obj));
1045
+ raise_generator_error(obj, "%"PRIsVALUE" not allowed in JSON", CLASS_OF(obj));
905
1046
  } else if (rb_respond_to(obj, i_to_json)) {
906
- tmp = rb_funcall(obj, i_to_json, 1, Vstate);
1047
+ tmp = rb_funcall(obj, i_to_json, 1, vstate_get(data));
907
1048
  Check_Type(tmp, T_STRING);
908
1049
  fbuffer_append_str(buffer, tmp);
909
1050
  } else {
910
1051
  tmp = rb_funcall(obj, i_to_s, 0);
911
1052
  Check_Type(tmp, T_STRING);
912
- generate_json_string(buffer, Vstate, state, tmp);
1053
+ generate_json_string(buffer, data, state, tmp);
913
1054
  }
914
1055
  }
915
1056
  }
916
1057
  }
917
1058
 
918
- static FBuffer *cState_prepare_buffer(VALUE self)
919
- {
920
- FBuffer *buffer;
921
- GET_STATE(self);
922
- buffer = fbuffer_alloc(state->buffer_initial_length);
923
-
924
- return buffer;
925
- }
926
-
927
- struct generate_json_data {
928
- FBuffer *buffer;
929
- VALUE vstate;
930
- JSON_Generator_State *state;
931
- VALUE obj;
932
- void (*func)(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj);
933
- };
934
-
935
1059
  static VALUE generate_json_try(VALUE d)
936
1060
  {
937
1061
  struct generate_json_data *data = (struct generate_json_data *)d;
938
1062
 
939
- data->func(data->buffer, data->vstate, data->state, data->obj);
1063
+ data->func(data->buffer, data, data->state, data->obj);
940
1064
 
941
1065
  return Qnil;
942
1066
  }
@@ -951,13 +1075,18 @@ static VALUE generate_json_rescue(VALUE d, VALUE exc)
951
1075
  return Qundef;
952
1076
  }
953
1077
 
954
- static VALUE cState_partial_generate(VALUE self, VALUE obj, void (*func)(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj))
1078
+ static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func, VALUE io)
955
1079
  {
956
- FBuffer *buffer = cState_prepare_buffer(self);
957
1080
  GET_STATE(self);
958
1081
 
1082
+ char stack_buffer[FBUFFER_STACK_SIZE];
1083
+ FBuffer buffer = {
1084
+ .io = RTEST(io) ? io : Qfalse,
1085
+ };
1086
+ fbuffer_stack_init(&buffer, state->buffer_initial_length, stack_buffer, FBUFFER_STACK_SIZE);
1087
+
959
1088
  struct generate_json_data data = {
960
- .buffer = buffer,
1089
+ .buffer = &buffer,
961
1090
  .vstate = self,
962
1091
  .state = state,
963
1092
  .obj = obj,
@@ -965,19 +1094,12 @@ static VALUE cState_partial_generate(VALUE self, VALUE obj, void (*func)(FBuffer
965
1094
  };
966
1095
  rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data);
967
1096
 
968
- return fbuffer_to_s(buffer);
1097
+ return fbuffer_finalize(&buffer);
969
1098
  }
970
1099
 
971
- /*
972
- * call-seq: generate(obj)
973
- *
974
- * Generates a valid JSON document from object +obj+ and returns the
975
- * result. If no valid JSON document can be created this method raises a
976
- * GeneratorError exception.
977
- */
978
- static VALUE cState_generate(VALUE self, VALUE obj)
1100
+ static VALUE cState_generate(VALUE self, VALUE obj, VALUE io)
979
1101
  {
980
- VALUE result = cState_partial_generate(self, obj, generate_json);
1102
+ VALUE result = cState_partial_generate(self, obj, generate_json, io);
981
1103
  GET_STATE(self);
982
1104
  (void)state;
983
1105
  return result;
@@ -1005,11 +1127,11 @@ static VALUE cState_init_copy(VALUE obj, VALUE orig)
1005
1127
  if (!objState) rb_raise(rb_eArgError, "unallocated JSON::State");
1006
1128
 
1007
1129
  MEMCPY(objState, origState, JSON_Generator_State, 1);
1008
- objState->indent = fstrndup(origState->indent, origState->indent_len);
1009
- objState->space = fstrndup(origState->space, origState->space_len);
1010
- objState->space_before = fstrndup(origState->space_before, origState->space_before_len);
1011
- objState->object_nl = fstrndup(origState->object_nl, origState->object_nl_len);
1012
- objState->array_nl = fstrndup(origState->array_nl, origState->array_nl_len);
1130
+ objState->indent = origState->indent;
1131
+ objState->space = origState->space;
1132
+ objState->space_before = origState->space_before;
1133
+ objState->object_nl = origState->object_nl;
1134
+ objState->array_nl = origState->array_nl;
1013
1135
  return obj;
1014
1136
  }
1015
1137
 
@@ -1039,7 +1161,18 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
1039
1161
  static VALUE cState_indent(VALUE self)
1040
1162
  {
1041
1163
  GET_STATE(self);
1042
- return state->indent ? rb_str_new(state->indent, state->indent_len) : rb_str_new2("");
1164
+ return state->indent ? state->indent : rb_str_freeze(rb_utf8_str_new("", 0));
1165
+ }
1166
+
1167
+ static VALUE string_config(VALUE config)
1168
+ {
1169
+ if (RTEST(config)) {
1170
+ Check_Type(config, T_STRING);
1171
+ if (RSTRING_LEN(config)) {
1172
+ return rb_str_new_frozen(config);
1173
+ }
1174
+ }
1175
+ return Qfalse;
1043
1176
  }
1044
1177
 
1045
1178
  /*
@@ -1049,21 +1182,8 @@ static VALUE cState_indent(VALUE self)
1049
1182
  */
1050
1183
  static VALUE cState_indent_set(VALUE self, VALUE indent)
1051
1184
  {
1052
- unsigned long len;
1053
1185
  GET_STATE(self);
1054
- Check_Type(indent, T_STRING);
1055
- len = RSTRING_LEN(indent);
1056
- if (len == 0) {
1057
- if (state->indent) {
1058
- ruby_xfree(state->indent);
1059
- state->indent = NULL;
1060
- state->indent_len = 0;
1061
- }
1062
- } else {
1063
- if (state->indent) ruby_xfree(state->indent);
1064
- state->indent = fstrndup(RSTRING_PTR(indent), len);
1065
- state->indent_len = len;
1066
- }
1186
+ RB_OBJ_WRITE(self, &state->indent, string_config(indent));
1067
1187
  return Qnil;
1068
1188
  }
1069
1189
 
@@ -1076,7 +1196,7 @@ static VALUE cState_indent_set(VALUE self, VALUE indent)
1076
1196
  static VALUE cState_space(VALUE self)
1077
1197
  {
1078
1198
  GET_STATE(self);
1079
- return state->space ? rb_str_new(state->space, state->space_len) : rb_str_new2("");
1199
+ return state->space ? state->space : rb_str_freeze(rb_utf8_str_new("", 0));
1080
1200
  }
1081
1201
 
1082
1202
  /*
@@ -1087,21 +1207,8 @@ static VALUE cState_space(VALUE self)
1087
1207
  */
1088
1208
  static VALUE cState_space_set(VALUE self, VALUE space)
1089
1209
  {
1090
- unsigned long len;
1091
1210
  GET_STATE(self);
1092
- Check_Type(space, T_STRING);
1093
- len = RSTRING_LEN(space);
1094
- if (len == 0) {
1095
- if (state->space) {
1096
- ruby_xfree(state->space);
1097
- state->space = NULL;
1098
- state->space_len = 0;
1099
- }
1100
- } else {
1101
- if (state->space) ruby_xfree(state->space);
1102
- state->space = fstrndup(RSTRING_PTR(space), len);
1103
- state->space_len = len;
1104
- }
1211
+ RB_OBJ_WRITE(self, &state->space, string_config(space));
1105
1212
  return Qnil;
1106
1213
  }
1107
1214
 
@@ -1113,7 +1220,7 @@ static VALUE cState_space_set(VALUE self, VALUE space)
1113
1220
  static VALUE cState_space_before(VALUE self)
1114
1221
  {
1115
1222
  GET_STATE(self);
1116
- return state->space_before ? rb_str_new(state->space_before, state->space_before_len) : rb_str_new2("");
1223
+ return state->space_before ? state->space_before : rb_str_freeze(rb_utf8_str_new("", 0));
1117
1224
  }
1118
1225
 
1119
1226
  /*
@@ -1123,21 +1230,8 @@ static VALUE cState_space_before(VALUE self)
1123
1230
  */
1124
1231
  static VALUE cState_space_before_set(VALUE self, VALUE space_before)
1125
1232
  {
1126
- unsigned long len;
1127
1233
  GET_STATE(self);
1128
- Check_Type(space_before, T_STRING);
1129
- len = RSTRING_LEN(space_before);
1130
- if (len == 0) {
1131
- if (state->space_before) {
1132
- ruby_xfree(state->space_before);
1133
- state->space_before = NULL;
1134
- state->space_before_len = 0;
1135
- }
1136
- } else {
1137
- if (state->space_before) ruby_xfree(state->space_before);
1138
- state->space_before = fstrndup(RSTRING_PTR(space_before), len);
1139
- state->space_before_len = len;
1140
- }
1234
+ RB_OBJ_WRITE(self, &state->space_before, string_config(space_before));
1141
1235
  return Qnil;
1142
1236
  }
1143
1237
 
@@ -1150,7 +1244,7 @@ static VALUE cState_space_before_set(VALUE self, VALUE space_before)
1150
1244
  static VALUE cState_object_nl(VALUE self)
1151
1245
  {
1152
1246
  GET_STATE(self);
1153
- return state->object_nl ? rb_str_new(state->object_nl, state->object_nl_len) : rb_str_new2("");
1247
+ return state->object_nl ? state->object_nl : rb_str_freeze(rb_utf8_str_new("", 0));
1154
1248
  }
1155
1249
 
1156
1250
  /*
@@ -1161,20 +1255,8 @@ static VALUE cState_object_nl(VALUE self)
1161
1255
  */
1162
1256
  static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
1163
1257
  {
1164
- unsigned long len;
1165
1258
  GET_STATE(self);
1166
- Check_Type(object_nl, T_STRING);
1167
- len = RSTRING_LEN(object_nl);
1168
- if (len == 0) {
1169
- if (state->object_nl) {
1170
- ruby_xfree(state->object_nl);
1171
- state->object_nl = NULL;
1172
- }
1173
- } else {
1174
- if (state->object_nl) ruby_xfree(state->object_nl);
1175
- state->object_nl = fstrndup(RSTRING_PTR(object_nl), len);
1176
- state->object_nl_len = len;
1177
- }
1259
+ RB_OBJ_WRITE(self, &state->object_nl, string_config(object_nl));
1178
1260
  return Qnil;
1179
1261
  }
1180
1262
 
@@ -1186,7 +1268,7 @@ static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
1186
1268
  static VALUE cState_array_nl(VALUE self)
1187
1269
  {
1188
1270
  GET_STATE(self);
1189
- return state->array_nl ? rb_str_new(state->array_nl, state->array_nl_len) : rb_str_new2("");
1271
+ return state->array_nl ? state->array_nl : rb_str_freeze(rb_utf8_str_new("", 0));
1190
1272
  }
1191
1273
 
1192
1274
  /*
@@ -1196,20 +1278,8 @@ static VALUE cState_array_nl(VALUE self)
1196
1278
  */
1197
1279
  static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
1198
1280
  {
1199
- unsigned long len;
1200
1281
  GET_STATE(self);
1201
- Check_Type(array_nl, T_STRING);
1202
- len = RSTRING_LEN(array_nl);
1203
- if (len == 0) {
1204
- if (state->array_nl) {
1205
- ruby_xfree(state->array_nl);
1206
- state->array_nl = NULL;
1207
- }
1208
- } else {
1209
- if (state->array_nl) ruby_xfree(state->array_nl);
1210
- state->array_nl = fstrndup(RSTRING_PTR(array_nl), len);
1211
- state->array_nl_len = len;
1212
- }
1282
+ RB_OBJ_WRITE(self, &state->array_nl, string_config(array_nl));
1213
1283
  return Qnil;
1214
1284
  }
1215
1285
 
@@ -1238,6 +1308,11 @@ static VALUE cState_max_nesting(VALUE self)
1238
1308
  return LONG2FIX(state->max_nesting);
1239
1309
  }
1240
1310
 
1311
+ static long long_config(VALUE num)
1312
+ {
1313
+ return RTEST(num) ? FIX2LONG(num) : 0;
1314
+ }
1315
+
1241
1316
  /*
1242
1317
  * call-seq: max_nesting=(depth)
1243
1318
  *
@@ -1247,8 +1322,7 @@ static VALUE cState_max_nesting(VALUE self)
1247
1322
  static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
1248
1323
  {
1249
1324
  GET_STATE(self);
1250
- Check_Type(depth, T_FIXNUM);
1251
- state->max_nesting = FIX2LONG(depth);
1325
+ state->max_nesting = long_config(depth);
1252
1326
  return Qnil;
1253
1327
  }
1254
1328
 
@@ -1376,8 +1450,7 @@ static VALUE cState_depth(VALUE self)
1376
1450
  static VALUE cState_depth_set(VALUE self, VALUE depth)
1377
1451
  {
1378
1452
  GET_STATE(self);
1379
- Check_Type(depth, T_FIXNUM);
1380
- state->depth = FIX2LONG(depth);
1453
+ state->depth = long_config(depth);
1381
1454
  return Qnil;
1382
1455
  }
1383
1456
 
@@ -1392,6 +1465,15 @@ static VALUE cState_buffer_initial_length(VALUE self)
1392
1465
  return LONG2FIX(state->buffer_initial_length);
1393
1466
  }
1394
1467
 
1468
+ static void buffer_initial_length_set(JSON_Generator_State *state, VALUE buffer_initial_length)
1469
+ {
1470
+ Check_Type(buffer_initial_length, T_FIXNUM);
1471
+ long initial_length = FIX2LONG(buffer_initial_length);
1472
+ if (initial_length > 0) {
1473
+ state->buffer_initial_length = initial_length;
1474
+ }
1475
+ }
1476
+
1395
1477
  /*
1396
1478
  * call-seq: buffer_initial_length=(length)
1397
1479
  *
@@ -1400,16 +1482,75 @@ static VALUE cState_buffer_initial_length(VALUE self)
1400
1482
  */
1401
1483
  static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_length)
1402
1484
  {
1403
- long initial_length;
1404
1485
  GET_STATE(self);
1405
- Check_Type(buffer_initial_length, T_FIXNUM);
1406
- initial_length = FIX2LONG(buffer_initial_length);
1407
- if (initial_length > 0) {
1408
- state->buffer_initial_length = initial_length;
1409
- }
1486
+ buffer_initial_length_set(state, buffer_initial_length);
1410
1487
  return Qnil;
1411
1488
  }
1412
1489
 
1490
+ static int configure_state_i(VALUE key, VALUE val, VALUE _arg)
1491
+ {
1492
+ JSON_Generator_State *state = (JSON_Generator_State *)_arg;
1493
+
1494
+ if (key == sym_indent) { state->indent = string_config(val); }
1495
+ else if (key == sym_space) { state->space = string_config(val); }
1496
+ else if (key == sym_space_before) { state->space_before = string_config(val); }
1497
+ else if (key == sym_object_nl) { state->object_nl = string_config(val); }
1498
+ else if (key == sym_array_nl) { state->array_nl = string_config(val); }
1499
+ else if (key == sym_max_nesting) { state->max_nesting = long_config(val); }
1500
+ else if (key == sym_allow_nan) { state->allow_nan = RTEST(val); }
1501
+ else if (key == sym_ascii_only) { state->ascii_only = RTEST(val); }
1502
+ else if (key == sym_depth) { state->depth = long_config(val); }
1503
+ else if (key == sym_buffer_initial_length) { buffer_initial_length_set(state, val); }
1504
+ else if (key == sym_script_safe) { state->script_safe = RTEST(val); }
1505
+ else if (key == sym_escape_slash) { state->script_safe = RTEST(val); }
1506
+ else if (key == sym_strict) { state->strict = RTEST(val); }
1507
+ return ST_CONTINUE;
1508
+ }
1509
+
1510
+ static void configure_state(JSON_Generator_State *state, VALUE config)
1511
+ {
1512
+ if (!RTEST(config)) return;
1513
+
1514
+ Check_Type(config, T_HASH);
1515
+
1516
+ if (!RHASH_SIZE(config)) return;
1517
+
1518
+ // We assume in most cases few keys are set so it's faster to go over
1519
+ // the provided keys than to check all possible keys.
1520
+ rb_hash_foreach(config, configure_state_i, (VALUE)state);
1521
+ }
1522
+
1523
+ static VALUE cState_configure(VALUE self, VALUE opts)
1524
+ {
1525
+ GET_STATE(self);
1526
+ configure_state(state, opts);
1527
+ return self;
1528
+ }
1529
+
1530
+ static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io)
1531
+ {
1532
+ JSON_Generator_State state = {0};
1533
+ state_init(&state);
1534
+ configure_state(&state, opts);
1535
+
1536
+ char stack_buffer[FBUFFER_STACK_SIZE];
1537
+ FBuffer buffer = {
1538
+ .io = RTEST(io) ? io : Qfalse,
1539
+ };
1540
+ fbuffer_stack_init(&buffer, state.buffer_initial_length, stack_buffer, FBUFFER_STACK_SIZE);
1541
+
1542
+ struct generate_json_data data = {
1543
+ .buffer = &buffer,
1544
+ .vstate = Qfalse,
1545
+ .state = &state,
1546
+ .obj = obj,
1547
+ .func = generate_json,
1548
+ };
1549
+ rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data);
1550
+
1551
+ return fbuffer_finalize(&buffer);
1552
+ }
1553
+
1413
1554
  /*
1414
1555
  *
1415
1556
  */
@@ -1426,16 +1567,18 @@ void Init_generator(void)
1426
1567
  VALUE mExt = rb_define_module_under(mJSON, "Ext");
1427
1568
  VALUE mGenerator = rb_define_module_under(mExt, "Generator");
1428
1569
 
1570
+ rb_global_variable(&eGeneratorError);
1429
1571
  eGeneratorError = rb_path2class("JSON::GeneratorError");
1572
+
1573
+ rb_global_variable(&eNestingError);
1430
1574
  eNestingError = rb_path2class("JSON::NestingError");
1431
- rb_gc_register_mark_object(eGeneratorError);
1432
- rb_gc_register_mark_object(eNestingError);
1433
1575
 
1434
1576
  cState = rb_define_class_under(mGenerator, "State", rb_cObject);
1435
1577
  rb_define_alloc_func(cState, cState_s_allocate);
1436
1578
  rb_define_singleton_method(cState, "from_state", cState_from_state_s, 1);
1437
1579
  rb_define_method(cState, "initialize", cState_initialize, -1);
1438
1580
  rb_define_alias(cState, "initialize", "initialize"); // avoid method redefinition warnings
1581
+ rb_define_private_method(cState, "_configure", cState_configure, 1);
1439
1582
 
1440
1583
  rb_define_method(cState, "initialize_copy", cState_init_copy, 1);
1441
1584
  rb_define_method(cState, "indent", cState_indent, 0);
@@ -1468,7 +1611,9 @@ void Init_generator(void)
1468
1611
  rb_define_method(cState, "depth=", cState_depth_set, 1);
1469
1612
  rb_define_method(cState, "buffer_initial_length", cState_buffer_initial_length, 0);
1470
1613
  rb_define_method(cState, "buffer_initial_length=", cState_buffer_initial_length_set, 1);
1471
- rb_define_method(cState, "generate", cState_generate, 1);
1614
+ rb_define_private_method(cState, "_generate", cState_generate, 2);
1615
+
1616
+ rb_define_singleton_method(cState, "generate", cState_m_generate, 3);
1472
1617
 
1473
1618
  VALUE mGeneratorMethods = rb_define_module_under(mGenerator, "GeneratorMethods");
1474
1619
 
@@ -1524,6 +1669,20 @@ void Init_generator(void)
1524
1669
  i_extend = rb_intern("extend");
1525
1670
  i_encode = rb_intern("encode");
1526
1671
 
1672
+ sym_indent = ID2SYM(rb_intern("indent"));
1673
+ sym_space = ID2SYM(rb_intern("space"));
1674
+ sym_space_before = ID2SYM(rb_intern("space_before"));
1675
+ sym_object_nl = ID2SYM(rb_intern("object_nl"));
1676
+ sym_array_nl = ID2SYM(rb_intern("array_nl"));
1677
+ sym_max_nesting = ID2SYM(rb_intern("max_nesting"));
1678
+ sym_allow_nan = ID2SYM(rb_intern("allow_nan"));
1679
+ sym_ascii_only = ID2SYM(rb_intern("ascii_only"));
1680
+ sym_depth = ID2SYM(rb_intern("depth"));
1681
+ sym_buffer_initial_length = ID2SYM(rb_intern("buffer_initial_length"));
1682
+ sym_script_safe = ID2SYM(rb_intern("script_safe"));
1683
+ sym_escape_slash = ID2SYM(rb_intern("escape_slash"));
1684
+ sym_strict = ID2SYM(rb_intern("strict"));
1685
+
1527
1686
  usascii_encindex = rb_usascii_encindex();
1528
1687
  utf8_encindex = rb_utf8_encindex();
1529
1688
  binary_encindex = rb_ascii8bit_encindex();