11#include "ruby.h"
22#include "../fbuffer/fbuffer.h"
3+ #include "../vendor/fpconv.c"
34
45#include <math.h>
56#include <ctype.h>
@@ -1054,8 +1055,9 @@ static void generate_json_float(FBuffer *buffer, struct generate_json_data *data
10541055{
10551056 double value = RFLOAT_VALUE (obj );
10561057 char allow_nan = state -> allow_nan ;
1057- if (!allow_nan ) {
1058- if (isinf (value ) || isnan (value )) {
1058+ if (isinf (value ) || isnan (value )) {
1059+ /* for NaN and Infinity values we either raise an error or rely on Float#to_s. */
1060+ if (!allow_nan ) {
10591061 if (state -> strict && state -> as_json ) {
10601062 VALUE casted_obj = rb_proc_call_with_block (state -> as_json , 1 , & obj , Qnil );
10611063 if (casted_obj != obj ) {
@@ -1067,8 +1069,24 @@ static void generate_json_float(FBuffer *buffer, struct generate_json_data *data
10671069 }
10681070 raise_generator_error (obj , "%" PRIsVALUE " not allowed in JSON" , rb_funcall (obj , i_to_s , 0 ));
10691071 }
1072+
1073+ VALUE tmp = rb_funcall (obj , i_to_s , 0 );
1074+ fbuffer_append_str (buffer , tmp );
1075+ return ;
10701076 }
1071- fbuffer_append_str (buffer , rb_funcall (obj , i_to_s , 0 ));
1077+
1078+ /* This implementation writes directly into the buffer. We reserve
1079+ * the 24 characters that fpconv_dtoa states as its maximum, plus
1080+ * 2 more characters for the potential ".0" suffix.
1081+ */
1082+ fbuffer_inc_capa (buffer , 26 );
1083+ char * d = buffer -> ptr + buffer -> len ;
1084+ int len = fpconv_dtoa (value , d );
1085+
1086+ /* fpconv_dtoa converts a float to its shortest string representation,
1087+ * but it adds a ".0" if this is a plain integer.
1088+ */
1089+ buffer -> len += len ;
10721090}
10731091
10741092static void generate_json_fragment (FBuffer * buffer , struct generate_json_data * data , JSON_Generator_State * state , VALUE obj )
0 commit comments