diff --git a/ext/rapidjson/encoder.hh b/ext/rapidjson/encoder.hh index 53cd592..319bdb2 100644 --- a/ext/rapidjson/encoder.hh +++ b/ext/rapidjson/encoder.hh @@ -60,19 +60,14 @@ class RubyObjectEncoder { } void encode_bignum(VALUE b) { - b = rb_big_norm(b); - if (FIXNUM_P(b)) { - return encode_fixnum(b); - } - - bool negative = rb_big_cmp(b, INT2FIX(0)) == INT2FIX(-1); - if (negative) { - long long ll = rb_big2ll(b); - writer.Int64(ll); - } else { - unsigned long long ull = rb_big2ull(b); - writer.Uint64(ull); - } + // Some T_BIGNUM might be small enough to fit in long long or unsigned long long + // but this being the slow path, it's not really worth it. + VALUE str = rb_funcall(b, id_to_s, 0); + Check_Type(str, T_STRING); + + // We should be able to use RawNumber here, but it's buggy + // https://github.com/Tencent/rapidjson/issues/852 + writer.RawValue(RSTRING_PTR(str), RSTRING_LEN(str), kNumberType); } void encode_float(VALUE v) { diff --git a/test/test_encoder.rb b/test/test_encoder.rb index 60cfe6a..75b8a8f 100644 --- a/test/test_encoder.rb +++ b/test/test_encoder.rb @@ -33,6 +33,10 @@ def test_encode_bignum assert_equal "18446744073709551615", encode(2**64 - 1) end + def test_encore_arbitrary_size_num + assert_equal "340282366920938463463374607431768211456", encode(2**128) + end + def test_encode_fixnum_exponents tests = [] 0.upto(65) do |exponent|