diff options
author | konsumlamm <44230978+konsumlamm@users.noreply.github.com> | 2021-01-22 19:52:34 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-22 19:52:34 +0100 |
commit | d2b218b80aeff3b98f76ff15be47d7632246015e (patch) | |
tree | b1e635798d9be95a249d24412ed2b65266a8e7e2 | |
parent | 18b983d7e3525787d0d0c5e767f62dab67e9329f (diff) | |
download | Nim-d2b218b80aeff3b98f76ff15be47d7632246015e.tar.gz |
Improve the marshal module (#16777)
* Improve marshal Use runnableExamples Refactor tests * Readd {.inheritable.} test Apply suggestions
-rw-r--r-- | lib/pure/marshal.nim | 134 | ||||
-rw-r--r-- | tests/stdlib/tmarshal.nim | 179 |
2 files changed, 113 insertions, 200 deletions
diff --git a/lib/pure/marshal.nim b/lib/pure/marshal.nim index e74e68b05..e6c40254b 100644 --- a/lib/pure/marshal.nim +++ b/lib/pure/marshal.nim @@ -10,39 +10,32 @@ ## This module contains procs for `serialization`:idx: and `deserialization`:idx: ## of arbitrary Nim data structures. The serialization format uses `JSON`:idx:. ## -## **Restriction**: For objects their type is **not** serialized. This means +## **Restriction**: For objects, their type is **not** serialized. This means ## essentially that it does not work if the object has some other runtime ## type than its compiletime type. ## ## ## Basic usage ## =========== -## -## .. code-block:: nim -## -## type -## A = object of RootObj -## B = object of A -## f: int -## -## var -## a: ref A -## b: ref B -## -## new(b) -## a = b -## echo($$a[]) # produces "{}", not "{f: 0}" -## -## # unmarshal -## let c = to[B]("""{"f": 2}""") -## assert typeof(c) is B -## assert c.f == 2 -## -## # marshal -## let s = $$c -## assert s == """{"f": 2}""" -## -## **Note**: The ``to`` and ``$$`` operations are available at compile-time! + +runnableExamples: + type + A = object of RootObj + B = object of A + f: int + + let a: ref A = new(B) + assert $$a[] == "{}" # not "{f: 0}" + + # unmarshal + let c = to[B]("""{"f": 2}""") + assert typeof(c) is B + assert c.f == 2 + + # marshal + assert $$c == """{"f": 2}""" + +## **Note**: The `to` and `$$` operations are available at compile-time! ## ## ## See also @@ -61,7 +54,7 @@ Please use alternative packages for serialization. It is possible to reimplement this module using generics and type traits. Please contribute a new implementation.""".} -import streams, typeinfo, json, intsets, tables, unicode +import std/[streams, typeinfo, json, intsets, tables, unicode] proc ptrToInt(x: pointer): int {.inline.} = result = cast[int](x) # don't skip alignment @@ -279,7 +272,8 @@ proc loadAny(s: Stream, a: Any, t: var Table[BiggestInt, pointer]) = proc load*[T](s: Stream, data: var T) = ## Loads `data` from the stream `s`. Raises `IOError` in case of an error. runnableExamples: - import marshal, streams + import std/streams + var s = newStringStream("[1, 3, 5]") var a: array[3, int] load(s, a) @@ -291,7 +285,8 @@ proc load*[T](s: Stream, data: var T) = proc store*[T](s: Stream, data: T) = ## Stores `data` into the stream `s`. Raises `IOError` in case of an error. runnableExamples: - import marshal, streams + import std/streams + var s = newStringStream("") var a = [1, 3, 5] store(s, a) @@ -306,7 +301,8 @@ proc store*[T](s: Stream, data: T) = proc `$$`*[T](x: T): string = ## Returns a string representation of `x` (serialization, marshalling). ## - ## **Note:** to serialize `x` to JSON use `$(%x)` from the ``json`` module. + ## **Note:** to serialize `x` to JSON use `%x` from the `json` module + ## or `jsonutils.toJson(x)`. runnableExamples: type Foo = object @@ -325,7 +321,7 @@ proc `$$`*[T](x: T): string = result = s.data proc to*[T](data: string): T = - ## Reads data and transforms it to a type ``T`` (deserialization, unmarshalling). + ## Reads data and transforms it to a type `T` (deserialization, unmarshalling). runnableExamples: type Foo = object @@ -341,77 +337,3 @@ proc to*[T](data: string): T = var tab = initTable[BiggestInt, pointer]() loadAny(newStringStream(data), toAny(result), tab) - - -when not defined(testing) and isMainModule: - template testit(x: untyped) = echo($$to[typeof(x)]($$x)) - - var x: array[0..4, array[0..4, string]] = [ - ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], - ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], - ["test", "1", "2", "3", "4"]] - testit(x) - var test2: tuple[name: string, s: uint] = ("tuple test", 56u) - testit(test2) - - type - TE = enum - blah, blah2 - - TestObj = object - test, asd: int - case test2: TE - of blah: - help: string - else: - nil - - PNode = ref Node - Node = object - next, prev: PNode - data: string - - proc buildList(): PNode = - new(result) - new(result.next) - new(result.prev) - result.data = "middle" - result.next.data = "next" - result.prev.data = "prev" - result.next.next = result.prev - result.next.prev = result - result.prev.next = result - result.prev.prev = result.next - - var test3: TestObj - test3.test = 42 - test3 = TestObj(test2: blah) - testit(test3) - - var test4: ref tuple[a, b: string] - new(test4) - test4.a = "ref string test: A" - test4.b = "ref string test: B" - testit(test4) - - var test5 = @[(0, 1), (2, 3), (4, 5)] - testit(test5) - - var test6: set[char] = {'A'..'Z', '_'} - testit(test6) - - var test7 = buildList() - echo($$test7) - testit(test7) - - type - A {.inheritable.} = object - B = object of A - f: int - - var - a: ref A - b: ref B - new(b) - a = b - echo($$a[]) # produces "{}", not "{f: 0}" diff --git a/tests/stdlib/tmarshal.nim b/tests/stdlib/tmarshal.nim index d76be73f3..7d4dee4f0 100644 --- a/tests/stdlib/tmarshal.nim +++ b/tests/stdlib/tmarshal.nim @@ -1,32 +1,15 @@ -discard """ - output: '''{"age": 12, "bio": "Я Cletus", "blob": [65, 66, 67, 128], "name": "Cletus"} -true -true -alpha 100 -omega 200 -Some(null) -None[JsonNode] -(numeric: "") -hello world -''' -joinable: false -""" - -#[ -joinable: false pending https://github.com/nim-lang/Nim/issues/9754 -]# - -import marshal - -template testit(x) = discard $$to[typeof(x)]($$x) - -var x: array[0..4, array[0..4, string]] = [ - ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], - ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], - ["test", "1", "2", "3", "4"]] -testit(x) -var test2: tuple[name: string, s: int] = ("tuple test", 56) -testit(test2) +import std/marshal + +# TODO: add static tests + +proc testit[T](x: T): string = $$to[T]($$x) + +let test1: array[0..1, array[0..4, string]] = [ + ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"]] +doAssert testit(test1) == + """[["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"]]""" +let test2: tuple[name: string, s: int] = ("tuple test", 56) +doAssert testit(test2) == """{"Field0": "tuple test", "Field1": 56}""" type TE = enum @@ -57,87 +40,86 @@ proc buildList(): PNode = result.prev.next = result result.prev.prev = result.next -var test3: TestObj -test3.test = 42 -test3.test2 = blah -testit(test3) +let test3 = TestObj(test: 42, test2: blah) +doAssert testit(test3) == + """{"test": 42, "asd": 0, "test2": "blah", "help": ""}""" var test4: ref tuple[a, b: string] new(test4) test4.a = "ref string test: A" test4.b = "ref string test: B" -testit(test4) +discard testit(test4) # serialization uses the pointer address, which is not consistent -var test5 = @[(0,1),(2,3),(4,5)] -testit(test5) +let test5 = @[(0,1),(2,3),(4,5)] +doAssert testit(test5) == + """[{"Field0": 0, "Field1": 1}, {"Field0": 2, "Field1": 3}, {"Field0": 4, "Field1": 5}]""" -var test7 = buildList() -testit(test7) +let test6: set[char] = {'A'..'Z', '_'} +doAssert testit(test6) == + """[65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 95]""" -var test6: set[char] = {'A'..'Z', '_'} -testit(test6) +let test7 = buildList() +discard testit(test7) # serialization uses the pointer address, which is not consistent # bug #1352 +block: + type + Entity = object of RootObj + name: string + + Person = object of Entity + age: int + bio: string + blob: string + + let instance1 = Person(name: "Cletus", age: 12, + bio: "Я Cletus", + blob: "ABC\x80") + doAssert $$instance1 == """{"age": 12, "bio": "Я Cletus", "blob": [65, 66, 67, 128], "name": "Cletus"}""" + doAssert to[Person]($$instance1).bio == instance1.bio + doAssert to[Person]($$instance1).blob == instance1.blob + +# bug #5757 +block: + type + Something = object + x: string + y: int -type - Entity = object of RootObj - name: string - - Person = object of Entity - age: int - bio: string - blob: string - -var instance1 = Person(name: "Cletus", age: 12, - bio: "Я Cletus", - blob: "ABC\x80") -echo($$instance1) -echo(to[Person]($$instance1).bio == instance1.bio) # true -echo(to[Person]($$instance1).blob == instance1.blob) # true - -# bug 5757 - -type - Something = object - x: string - y: int - -var data1 = """{"x": "alpha", "y": 100}""" -var data2 = """{"x": "omega", "y": 200}""" - -var r = to[Something](data1) - -echo r.x, " ", r.y - -r = to[Something](data2) - -echo r.x, " ", r.y + let data1 = """{"x": "alpha", "y": 100}""" + let data2 = """{"x": "omega", "y": 200}""" + var r = to[Something](data1) + doAssert $r.x & " " & $r.y == "alpha 100" + r = to[Something](data2) + doAssert $r.x & " " & $r.y == "omega 200" -type - Foo = object - a1: string - a2: string - a3: seq[string] - a4: seq[int] - a5: seq[int] - a6: seq[int] -var foo = Foo(a2: "", a4: @[], a6: @[1]) -foo.a6.setLen 0 -doAssert $$foo == """{"a1": "", "a2": "", "a3": [], "a4": [], "a5": [], "a6": []}""" -testit(foo) - -import options, json +block: + type + Foo = object + a1: string + a2: string + a3: seq[string] + a4: seq[int] + a5: seq[int] + a6: seq[int] + var foo = Foo(a2: "", a4: @[], a6: @[1]) + foo.a6.setLen 0 + doAssert $$foo == """{"a1": "", "a2": "", "a3": [], "a4": [], "a5": [], "a6": []}""" + doAssert testit(foo) == """{"a1": "", "a2": "", "a3": [], "a4": [], "a5": [], "a6": []}""" + +import std/[options, json] # bug #15934 block: let a1 = some(newJNull()) a2 = none(JsonNode) - echo ($$a1).to[:Option[JsonNode]] - echo ($$a2).to[:Option[JsonNode]] - + doAssert $($$a1).to[:Option[JsonNode]] == "Some(null)" + doAssert $($$a2).to[:Option[JsonNode]] == "None[JsonNode]" + doAssert ($$a1).to[:Option[JsonNode]] == some(newJNull()) + doAssert ($$a2).to[:Option[JsonNode]] == none(JsonNode) # bug #15620 block: @@ -148,10 +130,19 @@ block: numeric: string let test = to[LegacyEntry](str) - echo test + doAssert $test == """(numeric: "")""" # bug #16022 block: - let p: proc () = proc () = echo "hello world" - let poc = (to[typeof(p)]($$p)) - poc() + let p: proc (): string = proc (): string = "hello world" + let poc = to[typeof(p)]($$p) + doAssert poc() == "hello world" + +block: + type + A {.inheritable.} = object + B = object of A + f: int + + let a: ref A = new(B) + doAssert $$a[] == "{}" # not "{f: 0}" |