summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--lib/pure/json.nim17
-rw-r--r--tests/stdlib/tjsonmacro.nim36
2 files changed, 49 insertions, 4 deletions
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index 1ef08f547..23b23b4a4 100644
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -1369,11 +1369,20 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode =
           for `forLoopI` in 0 ..< `jsonNode`.len: list[`forLoopI`] =`constructorNode`;
           list
         )
-
+    of "tuple":
+      let typeNode = getTypeImpl(typeSym)
+      result = createConstructor(typeNode, jsonNode)
     else:
-      # Generic type.
+      # Generic type or some `seq[T]` alias
       let obj = getType(typeSym)
-      result = processType(typeSym, obj, jsonNode, false)
+      case obj.kind
+      of nnkBracketExpr:
+        # probably a `seq[T]` alias
+        let typeNode = getTypeImpl(typeSym)
+        result = createConstructor(typeNode, jsonNode)
+      else:
+        # generic type
+        result = processType(typeSym, obj, jsonNode, false)
   of nnkSym:
     # Handle JsonNode.
     if ($typeSym).cmpIgnoreStyle("jsonnode") == 0:
@@ -1385,7 +1394,7 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode =
     if typeNode.typeKind == ntyDistinct:
       result = createConstructor(typeNode, jsonNode)
     elif obj.kind == nnkBracketExpr:
-      # When `Sym "Foo"` turns out to be a `ref object`.
+      # When `Sym "Foo"` turns out to be a `ref object` or `tuple`
       result = createConstructor(obj, jsonNode)
     else:
       result = processType(typeSym, obj, jsonNode, false)
diff --git a/tests/stdlib/tjsonmacro.nim b/tests/stdlib/tjsonmacro.nim
index 0521d558c..85530065d 100644
--- a/tests/stdlib/tjsonmacro.nim
+++ b/tests/stdlib/tjsonmacro.nim
@@ -517,6 +517,42 @@ when true:
       doAssert v.name == "smith"
       doAssert MyRef(w).name == "smith"
 
+# bug #12015
+# The definition of the `%` proc needs to be here, since the `% c` calls below
+# can only find our custom `%` proc for `Pix` if defined in global scope.
+type
+  Pix = tuple[x, y: uint8, ch: uint16]
+proc `%`(p: Pix): JsonNode =
+  result = %* { "x" : % p.x,
+                "y" : % p.y,
+                "ch" : % p.ch }
+block:
+  type
+    Cluster = object
+      works: tuple[x, y: uint8, ch: uint16] # working
+      fails: Pix # previously broken
+
+  let data = (x: 123'u8, y: 53'u8, ch: 1231'u16)
+  let c = Cluster(works: data, fails: data)
+  let cFromJson = (% c).to(Cluster)
+  doAssert c == cFromJson
+
+block:
+  # bug related to #12015
+  type
+    PixInt = tuple[x, y, ch: int]
+    SomePix = Pix | PixInt
+    Cluster[T: SomePix] = seq[T]
+    ClusterObject[T: SomePix] = object
+      data: Cluster[T]
+    RecoEvent[T: SomePix] = object
+      cluster: seq[ClusterObject[T]]
+
+  let data = @[(x: 123'u8, y: 53'u8, ch: 1231'u16)]
+  var c = RecoEvent[Pix](cluster: @[ClusterObject[Pix](data: data)])
+  let cFromJson = (% c).to(RecoEvent[Pix])
+  doAssert c == cFromJson
+
 # TODO: when the issue with the limeted vm registers is solved, the
 # exact same test as above should be evaluated at compile time as
 # well, to ensure that the vm functionality won't diverge from the