Embed values for types with {.preservesEmbedded.}
This commit is contained in:
parent
79ea25d1be
commit
d2017228fb
|
@ -229,7 +229,7 @@ proc toDictionary*(pairs: openArray[(string, Value)]): Value =
|
|||
for (key, val) in pairs: result[toSymbol(key)] = val
|
||||
|
||||
proc embed*(pr: sink Value): Value =
|
||||
## Create a Preserves value that embeds ``e``.
|
||||
## Mark a Preserves value as embedded.
|
||||
result = pr
|
||||
result.embedded = true
|
||||
|
||||
|
@ -328,7 +328,7 @@ template preservesLiteral*(value: typed) {.pragma.}
|
|||
## See ``toPreserves``.
|
||||
|
||||
template preservesEmbedded*() {.pragma.}
|
||||
## Pragma to mark a value as embedded by `toPreserves`.
|
||||
## Pragma to mark a type or value as embedded.
|
||||
|
||||
template unpreservable*() {.pragma.}
|
||||
## Pragma to forbid a type from being converted by ``toPreserves``.
|
||||
|
@ -375,11 +375,12 @@ proc toPreserves*[T](x: T): Value {.gcsafe.} =
|
|||
elif T is Ordinal:
|
||||
result = Value(kind: pkRegister, register: x.ord)
|
||||
assert result.register.T == x
|
||||
elif T is EmbeddedRef:
|
||||
result = embed(x)
|
||||
elif T is ptr | ref:
|
||||
if system.`==`(x, nil): result = initRecord("null")
|
||||
else: result = toPreserves(x[])
|
||||
when T.hasCustomPragma(preservesEmbedded):
|
||||
result = embed(x)
|
||||
else:
|
||||
if system.`==`(x, nil): result = initRecord("null")
|
||||
else: result = toPreserves(x[])
|
||||
elif T is string:
|
||||
result = Value(kind: pkString, string: x)
|
||||
elif T is SomeInteger:
|
||||
|
@ -390,15 +391,18 @@ proc toPreserves*[T](x: T): Value {.gcsafe.} =
|
|||
elif T is distinct:
|
||||
result = toPreserves(x.distinctBase)
|
||||
elif T is object:
|
||||
template applyEmbed(key: string; v: var Value) {.used.} =
|
||||
when x.dot(key).hasCustomPragma(preservesEmbedded):
|
||||
v.embedded = true
|
||||
template fieldToPreserve(key: string; val: typed): Value {.used.} =
|
||||
template fieldToPreserve[F](key: string; field: F): Value {.used.} =
|
||||
when x.dot(key).hasCustomPragma(preservesLiteral):
|
||||
const atom = x.dot(key).getCustomPragmaVal(preservesLiteral).parsePreservesAtom
|
||||
atom.toPreservesHook()
|
||||
when x.dot(key).hasCustomPragma(preservesEmbedded):
|
||||
atom.toPreservesHook().embed
|
||||
else:
|
||||
atom.toPreservesHook()
|
||||
elif x.dot(key).hasCustomPragma(preservesEmbedded) and F is EmbeddedRef:
|
||||
embed(field)
|
||||
else:
|
||||
toPreserves(val)
|
||||
field.toPreserves
|
||||
# checking for the embedded pragma here yields false positives
|
||||
when T.hasCustomPragma(unpreservable):
|
||||
raiseAssert($T & " is unpreservable")
|
||||
elif T.hasCustomPragma(preservesOr):
|
||||
|
@ -410,13 +414,11 @@ proc toPreserves*[T](x: T): Value {.gcsafe.} =
|
|||
else:
|
||||
assert(hasKind and not hasVariant)
|
||||
result = fieldToPreserve(k, v)
|
||||
applyEmbed(k, result)
|
||||
hasVariant = true
|
||||
elif T.hasCustomPragma(preservesRecord):
|
||||
result = Value(kind: pkRecord)
|
||||
for k, v in x.fieldPairs:
|
||||
var pr = fieldToPreserve(k, v)
|
||||
applyEmbed(k, pr)
|
||||
result.record.add(pr)
|
||||
result.record.add(toSymbol(T.getCustomPragmaVal(preservesRecord)))
|
||||
elif T.hasCustomPragma(preservesTuple):
|
||||
|
@ -428,7 +430,6 @@ proc toPreserves*[T](x: T): Value {.gcsafe.} =
|
|||
# TODO: what if there are fields after the tail?
|
||||
else:
|
||||
var pr = fieldToPreserve(label, field)
|
||||
applyEmbed(label, pr)
|
||||
result.sequence.add(pr)
|
||||
elif T.hasCustomPragma(preservesDictionary):
|
||||
result = initDictionary()
|
||||
|
@ -436,11 +437,13 @@ proc toPreserves*[T](x: T): Value {.gcsafe.} =
|
|||
when val is Option:
|
||||
if val.isSome:
|
||||
var pr = fieldToPreserve(key, val.get)
|
||||
applyEmbed(key, pr)
|
||||
if x.dot(key).hasCustomPragma(preservesEmbedded):
|
||||
pr.embedded = true
|
||||
result[key.toSymbol] = pr
|
||||
else:
|
||||
var pr = fieldToPreserve(key, val)
|
||||
applyEmbed(key, pr)
|
||||
if x.dot(key).hasCustomPragma(preservesEmbedded):
|
||||
pr.embedded = true
|
||||
result[key.toSymbol] = pr
|
||||
sortDict(result)
|
||||
else:
|
||||
|
@ -661,19 +664,27 @@ proc fromPreserves*[T](v: var T; pr: Value): bool {.gcsafe.} =
|
|||
else: false
|
||||
if not result: break
|
||||
else: discard
|
||||
elif T is EmbeddedRef:
|
||||
v = T(pr.embeddedRef)
|
||||
result = true
|
||||
elif T is ref:
|
||||
if isNil(v): new(v)
|
||||
result = fromPreserves(v[], pr)
|
||||
when T.hasCustomPragma(preservesEmbedded):
|
||||
if (pr.kind == pkEmbedded) and (pr.embeddedRef of T):
|
||||
v = T(pr.embeddedRef)
|
||||
result = true
|
||||
else:
|
||||
if isNil(v): new(v)
|
||||
result = fromPreserves(v[], pr)
|
||||
elif T is object:
|
||||
template fieldFromPreserve(key: string; val: typed; pr: Value): bool {.used.} =
|
||||
template fieldFromPreserve[T](key: string; val: T; pr: Value): bool {.used.} =
|
||||
when v.dot(key).hasCustomPragma(preservesLiteral):
|
||||
const atom = v.dot(key).getCustomPragmaVal(preservesLiteral).parsePreservesAtom
|
||||
pr == atom.toPreservesHook()
|
||||
else:
|
||||
fromPreserves(val, pr)
|
||||
elif v.dot(key).hasCustomPragma(preservesEmbedded):
|
||||
when T is EmbeddedRef:
|
||||
if pr.kind == pkEmbedded and pr.embeddedRef of T:
|
||||
val = T(pr.embeddedRef)
|
||||
true
|
||||
else: false
|
||||
else: fromPreserves(val, pr)
|
||||
else: fromPreserves(val, pr)
|
||||
when T.hasCustomPragma(unpreservable):
|
||||
raiseAssert($T & " is unpreservable")
|
||||
elif T.hasCustomPragma(preservesRecord):
|
||||
|
@ -726,7 +737,8 @@ proc fromPreserves*[T](v: var T; pr: Value): bool {.gcsafe.} =
|
|||
inc i
|
||||
result = result and val.isSome
|
||||
if result:
|
||||
result = result and fieldFromPreserve(key, v.dot(key), val.get)
|
||||
var pr = val.get
|
||||
result = result and fieldFromPreserve(key, v.dot(key), pr)
|
||||
result = result and (i <= pr.len)
|
||||
elif T.hasCustomPragma(preservesOr):
|
||||
for kind in typeof(T.orKind):
|
||||
|
|
|
@ -79,7 +79,7 @@ suite "conversions":
|
|||
type
|
||||
Foo {.preservesRecord: "foo".} = object
|
||||
n: int
|
||||
bar: Bar
|
||||
bar {.preservesEmbedded.}: Bar
|
||||
Bar = ref object of RootObj
|
||||
x: int
|
||||
Baz = ref object of RootObj
|
||||
|
|
Loading…
Reference in New Issue