Skip to content

Commit

Permalink
fix nim-lang#18007: std/json now serializes nan,inf,-inf as raw strin…
Browse files Browse the repository at this point in the history
…gs instead of invalid json
  • Loading branch information
timotheecour committed May 16, 2021
1 parent 3614523 commit ba2d876
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 5 deletions.
2 changes: 2 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@
- `jsonutils` now serializes/deserializes holey enums as regular enums (via `ord`) instead of as strings.
Use `-d:nimLegacyJsonutilsHoleyEnum` for a transition period.

- `json` and `jsonutils` now serialize NaN, Inf, -Inf as "nan", "inf", "-inf", using raw strings (the same
that are used to encode numbers that can't fit in native number types).

## Standard library additions and changes
- Added support for parenthesized expressions in `strformat`
Expand Down
34 changes: 29 additions & 5 deletions lib/pure/json.nim
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,10 @@ proc `%`*(n: BiggestInt): JsonNode =

proc `%`*(n: float): JsonNode =
## Generic constructor for JSON data. Creates a new `JFloat JsonNode`.
result = JsonNode(kind: JFloat, fnum: n)
if n != n: newJRawNumber("nan")
elif n == Inf: newJRawNumber("inf")
elif n == -Inf: newJRawNumber("-inf")
else: JsonNode(kind: JFloat, fnum: n)

proc `%`*(b: bool): JsonNode =
## Generic constructor for JSON data. Creates a new `JBool JsonNode`.
Expand Down Expand Up @@ -1087,11 +1090,32 @@ when defined(nimFixedForwardGeneric):
dst = cast[T](jsonNode.num)

proc initFromJson[T: SomeFloat](dst: var T; jsonNode: JsonNode; jsonPath: var string) =
verifyJsonKind(jsonNode, {JInt, JFloat}, jsonPath)
if jsonNode.kind == JFloat:
dst = T(jsonNode.fnum)
if jsonNode.isUnquoted:
assert jsonNode.kind == JString # instead of exception, because isUnquoted is internal logic
# when nimvm:
when true:
case jsonNode.str
of "nan":
let b = NaN
dst = T(b)
# dst = NaN # would fail some tests because range conversions would cause CT error
# in some cases; but this is not a hot-spot inside this branch and backend can optimize
# this.
of "inf":
let b = Inf
dst = T(b)
of "-inf":
let b = -Inf
dst = T(b)
else: raise newException(JsonKindError, "expected 'nan|inf|-inf', got " & jsonNode.str)
else:
discard
else:
dst = T(jsonNode.num)
verifyJsonKind(jsonNode, {JInt, JFloat}, jsonPath)
if jsonNode.kind == JFloat:
dst = T(jsonNode.fnum)
else:
dst = T(jsonNode.num)

proc initFromJson[T: enum](dst: var T; jsonNode: JsonNode; jsonPath: var string) =
verifyJsonKind(jsonNode, {JString}, jsonPath)
Expand Down
6 changes: 6 additions & 0 deletions tests/stdlib/tjson.nim
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,12 @@ block: # bug #17383
testRoundtrip(int64.high): "9223372036854775807"
testRoundtrip(uint64.high): "18446744073709551615"

block: # bug #18007
testRoundtrip([NaN, Inf, -Inf, 0.0, -0.0, 1.0]): "[nan,inf,-inf,0.0,-0.0,1.0]"
# pending https://github.com/nim-lang/Nim/issues/18025 use:
# testRoundtrip([float32(NaN), Inf, -Inf, 0.0, -0.0, 1.0]): "[nan,inf,-inf,0.0,-0.0,1.0]"
let inf = float32(Inf)
testRoundtrip([float32(NaN), inf, -inf, 0.0, -0.0, 1.0]): "[nan,inf,-inf,0.0,-0.0,1.0]"

block:
let a = "18446744073709551615"
Expand Down
4 changes: 4 additions & 0 deletions tests/stdlib/tjsonutils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ template fn() =
else:
testRoundtrip(a): "[9223372036854775807,18446744073709551615]"

block: # bug #18007
testRoundtrip((NaN, Inf, -Inf, 0.0, -0.0, 1.0)): "[nan,inf,-inf,0.0,-0.0,1.0]"
testRoundtrip((float32(NaN), Inf, -Inf, 0.0, -0.0, 1.0)): "[nan,inf,-inf,0.0,-0.0,1.0]"

block: # case object
type Foo = object
x0: float
Expand Down

0 comments on commit ba2d876

Please sign in to comment.