Skip to content

Commit 3f32c47

Browse files
committed
Reimplement to_json methods in Ruby
1 parent 93bc1b3 commit 3f32c47

File tree

4 files changed

+84
-289
lines changed

4 files changed

+84
-289
lines changed

ext/json/ext/generator/generator.c

Lines changed: 40 additions & 252 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ static void generate_json_string(FBuffer *buffer, struct generate_json_data *dat
7474
static void generate_json_null(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
7575
static void generate_json_false(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
7676
static void generate_json_true(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
77-
static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
7877
static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
7978
static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
8079
static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
@@ -701,206 +700,6 @@ static void convert_UTF8_to_ASCII_only_JSON(search_state *search, const unsigned
701700
}
702701
}
703702

704-
/*
705-
* Document-module: JSON::Ext::Generator
706-
*
707-
* This is the JSON generator implemented as a C extension. It can be
708-
* configured to be used by setting
709-
*
710-
* JSON.generator = JSON::Ext::Generator
711-
*
712-
* with the method generator= in JSON.
713-
*
714-
*/
715-
716-
/* Explanation of the following: that's the only way to not pollute
717-
* standard library's docs with GeneratorMethods::<ClassName> which
718-
* are uninformative and take a large place in a list of classes
719-
*/
720-
721-
/*
722-
* Document-module: JSON::Ext::Generator::GeneratorMethods
723-
* :nodoc:
724-
*/
725-
726-
/*
727-
* Document-module: JSON::Ext::Generator::GeneratorMethods::Array
728-
* :nodoc:
729-
*/
730-
731-
/*
732-
* Document-module: JSON::Ext::Generator::GeneratorMethods::Bignum
733-
* :nodoc:
734-
*/
735-
736-
/*
737-
* Document-module: JSON::Ext::Generator::GeneratorMethods::FalseClass
738-
* :nodoc:
739-
*/
740-
741-
/*
742-
* Document-module: JSON::Ext::Generator::GeneratorMethods::Fixnum
743-
* :nodoc:
744-
*/
745-
746-
/*
747-
* Document-module: JSON::Ext::Generator::GeneratorMethods::Float
748-
* :nodoc:
749-
*/
750-
751-
/*
752-
* Document-module: JSON::Ext::Generator::GeneratorMethods::Hash
753-
* :nodoc:
754-
*/
755-
756-
/*
757-
* Document-module: JSON::Ext::Generator::GeneratorMethods::Integer
758-
* :nodoc:
759-
*/
760-
761-
/*
762-
* Document-module: JSON::Ext::Generator::GeneratorMethods::NilClass
763-
* :nodoc:
764-
*/
765-
766-
/*
767-
* Document-module: JSON::Ext::Generator::GeneratorMethods::Object
768-
* :nodoc:
769-
*/
770-
771-
/*
772-
* Document-module: JSON::Ext::Generator::GeneratorMethods::String
773-
* :nodoc:
774-
*/
775-
776-
/*
777-
* Document-module: JSON::Ext::Generator::GeneratorMethods::String::Extend
778-
* :nodoc:
779-
*/
780-
781-
/*
782-
* Document-module: JSON::Ext::Generator::GeneratorMethods::TrueClass
783-
* :nodoc:
784-
*/
785-
786-
/*
787-
* call-seq: to_json(state = nil)
788-
*
789-
* Returns a JSON string containing a JSON object, that is generated from
790-
* this Hash instance.
791-
* _state_ is a JSON::State object, that can also be used to configure the
792-
* produced JSON string output further.
793-
*/
794-
static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self)
795-
{
796-
rb_check_arity(argc, 0, 1);
797-
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
798-
return cState_partial_generate(Vstate, self, generate_json_object, Qfalse);
799-
}
800-
801-
/*
802-
* call-seq: to_json(state = nil)
803-
*
804-
* Returns a JSON string containing a JSON array, that is generated from
805-
* this Array instance.
806-
* _state_ is a JSON::State object, that can also be used to configure the
807-
* produced JSON string output further.
808-
*/
809-
static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self)
810-
{
811-
rb_check_arity(argc, 0, 1);
812-
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
813-
return cState_partial_generate(Vstate, self, generate_json_array, Qfalse);
814-
}
815-
816-
/*
817-
* call-seq: to_json(*)
818-
*
819-
* Returns a JSON string representation for this Integer number.
820-
*/
821-
static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self)
822-
{
823-
rb_check_arity(argc, 0, 1);
824-
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
825-
return cState_partial_generate(Vstate, self, generate_json_integer, Qfalse);
826-
}
827-
828-
/*
829-
* call-seq: to_json(*)
830-
*
831-
* Returns a JSON string representation for this Float number.
832-
*/
833-
static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self)
834-
{
835-
rb_check_arity(argc, 0, 1);
836-
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
837-
return cState_partial_generate(Vstate, self, generate_json_float, Qfalse);
838-
}
839-
840-
/*
841-
* call-seq: to_json(*)
842-
*
843-
* This string should be encoded with UTF-8 A call to this method
844-
* returns a JSON string encoded with UTF16 big endian characters as
845-
* \u????.
846-
*/
847-
static VALUE mString_to_json(int argc, VALUE *argv, VALUE self)
848-
{
849-
rb_check_arity(argc, 0, 1);
850-
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
851-
return cState_partial_generate(Vstate, self, generate_json_string, Qfalse);
852-
}
853-
854-
/*
855-
* call-seq: to_json(*)
856-
*
857-
* Returns a JSON string for true: 'true'.
858-
*/
859-
static VALUE mTrueClass_to_json(int argc, VALUE *argv, VALUE self)
860-
{
861-
rb_check_arity(argc, 0, 1);
862-
return rb_utf8_str_new("true", 4);
863-
}
864-
865-
/*
866-
* call-seq: to_json(*)
867-
*
868-
* Returns a JSON string for false: 'false'.
869-
*/
870-
static VALUE mFalseClass_to_json(int argc, VALUE *argv, VALUE self)
871-
{
872-
rb_check_arity(argc, 0, 1);
873-
return rb_utf8_str_new("false", 5);
874-
}
875-
876-
/*
877-
* call-seq: to_json(*)
878-
*
879-
* Returns a JSON string for nil: 'null'.
880-
*/
881-
static VALUE mNilClass_to_json(int argc, VALUE *argv, VALUE self)
882-
{
883-
rb_check_arity(argc, 0, 1);
884-
return rb_utf8_str_new("null", 4);
885-
}
886-
887-
/*
888-
* call-seq: to_json(*)
889-
*
890-
* Converts this object to a string (calling #to_s), converts
891-
* it to a JSON string, and returns the result. This is a fallback, if no
892-
* special method #to_json was defined for some object.
893-
*/
894-
static VALUE mObject_to_json(int argc, VALUE *argv, VALUE self)
895-
{
896-
VALUE state;
897-
VALUE string = rb_funcall(self, i_to_s, 0);
898-
rb_scan_args(argc, argv, "01", &state);
899-
Check_Type(string, T_STRING);
900-
state = cState_from_state_s(cState, state);
901-
return cState_partial_generate(state, string, generate_json_string, Qfalse);
902-
}
903-
904703
static void State_mark(void *ptr)
905704
{
906705
JSON_Generator_State *state = ptr;
@@ -1348,14 +1147,6 @@ static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *dat
13481147
fbuffer_append_str(buffer, StringValue(tmp));
13491148
}
13501149

