| ... | @@ -33,6 +33,9 @@ pub const StringifyOptions = struct { | ... | @@ -33,6 +33,9 @@ pub const StringifyOptions = struct { |
| 33 | | 33 | |
| 34 | /// Should unicode characters be escaped in strings? | 34 | /// Should unicode characters be escaped in strings? |
| 35 | escape_unicode: bool = false, | 35 | escape_unicode: bool = false, |
| | 36 | |
| | 37 | /// When true, renders numbers outside the range `+-1<<53` (the precise integer range of f64) as JSON strings in base 10. |
| | 38 | emit_nonportable_numbers_as_strings: bool = false, |
| 36 | }; | 39 | }; |
| 37 | | 40 | |
| 38 | /// Writes the given value to the `std.io.Writer` stream. | 41 | /// Writes the given value to the `std.io.Writer` stream. |
| ... | @@ -161,7 +164,7 @@ pub fn writeStreamArbitraryDepth( | ... | @@ -161,7 +164,7 @@ pub fn writeStreamArbitraryDepth( |
| 161 | /// * Zig `bool` -> JSON `true` or `false`. | 164 | /// * Zig `bool` -> JSON `true` or `false`. |
| 162 | /// * Zig `?T` -> `null` or the rendering of `T`. | 165 | /// * Zig `?T` -> `null` or the rendering of `T`. |
| 163 | /// * Zig `i32`, `u64`, etc. -> JSON number or string. | 166 | /// * Zig `i32`, `u64`, etc. -> JSON number or string. |
| 164 | /// * If the value is outside the range `±1<<53` (the precise integer rage of f64), it is rendered as a JSON string in base 10. Otherwise, it is rendered as JSON number. | 167 | /// * When option `emit_nonportable_numbers_as_strings` is true, if the value is outside the range `+-1<<53` (the precise integer range of f64), it is rendered as a JSON string in base 10. Otherwise, it is rendered as JSON number. |
| 165 | /// * Zig floats -> JSON number or string. | 168 | /// * Zig floats -> JSON number or string. |
| 166 | /// * If the value cannot be precisely represented by an f64, it is rendered as a JSON string. Otherwise, it is rendered as JSON number. | 169 | /// * If the value cannot be precisely represented by an f64, it is rendered as a JSON string. Otherwise, it is rendered as JSON number. |
| 167 | /// * TODO: Float rendering will likely change in the future, e.g. to remove the unnecessary "e+00". | 170 | /// * TODO: Float rendering will likely change in the future, e.g. to remove the unnecessary "e+00". |
| ... | @@ -399,21 +402,15 @@ pub fn WriteStream( | ... | @@ -399,21 +402,15 @@ pub fn WriteStream( |
| 399 | pub fn write(self: *Self, value: anytype) Error!void { | 402 | pub fn write(self: *Self, value: anytype) Error!void { |
| 400 | const T = @TypeOf(value); | 403 | const T = @TypeOf(value); |
| 401 | switch (@typeInfo(T)) { | 404 | switch (@typeInfo(T)) { |
| 402 | .Int => |info| { | 405 | .Int => { |
| 403 | if (info.bits < 53) { | 406 | try self.valueStart(); |
| 404 | try self.valueStart(); | 407 | if (self.options.emit_nonportable_numbers_as_strings and |
| 405 | try self.stream.print("{}", .{value}); | 408 | (value <= -(1 << 53) or value >= (1 << 53))) |
| 406 | self.valueDone(); | 409 | { |
| 407 | return; | 410 | try self.stream.print("\"{}\"", .{value}); |
| 408 | } | 411 | } else { |
| 409 | if (value < 4503599627370496 and (info.signedness == .unsigned or value > -4503599627370496)) { | | |
| 410 | try self.valueStart(); | | |
| 411 | try self.stream.print("{}", .{value}); | 412 | try self.stream.print("{}", .{value}); |
| 412 | self.valueDone(); | | |
| 413 | return; | | |
| 414 | } | 413 | } |
| 415 | try self.valueStart(); | | |
| 416 | try self.stream.print("\"{}\"", .{value}); | | |
| 417 | self.valueDone(); | 414 | self.valueDone(); |
| 418 | return; | 415 | return; |
| 419 | }, | 416 | }, |