Skip to content

Commit b4bfbca

Browse files
etiennebarriebyroot
authored andcommitted
Optimize Symbol generation in strict mode
Co-authored-by: Jean Boussier <[email protected]>
1 parent f865148 commit b4bfbca

File tree

3 files changed

+40
-10
lines changed

3 files changed

+40
-10
lines changed

ext/json/generator/generator.c

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -991,6 +991,29 @@ static void generate_json_string(FBuffer *buffer, struct generate_json_data *dat
991991
fbuffer_append_char(buffer, '"');
992992
}
993993

994+
static void generate_json_fallback(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
995+
{
996+
VALUE tmp;
997+
if (rb_respond_to(obj, i_to_json)) {
998+
tmp = rb_funcall(obj, i_to_json, 1, vstate_get(data));
999+
Check_Type(tmp, T_STRING);
1000+
fbuffer_append_str(buffer, tmp);
1001+
} else {
1002+
tmp = rb_funcall(obj, i_to_s, 0);
1003+
Check_Type(tmp, T_STRING);
1004+
generate_json_string(buffer, data, state, tmp);
1005+
}
1006+
}
1007+
1008+
static inline void generate_json_symbol(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
1009+
{
1010+
if (state->strict) {
1011+
generate_json_string(buffer, data, state, rb_sym2str(obj));
1012+
} else {
1013+
generate_json_fallback(buffer, data, state, obj);
1014+
}
1015+
}
1016+
9941017
static void generate_json_null(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
9951018
{
9961019
fbuffer_append(buffer, "null", 4);
@@ -1057,7 +1080,6 @@ static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *d
10571080

10581081
static void generate_json(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
10591082
{
1060-
VALUE tmp;
10611083
bool as_json_called = false;
10621084
start:
10631085
if (obj == Qnil) {
@@ -1071,6 +1093,8 @@ static void generate_json(FBuffer *buffer, struct generate_json_data *data, JSON
10711093
generate_json_fixnum(buffer, data, state, obj);
10721094
} else if (RB_FLONUM_P(obj)) {
10731095
generate_json_float(buffer, data, state, obj);
1096+
} else if (RB_STATIC_SYM_P(obj)) {
1097+
generate_json_symbol(buffer, data, state, obj);
10741098
} else {
10751099
goto general;
10761100
}
@@ -1092,6 +1116,9 @@ static void generate_json(FBuffer *buffer, struct generate_json_data *data, JSON
10921116
if (klass != rb_cString) goto general;
10931117
generate_json_string(buffer, data, state, obj);
10941118
break;
1119+
case T_SYMBOL:
1120+
generate_json_symbol(buffer, data, state, obj);
1121+
break;
10951122
case T_FLOAT:
10961123
if (klass != rb_cFloat) goto general;
10971124
generate_json_float(buffer, data, state, obj);
@@ -1110,14 +1137,8 @@ static void generate_json(FBuffer *buffer, struct generate_json_data *data, JSON
11101137
} else {
11111138
raise_generator_error(obj, "%"PRIsVALUE" not allowed in JSON", CLASS_OF(obj));
11121139
}
1113-
} else if (rb_respond_to(obj, i_to_json)) {
1114-
tmp = rb_funcall(obj, i_to_json, 1, vstate_get(data));
1115-
Check_Type(tmp, T_STRING);
1116-
fbuffer_append_str(buffer, tmp);
11171140
} else {
1118-
tmp = rb_funcall(obj, i_to_s, 0);
1119-
Check_Type(tmp, T_STRING);
1120-
generate_json_string(buffer, data, state, tmp);
1141+
generate_json_fallback(buffer, data, state, obj);
11211142
}
11221143
}
11231144
}

ext/json/lib/json/add/symbol.rb

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,13 @@ def as_json(*)
3636
#
3737
# # {"json_class":"Symbol","s":"foo"}
3838
#
39-
def to_json(*a)
40-
as_json.to_json(*a)
39+
def to_json(state = nil, *a)
40+
state = ::JSON::State.from_state(state)
41+
if state.strict?
42+
super
43+
else
44+
as_json.to_json(state, *a)
45+
end
4146
end
4247

4348
# See #as_json.

test/json/json_generator_test.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ def test_dump_strict
8686

8787
assert_equal '42', dump(42, strict: true)
8888
assert_equal 'true', dump(true, strict: true)
89+
90+
assert_equal '"hello"', dump(:hello, strict: true)
91+
assert_equal '"hello"', :hello.to_json(strict: true)
92+
assert_equal '"World"', "World".to_json(strict: true)
8993
end
9094

9195
def test_generate_pretty

0 commit comments

Comments
 (0)