changeset 1470:63364723d460 default tip

fix: make de-/serialization work with all kinds of weird object configurtions
author sam <sam@basx.dev>
date Wed, 02 Apr 2025 00:49:02 +0700
parents c69bb7c58cf2
children
files semicongine/storage.nim tests/test_storage.nim
diffstat 2 files changed, 56 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/semicongine/storage.nim	Tue Apr 01 00:26:49 2025 +0700
+++ b/semicongine/storage.nim	Wed Apr 02 00:49:02 2025 +0700
@@ -115,25 +115,43 @@
     )
   )
 
-proc writeValue[T: object | tuple](s: Stream, data: T)
-proc writeValue[T](s: Stream, value: openArray[T])
+proc writeValue[T](s: Stream, value: T)
 
-proc writeValue[T: SomeOrdinal | SomeFloat](s: Stream, value: T) =
+proc writeNumericValue[T](s: Stream, value: T) =
   s.write(value)
 
-proc writeValue(s: Stream, value: string) =
+proc writeStringValue(s: Stream, value: string) =
   s.write(value.len.int32)
   s.write(value)
 
-proc writeValue[T](s: Stream, value: openArray[T]) =
+proc writeSeqValue[T](s: Stream, value: T) =
   s.write(value.len.int32)
-  for v in value:
-    writeValue(s, v)
+  for i in 0 ..< value.len:
+    writeValue(s, value[i])
 
-proc writeValue[T: object | tuple](s: Stream, data: T) =
+proc writeArrayValue[T](s: Stream, value: T) =
+  s.write(value.len.int32)
+  for i in 0 ..< value.len:
+    writeValue(s, value[genericParams(distinctBase(T)).get(0)(i)])
+
+proc writeObjectValue[T](s: Stream, data: T) =
   for field, value in data.fieldPairs():
     writeValue(s, value)
 
+proc writeValue[T](s: Stream, value: T) =
+  when distinctBase(T) is SomeOrdinal or T is SomeFloat:
+    writeNumericValue[T](s, value)
+  elif distinctBase(T) is seq:
+    writeSeqValue[T](s, value)
+  elif distinctBase(T) is array:
+    writeArrayValue[T](s, value)
+  elif distinctBase(T) is string:
+    writeStringValue(s, value)
+  elif distinctBase(T) is object or T is tuple:
+    writeObjectValue[T](s, value)
+  else:
+    {.error: "Cannot load type " & $T.}
+
 proc storeWorld*[T](
     worldName: string, data: T, table = DEFAULT_WORLD_TABLE_NAME, deleteOld = false
 ) =
@@ -155,45 +173,47 @@
   if deleteOld:
     db.exec(sql(&"""DELETE FROM {table} WHERE key <> ?"""), key)
 
-proc loadNumericValue[T: SomeOrdinal | SomeFloat](s: Stream): T =
+proc loadValue[T](s: Stream): T
+
+proc loadNumericValue[T](s: Stream): T =
   read(s, result)
 
-proc loadSeqValue[T: seq](s: Stream): T =
+proc loadSeqValue[T](s: Stream): T =
   var len: int32
   read(s, len)
-  for i in 0 ..< len:
-    var v: elementType(result)
-    read(s, v)
-    result.add v
+  result.setLen(len)
+  for i in 0 ..< int(len):
+    # var v: elementType(result)
+    # read(s, v)
+    result[i] = loadValue[elementType(result)](s)
 
-proc loadArrayValue[T: array](s: Stream): T =
+proc loadArrayValue[T](s: Stream): T =
   var len: int32
   read(s, len)
   doAssert len == len(result)
-  for i in 0 ..< len:
-    read(s, result[i])
+  for i in 0 .. high(distinctBase(T)):
+    read(s, result[genericParams(distinctBase(T)).get(0)(i)])
 
 proc loadStringValue(s: Stream): string =
   var len: int32
   read(s, len)
   readStr(s, len)
 
-proc loadValue[T](s: Stream): T
-
-proc loadObjectValue[T: object | tuple](s: Stream): T =
+proc loadObjectValue[T](s: Stream): T =
   for field, value in result.fieldPairs():
-    value = loadValue[typeof(value)](s)
+    {.cast(uncheckedAssign).}:
+      value = loadValue[typeof(value)](s)
 
 proc loadValue[T](s: Stream): T =
-  when T is SomeOrdinal or T is SomeFloat:
+  when distinctBase(T) is SomeOrdinal or distinctBase(T) is SomeFloat:
     loadNumericValue[T](s)
-  elif T is seq:
+  elif distinctBase(T) is seq:
     loadSeqValue[T](s)
-  elif T is array:
+  elif distinctBase(T) is array:
     loadArrayValue[T](s)
-  elif T is string:
+  elif distinctBase(T) is string:
     loadStringValue(s)
-  elif T is object or T is tuple:
+  elif distinctBase(T) is object or distinctBase(T) is tuple:
     loadObjectValue[T](s)
   else:
     {.error: "Cannot load type " & $T.}
--- a/tests/test_storage.nim	Tue Apr 01 00:26:49 2025 +0700
+++ b/tests/test_storage.nim	Wed Apr 02 00:49:02 2025 +0700
@@ -14,9 +14,14 @@
   store(storage, KEY, TEST_VALUE)
   assert storage.load(KEY, 0) == TEST_VALUE
 
+type ID = distinct int
+proc `==`(a, b: ID): bool =
+  `==`(int(a), int(b))
+
 proc testWorldAPI() =
   type Obj1 = object
     value: int
+    id: ID
 
   type Obj2 = object
     a: string
@@ -27,16 +32,18 @@
 
   assert listWorlds().len == 0
 
-  const obj1 = Obj1(value: 42)
+  const obj1 = Obj1(value: 42, id: ID(1))
   "testWorld".storeWorld(obj1)
   assert listWorlds() == @["testWorld"]
   assert loadWorld[Obj1]("testWorld") == obj1
 
   const obj2 = Obj2(
     a: "Hello world",
-    b: Obj1(value: 20),
+    b: Obj1(value: 20, id: ID(20)),
     c: @[1, 2, 3, 4],
-    d: [Obj1(value: 1), Obj1(value: 2), Obj1(value: 3)],
+    d: [
+      Obj1(value: 1, id: ID(11)), Obj1(value: 2, id: ID(22)), Obj1(value: 3, id: ID(33))
+    ],
     e: true,
   )
   "testWorld".storeWorld(obj2)