Option support in toPreserves and fromPreserves

This commit is contained in:
Emery Hemingway 2024-01-03 14:14:46 +02:00
parent 501d6cc012
commit 0acd369262
3 changed files with 37 additions and 22 deletions

View File

@ -1,6 +1,6 @@
# Package
version = "20240102"
version = "20240103"
author = "Emery Hemingway"
description = "data model and serialization format"
license = "Unlicense"

View File

@ -142,15 +142,6 @@ proc `&`*(x: Value; y: seq[Value]): Value =
raise newException(ValueError, "cannot concatenate to non-sequence value")
result = Value(kind: pkSequence, sequence: x.sequence & y)
proc getOrDefault(pr, key: Value): Value =
## Retrieves the value of `pr[key]` if `pr` is a dictionary containing `key`
## or returns the `#f` Preserves value.
if pr.kind == pkDictionary:
for (k, v) in pr.dict:
if key == k:
result = v
break
proc pop*(pr: var Value; key: Value; val: var Value): bool =
## Deletes the `key` from a Preserves dictionary.
## Returns true, if the key existed, and sets `val` to the mapping
@ -440,9 +431,15 @@ proc toPreserves*[T](x: T): Value {.gcsafe.} =
elif T.hasCustomPragma(preservesDictionary):
result = initDictionary()
for key, val in x.fieldPairs:
var pr = fieldToPreserve(key, val)
applyEmbed(key, pr)
result[toSymbol(key)] = pr
when val is Option:
if val.isSome:
var pr = fieldToPreserve(key, val.get)
applyEmbed(key, pr)
result[key.toSymbol] = pr
else:
var pr = fieldToPreserve(key, val)
applyEmbed(key, pr)
result[key.toSymbol] = pr
sortDict(result)
else:
{.warning: "failed to preserve object " & $T .}
@ -491,6 +488,9 @@ proc toPreservesHook*[A, B](table: Table[A, B]|TableRef[A, B]): Value =
result[toPreserves(k)] = toPreserves(v)
sortDict(result)
proc toPreservesHook*(o: Option): Value =
o.get.toPreserves
proc fromAtom*[T](v: var T; a: ATom): bool =
if T is Atom:
v = a
@ -715,12 +715,17 @@ proc fromPreserves*[T](v: var T; pr: Value): bool {.gcsafe.} =
if pr.isDictionary:
result = true
var i: int
for key, _ in fieldPairs(v):
let val = pr.getOrDefault(toSymbol(key))
result = result and fieldFromPreserve(
key, v.dot(key), val)
for key, field in fieldPairs(v):
if not result: break
inc i
let val = step(pr, key.toSymbol)
when field is Option:
if val.isSome:
discard fieldFromPreserve(key, v.dot(key), val.get)
else:
inc i
result = result and val.isSome
if result:
result = result and fieldFromPreserve(key, v.dot(key), val.get)
result = result and (i <= pr.len)
elif T.hasCustomPragma(preservesOr):
for kind in typeof(T.orKind):
@ -740,9 +745,11 @@ proc fromPreserves*[T](v: var T; pr: Value): bool {.gcsafe.} =
result = true
var i: int
for key, _ in fieldPairs(v):
let val = pr.getOrDefault(toSymbol(key))
result = result and fieldFromPreserve(key, v.dot(key), val)
if not result: break
let val = step(pr, key.toSymbol)
result = result and val.isSome
if result:
result = result and fieldFromPreserve(key, v.dot(key), val.get)
inc i
result = result and (i <= pr.len)
else:
@ -811,6 +818,12 @@ proc fromPreservesHook*[A,B](t: var (Table[A,B]|TableRef[A,B]); pr: Value): bool
break
t[move a] = move b
proc fromPreservesHook*[T](opt: var Option[T]; pr: Value): bool =
opt = some(default T)
result = opt.get.fromPreserves(pr)
if not result:
opt = none(T)
when isMainModule:
var t: Table[int, string]
var pr = t.toPreservesHook()

View File

@ -17,11 +17,13 @@ suite "conversions":
a: int
b: seq[int]
c {.preservesEmbedded.}: Bar
d: Option[bool]
e: Option[bool]
let
c = Foobar(a: 1, b: @[2], c: ("ku", ))
c = Foobar(a: 1, b: @[2], c: ("ku", ), e: some(true))
b = toPreserves(c)
a = preservesTo(b, Foobar)
check($b == """{a: 1 b: [2] c: #!["ku"]}""")
check($b == """{a: 1 b: [2] c: #!["ku"] e: #t}""")
check(a.isSome)
if a.isSome: check(get(a) == c)
check(b.kind == pkDictionary)