1351-
static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
1352-
{
1353-
if (FIXNUM_P(obj))
1354-
generate_json_fixnum(buffer, data, obj);
1355-
else
1356-
generate_json_bignum(buffer, data, obj);
1357-
}
1358-
13591150
static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
13601151
{
13611152
double value = RFLOAT_VALUE(obj);
@@ -1399,7 +1190,7 @@ static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *d
13991190
fbuffer_append_str(buffer, fragment);
14001191
}
14011192

1402-
static void generate_json(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
1193+
static inline void generate_json_general(FBuffer *buffer, struct generate_json_data *data, VALUE obj, bool fallback)
14031194
{
14041195
bool as_json_called = false;
14051196
start:
@@ -1426,15 +1217,15 @@ static void generate_json(FBuffer *buffer, struct generate_json_data *data, VALU
14261217
generate_json_bignum(buffer, data, obj);
14271218
break;
14281219
case T_HASH:
1429-
if (klass != rb_cHash) goto general;
1220+
if (fallback && klass != rb_cHash) goto general;
14301221
generate_json_object(buffer, data, obj);
14311222
break;
14321223
case T_ARRAY:
1433-
if (klass != rb_cArray) goto general;
1224+
if (fallback && klass != rb_cArray) goto general;
14341225
generate_json_array(buffer, data, obj);
14351226
break;
14361227
case T_STRING:
1437-
if (klass != rb_cString) goto general;
1228+
if (fallback && klass != rb_cString) goto general;
14381229

14391230
if (RB_LIKELY(valid_json_string_p(obj))) {
14401231
raw_generate_json_string(buffer, data, obj);
@@ -1450,7 +1241,7 @@ static void generate_json(FBuffer *buffer, struct generate_json_data *data, VALU
14501241
generate_json_symbol(buffer, data, obj);
14511242
break;
14521243
case T_FLOAT:
1453-
if (klass != rb_cFloat) goto general;
1244+
if (fallback && klass != rb_cFloat) goto general;
14541245
generate_json_float(buffer, data, obj);
14551246
break;
14561247
case T_STRUCT:
@@ -1474,6 +1265,16 @@ static void generate_json(FBuffer *buffer, struct generate_json_data *data, VALU
14741265
}
14751266
}
14761267

1268+
static void generate_json(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
1269+
{
1270+
generate_json_general(buffer, data, obj, true);
1271+
}
1272+
1273+
static void generate_json_no_fallback(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
1274+
{
1275+
generate_json_general(buffer, data, obj, false);
1276+
}
1277+
14771278
static VALUE generate_json_try(VALUE d)
14781279
{
14791280
struct generate_json_data *data = (struct generate_json_data *)d;
@@ -1491,7 +1292,7 @@ static VALUE generate_json_ensure(VALUE d)
14911292
return Qundef;
14921293
}
14931294

1494-
static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func, VALUE io)
1295+
static inline VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func, VALUE io)
14951296
{
14961297
GET_STATE(self);
14971298

@@ -1509,9 +1310,7 @@ static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func,
15091310
.obj = obj,
15101311
.func = func
15111312
};
1512-
VALUE result = rb_ensure(generate_json_try, (VALUE)&data, generate_json_ensure, (VALUE)&data);
1513-
RB_GC_GUARD(self);
1514-
return result;
1313+
return rb_ensure(generate_json_try, (VALUE)&data, generate_json_ensure, (VALUE)&data);
15151314
}
15161315

15171316
/* call-seq:
@@ -1530,6 +1329,15 @@ static VALUE cState_generate(int argc, VALUE *argv, VALUE self)
15301329
return cState_partial_generate(self, obj, generate_json, io);
15311330
}
15321331

1332+
/* :nodoc: */
1333+
static VALUE cState_generate_no_fallback(int argc, VALUE *argv, VALUE self)
1334+
{
1335+
rb_check_arity(argc, 1, 2);
1336+
VALUE obj = argv[0];
1337+
VALUE io = argc > 1 ? argv[1] : Qnil;
1338+
return cState_partial_generate(self, obj, generate_json_no_fallback, io);
1339+
}
1340+
15331341
static VALUE cState_initialize(int argc, VALUE *argv, VALUE self)
15341342
{
15351343
rb_warn("The json gem extension was loaded with the stdlib ruby code. You should upgrade rubygems with `gem update --system`");
@@ -2028,7 +1836,7 @@ static VALUE cState_configure(VALUE self, VALUE opts)
20281836
return self;
20291837
}
20301838

2031-
static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io)
1839+
static VALUE cState_m_do_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io, generator_func func)
20321840
{
20331841
JSON_Generator_State state = {0};
20341842
state_init(&state);
@@ -2046,14 +1854,21 @@ static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io)
20461854
.state = &state,
20471855
.depth = state.depth,
20481856
.obj = obj,
2049-
.func = generate_json,
1857+
.func = func,
20501858
};
20511859
return rb_ensure(generate_json_try, (VALUE)&data, generate_json_ensure, (VALUE)&data);
20521860
}
20531861

