summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
authorTimothee Cour <timothee.cour2@gmail.com>2020-06-15 04:22:43 -0700
committerGitHub <noreply@github.com>2020-06-15 13:22:43 +0200
commitd51beb7b20c7670a17769b30e721fe67761f98e6 (patch)
tree8cf5004199932ce1952515365928d07004378a2d /lib
parentbf604c6829f87a551dc3b5ad836679be4ab53789 (diff)
downloadNim-d51beb7b20c7670a17769b30e721fe67761f98e6.tar.gz
make `fromJson/toJson` work with `array[range, typ]`, + 1 bugfix (#14669)
* make toJson more robust

* properly handle array
Diffstat (limited to 'lib')
-rw-r--r--lib/std/jsonutils.nim32
1 files changed, 24 insertions, 8 deletions
diff --git a/lib/std/jsonutils.nim b/lib/std/jsonutils.nim
index bfa600fa9..be3d7e7c8 100644
--- a/lib/std/jsonutils.nim
+++ b/lib/std/jsonutils.nim
@@ -2,9 +2,17 @@
 This module implements a hookable (de)serialization for arbitrary types.
 Design goal: avoid importing modules where a custom serialization is needed;
 see strtabs.fromJsonHook,toJsonHook for an example.
-
 ]##
 
+runnableExamples:
+  import std/[strtabs,json]
+  type Foo = ref object
+    t: bool
+    z1: int8
+  let a = (1.5'f32, (b: "b2", a: "a2"), 'x', @[Foo(t: true, z1: -3), nil], [{"name": "John"}.newStringTable])
+  let j = a.toJson
+  doAssert j.jsonTo(type(a)).toJson == j
+
 import std/[json,tables,strutils]
 
 #[
@@ -12,10 +20,14 @@ xxx
 use toJsonHook,fromJsonHook for Table|OrderedTable
 add Options support also using toJsonHook,fromJsonHook and remove `json=>options` dependency
 
-future direction:
-add a way to customize serialization, for eg allowing missing
-or extra fields in JsonNode, field renaming, and a way to handle cyclic references
-using a cache of already visited addresses.
+Future directions:
+add a way to customize serialization, for eg:
+* allowing missing or extra fields in JsonNode
+* field renaming
+* allow serializing `enum` and `char` as `string` instead of `int`
+  (enum is more compact/efficient, and robust to enum renamings, but string
+  is more human readable)
+* handle cyclic references, using a cache of already visited addresses
 ]#
 
 proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".}
@@ -65,8 +77,10 @@ proc fromJson*[T](a: var T, b: JsonNode) =
       fromJson(a[], b)
   elif T is array:
     checkJson a.len == b.len, $(a.len, b.len, $T)
-    for i, val in b.getElems:
-      fromJson(a[i], val)
+    var i = 0
+    for ai in mitems(a):
+      fromJson(ai, b[i])
+      i.inc
   elif T is seq:
     a.setLen b.len
     for i, val in b.getElems:
@@ -114,12 +128,14 @@ proc toJson*[T](a: T): JsonNode =
       result = newJArray()
       for v in a.fields: result.add toJson(v)
   elif T is ref | ptr:
-    if a == nil: result = newJNull()
+    if system.`==`(a, nil): result = newJNull()
     else: result = toJson(a[])
   elif T is array | seq:
     result = newJArray()
     for ai in a: result.add toJson(ai)
   elif T is pointer: result = toJson(cast[int](a))
+    # edge case: `a == nil` could've also led to `newJNull()`, but this results
+    # in simpler code for `toJson` and `fromJson`.
   elif T is distinct: result = toJson(a.distinctBase)
   elif T is bool: result = %(a)
   elif T is Ordinal: result = %(a.ord)