From 60c5f036375edb0e68d2bebac8f0e1c7b8c1f69f Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Tue, 6 Dec 2022 13:31:21 -0600 Subject: [PATCH] Add preservesEmbedded pragma --- src/preserves.nim | 19 ++++++++++++++++--- tests/test_conversions.nim | 3 ++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/preserves.nim b/src/preserves.nim index 46ffd6f..f87614f 100644 --- a/src/preserves.nim +++ b/src/preserves.nim @@ -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 diff --git a/tests/test_conversions.nim b/tests/test_conversions.nim index 0148a8e..85dc64e 100644 --- a/tests/test_conversions.nim +++ b/tests/test_conversions.nim @@ -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)