json 2.7.4 → 2.8.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES.md +25 -0
- data/README.md +8 -77
- data/ext/json/ext/fbuffer/fbuffer.h +85 -47
- data/ext/json/ext/generator/generator.c +367 -216
- data/ext/json/ext/parser/extconf.rb +5 -27
- data/ext/json/ext/parser/parser.c +1536 -474
- data/ext/json/ext/parser/parser.rl +717 -243
- data/json.gemspec +4 -1
- data/lib/json/add/bigdecimal.rb +1 -1
- data/lib/json/common.rb +200 -54
- data/lib/json/ext/generator/state.rb +1 -31
- data/lib/json/ext.rb +2 -4
- data/lib/json/{pure → truffle_ruby}/generator.rb +165 -124
- data/lib/json/version.rb +1 -1
- data/lib/json.rb +15 -20
- metadata +4 -8
- data/ext/json/ext/generator/generator.h +0 -129
- data/ext/json/ext/parser/parser.h +0 -60
- data/lib/json/pure/parser.rb +0 -331
- data/lib/json/pure.rb +0 -16
@@ -1,5 +1,27 @@
|
|
1
|
+
#include "ruby.h"
|
1
2
|
#include "../fbuffer/fbuffer.h"
|
2
|
-
|
3
|
+
|
4
|
+
#include <math.h>
|
5
|
+
#include <ctype.h>
|
6
|
+
|
7
|
+
/* ruby api and some helpers */
|
8
|
+
|
9
|
+
typedef struct JSON_Generator_StateStruct {
|
10
|
+
VALUE indent;
|
11
|
+
VALUE space;
|
12
|
+
VALUE space_before;
|
13
|
+
VALUE object_nl;
|
14
|
+
VALUE array_nl;
|
15
|
+
|
16
|
+
long max_nesting;
|
17
|
+
long depth;
|
18
|
+
long buffer_initial_length;
|
19
|
+
|
20
|
+
bool allow_nan;
|
21
|
+
bool ascii_only;
|
22
|
+
bool script_safe;
|
23
|
+
bool strict;
|
24
|
+
} JSON_Generator_State;
|
3
25
|
|
4
26
|
#ifndef RB_UNLIKELY
|
5
27
|
#define RB_UNLIKELY(cond) (cond)
|
@@ -8,6 +30,46 @@
|
|
8
30
|
static VALUE mJSON, cState, mString_Extend, eGeneratorError, eNestingError, Encoding_UTF_8;
|
9
31
|
|
10
32
|
static ID i_to_s, i_to_json, i_new, i_pack, i_unpack, i_create_id, i_extend, i_encode;
|
33
|
+
static ID sym_indent, sym_space, sym_space_before, sym_object_nl, sym_array_nl, sym_max_nesting, sym_allow_nan,
|
34
|
+
sym_ascii_only, sym_depth, sym_buffer_initial_length, sym_script_safe, sym_escape_slash, sym_strict;
|
35
|
+
|
36
|
+
|
37
|
+
#define GET_STATE_TO(self, state) \
|
38
|
+
TypedData_Get_Struct(self, JSON_Generator_State, &JSON_Generator_State_type, state)
|
39
|
+
|
40
|
+
#define GET_STATE(self) \
|
41
|
+
JSON_Generator_State *state; \
|
42
|
+
GET_STATE_TO(self, state)
|
43
|
+
|
44
|
+
struct generate_json_data;
|
45
|
+
|
46
|
+
typedef void (*generator_func)(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
47
|
+
|
48
|
+
struct generate_json_data {
|
49
|
+
FBuffer *buffer;
|
50
|
+
VALUE vstate;
|
51
|
+
JSON_Generator_State *state;
|
52
|
+
VALUE obj;
|
53
|
+
generator_func func;
|
54
|
+
};
|
55
|
+
|
56
|
+
static VALUE cState_from_state_s(VALUE self, VALUE opts);
|
57
|
+
static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func);
|
58
|
+
static void generate_json(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
59
|
+
static void generate_json_object(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
60
|
+
static void generate_json_array(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
61
|
+
static void generate_json_string(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
62
|
+
static void generate_json_null(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
63
|
+
static void generate_json_false(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
64
|
+
static void generate_json_true(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
65
|
+
#ifdef RUBY_INTEGER_UNIFICATION
|
66
|
+
static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
67
|
+
#endif
|
68
|
+
static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
69
|
+
static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
70
|
+
static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
71
|
+
|
72
|
+
static int usascii_encindex, utf8_encindex, binary_encindex;
|
11
73
|
|
12
74
|
/* Converts in_string to a JSON string (without the wrapping '"'
|
13
75
|
* characters) in FBuffer out_buffer.
|
@@ -44,9 +106,6 @@ static void convert_UTF8_to_JSON(FBuffer *out_buffer, VALUE str, const char esca
|
|
44
106
|
|
45
107
|
if (RB_UNLIKELY(ch_len)) {
|
46
108
|
switch (ch_len) {
|
47
|
-
case 0:
|
48
|
-
pos++;
|
49
|
-
break;
|
50
109
|
case 1: {
|
51
110
|
FLUSH_POS(1);
|
52
111
|
switch (ch) {
|
@@ -59,8 +118,8 @@ static void convert_UTF8_to_JSON(FBuffer *out_buffer, VALUE str, const char esca
|
|
59
118
|
case '\r': fbuffer_append(out_buffer, "\\r", 2); break;
|
60
119
|
case '\t': fbuffer_append(out_buffer, "\\t", 2); break;
|
61
120
|
default: {
|
62
|
-
scratch[2] =
|
63
|
-
scratch[3] =
|
121
|
+
scratch[2] = '0';
|
122
|
+
scratch[3] = '0';
|
64
123
|
scratch[4] = hexdig[(ch >> 4) & 0xf];
|
65
124
|
scratch[5] = hexdig[ch & 0xf];
|
66
125
|
fbuffer_append(out_buffer, scratch, 6);
|
@@ -181,8 +240,8 @@ static void convert_ASCII_to_JSON(FBuffer *out_buffer, VALUE str, const char esc
|
|
181
240
|
case '\r': fbuffer_append(out_buffer, "\\r", 2); break;
|
182
241
|
case '\t': fbuffer_append(out_buffer, "\\t", 2); break;
|
183
242
|
default:
|
184
|
-
scratch[2] =
|
185
|
-
scratch[3] =
|
243
|
+
scratch[2] = '0';
|
244
|
+
scratch[3] = '0';
|
186
245
|
scratch[4] = hexdig[(ch >> 4) & 0xf];
|
187
246
|
scratch[5] = hexdig[ch & 0xf];
|
188
247
|
fbuffer_append(out_buffer, scratch, 6);
|
@@ -217,9 +276,6 @@ static void convert_UTF8_to_ASCII_only_JSON(FBuffer *out_buffer, VALUE str, cons
|
|
217
276
|
|
218
277
|
if (RB_UNLIKELY(ch_len)) {
|
219
278
|
switch (ch_len) {
|
220
|
-
case 0:
|
221
|
-
pos++;
|
222
|
-
break;
|
223
279
|
case 1: {
|
224
280
|
FLUSH_POS(1);
|
225
281
|
switch (ch) {
|
@@ -232,8 +288,8 @@ static void convert_UTF8_to_ASCII_only_JSON(FBuffer *out_buffer, VALUE str, cons
|
|
232
288
|
case '\r': fbuffer_append(out_buffer, "\\r", 2); break;
|
233
289
|
case '\t': fbuffer_append(out_buffer, "\\t", 2); break;
|
234
290
|
default: {
|
235
|
-
scratch[2] =
|
236
|
-
scratch[3] =
|
291
|
+
scratch[2] = '0';
|
292
|
+
scratch[3] = '0';
|
237
293
|
scratch[4] = hexdig[(ch >> 4) & 0xf];
|
238
294
|
scratch[5] = hexdig[ch & 0xf];
|
239
295
|
fbuffer_append(out_buffer, scratch, 6);
|
@@ -303,14 +359,6 @@ static void convert_UTF8_to_ASCII_only_JSON(FBuffer *out_buffer, VALUE str, cons
|
|
303
359
|
RB_GC_GUARD(str);
|
304
360
|
}
|
305
361
|
|
306
|
-
static char *fstrndup(const char *ptr, unsigned long len) {
|
307
|
-
char *result;
|
308
|
-
if (len <= 0) return NULL;
|
309
|
-
result = ALLOC_N(char, len);
|
310
|
-
memcpy(result, ptr, len);
|
311
|
-
return result;
|
312
|
-
}
|
313
|
-
|
314
362
|
/*
|
315
363
|
* Document-module: JSON::Ext::Generator
|
316
364
|
*
|
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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,
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
{
|
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
|
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
|
-
|
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
|
-
|
635
|
-
|
636
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
665
|
-
|
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))
|
668
|
-
generate_json(buffer,
|
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,
|
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
|
687
|
-
|
688
|
-
|
689
|
-
|
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
|
-
|
812
|
+
fbuffer_append_str(buffer, state->object_nl);
|
695
813
|
if (RB_UNLIKELY(state->indent)) {
|
696
814
|
for (j = 0; j < depth; j++) {
|
697
|
-
|
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,
|
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))
|
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))
|
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
|
-
|
846
|
+
fbuffer_append_str(buffer, state->indent);
|
722
847
|
}
|
723
848
|
}
|
724
|
-
generate_json(buffer,
|
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
|
-
|
853
|
+
fbuffer_append_str(buffer, state->array_nl);
|
729
854
|
if (RB_UNLIKELY(state->indent)) {
|
730
855
|
for (j = 0; j < depth; j++) {
|
731
|
-
|
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,
|
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,
|
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,
|
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,
|
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,
|
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,
|
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,
|
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,
|
948
|
+
generate_json_fixnum(buffer, data, state, obj);
|
825
949
|
else
|
826
|
-
generate_json_bignum(buffer,
|
950
|
+
generate_json_bignum(buffer, data, state, obj);
|
827
951
|
}
|
828
952
|
#endif
|
829
|
-
|
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,
|
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,
|
973
|
+
generate_json_null(buffer, data, state, obj);
|
849
974
|
} else if (obj == Qfalse) {
|
850
|
-
generate_json_false(buffer,
|
975
|
+
generate_json_false(buffer, data, state, obj);
|
851
976
|
} else if (obj == Qtrue) {
|
852
|
-
generate_json_true(buffer,
|
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,
|
980
|
+
generate_json_fixnum(buffer, data, state, obj);
|
856
981
|
} else if (RB_FLONUM_P(obj)) {
|
857
|
-
generate_json_float(buffer,
|
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,
|
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,
|
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,
|
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,
|
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,
|
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,
|
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,
|
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
|
-
|
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 =
|
989
|
-
objState->space =
|
990
|
-
objState->space_before =
|
991
|
-
objState->object_nl =
|
992
|
-
objState->array_nl =
|
1105
|
+
objState->indent = origState->indent;
|
1106
|
+
objState->space = origState->space;
|
1107
|
+
objState->space_before = origState->space_before;
|
1108
|
+
objState->object_nl = origState->object_nl;
|
1109
|
+
objState->array_nl = origState->array_nl;
|
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 ?
|
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
|
-
|
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 ?
|
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
|
-
|
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 ?
|
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
|
-
|
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 ?
|
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
|
-
|
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 ?
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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();
|