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