Add preservesEmbedded pragma

This commit is contained in:
Emery Hemingway 2022-12-06 13:31:21 -06:00
parent d3132391bd
commit 60c5f03637
2 changed files with 18 additions and 4 deletions

View File

@ -728,6 +728,9 @@ template preservesLiteral*(value: typed) {.pragma.}
## Serialize a Preserves literal within this object.
## See ``toPreserve``.
template preservesEmbedded*() {.pragma.}
## Pragma to mark a value as embedded by `toPreserve`.
template unpreservable*() {.pragma.}
## Pragma to forbid a type from being converted by ``toPreserve``.
## Useful for preventing an embeded type from being encoded
@ -781,6 +784,9 @@ proc toPreserve*[T](x: T; E = void): Preserve[E] =
elif T is distinct:
result = toPreserve(x.distinctBase, E)
elif T is object:
template applyEmbed(key: string; v: var Preserve[E]) {.used.} =
when x.dot(key).hasCustomPragma(preservesEmbedded):
v.embedded = true
template fieldToPreserve(key: string; val: typed): Preserve {.used.} =
when x.dot(key).hasCustomPragma(preservesLiteral):
const lit = parsePreserves(x.dot(key).getCustomPragmaVal(preservesLiteral))
@ -798,11 +804,14 @@ proc toPreserve*[T](x: T; E = void): Preserve[E] =
else:
assert(hasKind and not hasVariant)
result = fieldToPreserve(k, v)
applyEmbed(k, result)
hasVariant = true
elif T.hasCustomPragma(preservesRecord):
result = Preserve[E](kind: pkRecord)
for k, v in x.fieldPairs:
result.record.add(fieldToPreserve(k, v))
var pr = fieldToPreserve(k, v)
applyEmbed(k, pr)
result.record.add(pr)
result.record.add(tosymbol(T.getCustomPragmaVal(preservesRecord), E))
elif T.hasCustomPragma(preservesTuple):
result = initSequence[E]()
@ -812,11 +821,15 @@ proc toPreserve*[T](x: T; E = void): Preserve[E] =
result.sequence.add(toPreserve(y, E))
# TODO: what if there are fields after the tail?
else:
result.sequence.add(fieldToPreserve(label, field))
var pr = fieldToPreserve(label, field)
applyEmbed(label, pr)
result.sequence.add(pr)
elif T.hasCustomPragma(preservesDictionary):
result = initDictionary[E]()
for key, val in x.fieldPairs:
result[toSymbol(key, E)] = fieldToPreserve(key, val)
var pr = fieldToPreserve(key, val)
applyEmbed(key, pr)
result[toSymbol(key, E)] = pr
else: result = toPreserveHook(x, E)
else: result = toPreserveHook(x, E)
# the hook doesn't compile but produces a useful error

View File

@ -10,11 +10,12 @@ suite "conversions":
s: string
type Foobar {.preservesDictionary.} = object
a, b: int
c: Bar
c {.preservesEmbedded.}: Bar
let
c = Foobar(a: 1, b: 2, c: ("ku", ))
b = toPreserve(c)
a = preserveTo(b, Foobar)
check($b == """{a: 1 b: 2 c: #!["ku"]}""")
check(a.isSome and (get(a) == c))
check(b.kind == pkDictionary)