Skip to content

Commit

Permalink
properly fix nim-lang#13196: json serialialization lossless roundtrip
Browse files Browse the repository at this point in the history
  • Loading branch information
timotheecour committed Feb 8, 2020
1 parent e441542 commit 78a6c84
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 6 deletions.
13 changes: 11 additions & 2 deletions lib/pure/json.nim
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ type
of JArray:
elems*: seq[JsonNode]

const floatSerializationPrecision = 18

proc newJString*(s: string): JsonNode =
## Creates a new `JString JsonNode`.
result = JsonNode(kind: JString, str: s)
Expand Down Expand Up @@ -647,7 +649,7 @@ proc toPretty(result: var string, node: JsonNode, indent = 2, ml = true,
if lstArr: result.indent(currIndent)
# Fixme: implement new system.add ops for the JS target
when defined(js): result.add($node.fnum)
else: result.addFloat(node.fnum)
else: result.addFloat(node.fnum, precision = floatSerializationPrecision)
of JBool:
if lstArr: result.indent(currIndent)
result.add(if node.bval: "true" else: "false")
Expand Down Expand Up @@ -726,7 +728,7 @@ proc toUgly*(result: var string, node: JsonNode) =
else: result.addInt(node.num)
of JFloat:
when defined(js): result.add($node.fnum)
else: result.addFloat(node.fnum)
else: result.addFloat(node.fnum, precision = floatSerializationPrecision)
of JBool:
result.add(if node.bval: "true" else: "false")
of JNull:
Expand Down Expand Up @@ -1486,3 +1488,10 @@ when isMainModule:
doAssert not isRefSkipDistinct(MyObject)
doAssert isRefSkipDistinct(MyDistinct)
doAssert isRefSkipDistinct(MyOtherDistinct)

# issue #13196
# some arbitrary float, not caring about actually significant places here
let x = 0.12345678901234567890123456789
let y = ($(%* x)).parseJson().getFloat()
doAssert x == y
doAssert $0.6 == "0.6"
6 changes: 4 additions & 2 deletions lib/system/formatfloat.nim
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ proc writeToBuffer(buf: var array[65, char]; value: cstring) =
buf[i] = value[i]
inc i

proc writeFloatToBuffer*(buf: var array[65, char]; value: BiggestFloat): int =
proc writeFloatToBuffer*(buf: var array[65, char]; value: BiggestFloat, precision: static int = -1): int =
## This is the implementation to format floats in the Nim
## programming language. The specific format for floating point
## numbers is not specified in the Nim programming language and
Expand All @@ -29,7 +29,9 @@ proc writeFloatToBuffer*(buf: var array[65, char]; value: BiggestFloat): int =
## * `buf` - A buffer to write into. The buffer does not need to be
## initialized and it will be overridden.
##
var n: int = c_sprintf(addr buf, "%.16g", value)
const precision2 = if precision == -1: 16 else: precision
const format = "%." & $precision2 & "g"
var n: int = c_sprintf(addr buf, format, value)
var hasDot = false
for i in 0..n-1:
if buf[i] == ',':
Expand Down
5 changes: 3 additions & 2 deletions lib/system/strmantle.nim
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,9 @@ proc addCstringN(result: var string, buf: cstring; buflen: int) =

import formatfloat

proc addFloat*(result: var string; x: float) =
proc addFloat*(result: var string; x: float, precision: static int = -1) =
## Converts float to its string representation and appends it to `result`.
## passing `precision >=0 ` can override the default precision.
##
## .. code-block:: Nim
## var
Expand All @@ -95,7 +96,7 @@ proc addFloat*(result: var string; x: float) =
result.add $x
else:
var buffer: array[65, char]
let n = writeFloatToBuffer(buffer, x)
let n = writeFloatToBuffer(buffer, x, precision = precision)
result.addCstringN(cstring(buffer[0].addr), n)

proc add*(result: var string; x: float) {.deprecated:
Expand Down

0 comments on commit 78a6c84

Please sign in to comment.