From 9e8773e579ecb7b1f107586793fba97e265a58ae Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 15 Mar 2021 16:37:35 -0700 Subject: [PATCH] fix #17383: json.%,to and jsonutils.formJson,toJson now works with uint|uint64 --- lib/pure/json.nim | 22 ++++++++++++++++++---- lib/std/jsonutils.nim | 2 ++ tests/stdlib/tjson.nim | 16 ++++++++++++++++ tests/stdlib/tjsonutils.nim | 10 ++++++++++ 4 files changed, 46 insertions(+), 4 deletions(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 51d4bb8151337..3d4a7a1ff54b7 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -304,7 +304,10 @@ proc `%`*(s: string): JsonNode = proc `%`*(n: uint): JsonNode = ## Generic constructor for JSON data. Creates a new `JInt JsonNode`. - result = JsonNode(kind: JInt, num: BiggestInt(n)) + if n > static(BiggestUInt(BiggestInt.high)): + result = newJRawNumber($n) + else: + result = JsonNode(kind: JInt, num: BiggestInt(n)) proc `%`*(n: int): JsonNode = ## Generic constructor for JSON data. Creates a new `JInt JsonNode`. @@ -312,7 +315,10 @@ proc `%`*(n: int): JsonNode = proc `%`*(n: BiggestUInt): JsonNode = ## Generic constructor for JSON data. Creates a new `JInt JsonNode`. - result = JsonNode(kind: JInt, num: BiggestInt(n)) + if n > static(BiggestUInt(BiggestInt.high)): + result = newJRawNumber($n) + else: + result = JsonNode(kind: JInt, num: BiggestInt(n)) proc `%`*(n: BiggestInt): JsonNode = ## Generic constructor for JSON data. Creates a new `JInt JsonNode`. @@ -1055,8 +1061,16 @@ when defined(nimFixedForwardGeneric): dst = jsonNode.copy proc initFromJson[T: SomeInteger](dst: var T; jsonNode: JsonNode, jsonPath: var string) = - verifyJsonKind(jsonNode, {JInt}, jsonPath) - dst = T(jsonNode.num) + when T is uint|uint64: + case jsonNode.kind + of JString: + dst = T(parseBiggestUint(jsonNode.str)) + else: + verifyJsonKind(jsonNode, {JInt}, jsonPath) + dst = T(jsonNode.num) + else: + verifyJsonKind(jsonNode, {JInt}, jsonPath) + dst = T(jsonNode.num) proc initFromJson[T: SomeFloat](dst: var T; jsonNode: JsonNode; jsonPath: var string) = verifyJsonKind(jsonNode, {JInt, JFloat}, jsonPath) diff --git a/lib/std/jsonutils.nim b/lib/std/jsonutils.nim index bbe6a7cd4fee8..77b1f92a74bb5 100644 --- a/lib/std/jsonutils.nim +++ b/lib/std/jsonutils.nim @@ -187,6 +187,7 @@ proc fromJson*[T](a: var T, b: JsonNode, opt = Joptions()) = of JInt: a = T(b.getBiggestInt()) of JString: a = parseEnum[T](b.getStr()) else: checkJson false, $($T, " ", b) + elif T is uint|uint64: a = T(to(b, uint64)) elif T is Ordinal: a = T(to(b, int)) elif T is pointer: a = cast[pointer](to(b, int)) elif T is distinct: @@ -270,6 +271,7 @@ proc toJson*[T](a: T): JsonNode = # in simpler code for `toJson` and `fromJson`. elif T is distinct: result = toJson(a.distinctBase) elif T is bool: result = %(a) + elif T is SomeInteger: result = %a elif T is Ordinal: result = %(a.ord) else: result = %a diff --git a/tests/stdlib/tjson.nim b/tests/stdlib/tjson.nim index 5508509ba0b79..e19beba9255e9 100644 --- a/tests/stdlib/tjson.nim +++ b/tests/stdlib/tjson.nim @@ -9,6 +9,11 @@ Note: Macro tests are in tests/stdlib/tjsonmacro.nim import std/[json,parsejson,strutils,streams] +proc testRoundtrip[T](t: T, expected: string) = + let j = %t + doAssert $j == expected, $j + doAssert %(j.to(T)) == j + let testJson = parseJson"""{ "a": [1, 2, 3, 4], "b": "asd", "c": "\ud83c\udf83", "d": "\u00E6"}""" # nil passthrough doAssert(testJson{"doesnt_exist"}{"anything"}.isNil) @@ -281,3 +286,14 @@ let jsonNode = %*mynode doAssert $jsonNode == """{"kind":"P","pChildren":[{"kind":"Text","textStr":"mychild"},{"kind":"Br"}]}""" doAssert $jsonNode.to(ContentNode) == """(kind: P, pChildren: @[(kind: Text, textStr: "mychild"), (kind: Br)])""" +block: # bug #17383 + testRoundtrip(int32.high): "2147483647" + testRoundtrip(uint32.high): "4294967295" + when int.sizeof == 4: + testRoundtrip(int.high): "2147483647" + testRoundtrip(uint.high): "4294967295" + else: + testRoundtrip(int.high): "9223372036854775807" + testRoundtrip(uint.high): "18446744073709551615" + testRoundtrip(int64.high): "9223372036854775807" + testRoundtrip(uint64.high): "18446744073709551615" diff --git a/tests/stdlib/tjsonutils.nim b/tests/stdlib/tjsonutils.nim index beb12d5ae0f06..88711815f02f8 100644 --- a/tests/stdlib/tjsonutils.nim +++ b/tests/stdlib/tjsonutils.nim @@ -67,6 +67,16 @@ template fn() = doAssert b2.ord == 1 # explains the `1` testRoundtrip(a): """[1,2,3]""" + block: # bug #17383 + let a = (int32.high, uint32.high, int64.high, uint64.high) + testRoundtrip(a): "[2147483647,4294967295,9223372036854775807,18446744073709551615]" + testRoundtrip(a): "[2147483647,4294967295,9223372036854775807,18446744073709551615]" + let b = (int.high, uint.high) + when int.sizeof == 4: + testRoundtrip(b): "[2147483647,4294967295]" + else: + testRoundtrip(b): "[9223372036854775807,18446744073709551615]" + block: # case object type Foo = object x0: float