2054-
/*
2055-
*
2056-
*/
1862+
static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io)
1863+
{
1864+
return cState_m_do_generate(klass, obj, opts, io, generate_json);
1865+
}
1866+
1867+
static VALUE cState_m_generate_no_fallback(VALUE klass, VALUE obj, VALUE opts, VALUE io)
1868+
{
1869+
return cState_m_do_generate(klass, obj, opts, io, generate_json_no_fallback);
1870+
}
1871+
20571872
void Init_generator(void)
20581873
{
20591874
#ifdef HAVE_RB_EXT_RACTOR_SAFE
@@ -2118,39 +1933,12 @@ void Init_generator(void)
21181933
rb_define_method(cState, "buffer_initial_length", cState_buffer_initial_length, 0);
21191934
rb_define_method(cState, "buffer_initial_length=", cState_buffer_initial_length_set, 1);
21201935
rb_define_method(cState, "generate", cState_generate, -1);
1936+
rb_define_method(cState, "_generate_no_fallback", cState_generate_no_fallback, -1);
21211937

21221938
rb_define_private_method(cState, "allow_duplicate_key?", cState_allow_duplicate_key_p, 0);
21231939

21241940
rb_define_singleton_method(cState, "generate", cState_m_generate, 3);
2125-
2126-
VALUE mGeneratorMethods = rb_define_module_under(mGenerator, "GeneratorMethods");
2127-
2128-
VALUE mObject = rb_define_module_under(mGeneratorMethods, "Object");
2129-
rb_define_method(mObject, "to_json", mObject_to_json, -1);
2130-
2131-
VALUE mHash = rb_define_module_under(mGeneratorMethods, "Hash");
2132-
rb_define_method(mHash, "to_json", mHash_to_json, -1);
2133-
2134-
VALUE mArray = rb_define_module_under(mGeneratorMethods, "Array");
2135-
rb_define_method(mArray, "to_json", mArray_to_json, -1);
2136-
2137-
VALUE mInteger = rb_define_module_under(mGeneratorMethods, "Integer");
2138-
rb_define_method(mInteger, "to_json", mInteger_to_json, -1);
2139-
2140-
VALUE mFloat = rb_define_module_under(mGeneratorMethods, "Float");
2141-
rb_define_method(mFloat, "to_json", mFloat_to_json, -1);
2142-
2143-
VALUE mString = rb_define_module_under(mGeneratorMethods, "String");
2144-
rb_define_method(mString, "to_json", mString_to_json, -1);
2145-
2146-
VALUE mTrueClass = rb_define_module_under(mGeneratorMethods, "TrueClass");
2147-
rb_define_method(mTrueClass, "to_json", mTrueClass_to_json, -1);
2148-
2149-
VALUE mFalseClass = rb_define_module_under(mGeneratorMethods, "FalseClass");
2150-
rb_define_method(mFalseClass, "to_json", mFalseClass_to_json, -1);
2151-
2152-
VALUE mNilClass = rb_define_module_under(mGeneratorMethods, "NilClass");
2153-
rb_define_method(mNilClass, "to_json", mNilClass_to_json, -1);
1941+
rb_define_singleton_method(cState, "_generate_no_fallback", cState_m_generate_no_fallback, 3);
21541942

21551943
rb_global_variable(&Encoding_UTF_8);
21561944
Encoding_UTF_8 = rb_const_get(rb_path2class("Encoding"), rb_intern("UTF_8"));

0 commit comments

Comments
 (0)