Closed planetis-m closed 3 years ago
It wont work...
This will:
while readfields:
case key
of "kind":
tmp_kind = readAny(value)
of "fieldA":
tmp_fieldA = readAny(value)
of "fieldB":
tmp_fieldB = readAny(value)
result = Obj(kind: tmp_kind)
case kind
of variantA:
result.fieldA = tmp_fieldA
of variantB:
result.fieldB = tmp_fieldB
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)
Warning pseudocode:
proc packImpl(p: var JsonParser): Foo =
var prev = -1
while readfields:
case key
of "name":
tmp_name = readAny(value)
of "kind":
tmp_kind = readAny(value)
of "banana", "apple":
if prev != -1: prev = p.stream.getPosition() # impossible
else:
error("object field")
result = Obj(name: tmp_name, kind: tmp_kind)
if prev != -1: p.stream.setPosition(prev)
while readfields:
case kind
of Banana:
case key
of "banana":
result.banana = readAny(value)
of "name", "kind": discard
else:
error("object field")
of Apple:
case key
of "apple":
result.apple = readAny(value)
of "name", "kind": discard
else:
error("object field")
However LexBase
doesn't allow backtracking, so I might do this:
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")
Ofcourse this still holds and needs to be considered:
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
Done. For now it expects first the discriminator field. Its sufficient for me but PRs welcome.
Write code like: