So I'm having trouble adding support for case objects in my deserialization
library. I'm sorry for the long post but the question is really simple.
Let's consider this example:
type
Fruit = enum
Apple
Banana
Foo = object
name: string
case kind: Fruit
of Banana: banana: int
of Apple: apple: string
let
original = Foo(name: "hello", kind: Apple, apple: "world")
let s =
newStringStream("""{"name":"hello","apple":"world","kind":"Apple"}""")
echo s.to(Foo)
Run
Warning pseudocode ahead:
1\. In this approach it requires the kind field to be ahead of the rest.
However JSON does not pose requirements for field ordering.
proc packImpl(p: var JsonParser): Foo =
while readfields:
case key
of "name":
tmp_name = readAny(value)
of "kind":
tmp_kind = readAny(value)
else:
error("object field")
result = Obj(name: tmp_name, kind: tmp_kind)
while readfields:
case kind
of Banana:
case key
of "banana":
result.banana = readAny(value)
of "name":
result.name = readAny(value)
else:
error("object field")
of Apple:
case key
of "apple":
result.apple = readAny(value)
of "name"
result.name = readAny(value)
else:
error("object field")
Run
2\. This approach creates tmps for every field in the object (is that
unwanted?), but is more flexible:
proc packImpl(p: var JsonParser): Foo =
while readfields:
case key
of "name":
tmp_name = readAny(value)
of "kind":
tmp_kind = readAny(value)
of "banana":
isBanana = true
tmp_banana = readAny(value)
of "apple":
isApple = true
tmp_apple = readAny(value)
else:
error("object field")
result = Obj(kind: tmp_kind)
if not(isBanana xor isApple):
raise newException(FieldDefect, "field is not accessible using
discriminant " & $tmp_kind)
result.name = tmp_name
case kind
of Banana:
result.banana = tmp_banana
of Apple:
result.apple = tmp_apple
Run
3\. And of couse we can assign to field kind directly ignoring the compiler
warnings. This is what `json.to` and `status-im/nim-json-serialization` do.
proc packImpl(p: var JsonParser): Foo =
while readfields:
case key
of "name":
result.name = readAny(value)
of "kind":
resulr.kind = readAny(value)
of "banana":
isBanana = true
result.banana = readAny(value)
of "apple":
isApple = true
result.apple = readAny(value)
else:
error("object field")
if not(isBanana xor isApple):
raise newException(FieldDefect, "field is not accessible using
discriminant " & $tmp_kind)
Run
So which approach should I follow?