Implemented ignoreInputKey

This commit is contained in:
Felix Krause 2016-10-27 17:58:14 +02:00
parent 6402433d2a
commit dcfa8fd27c
2 changed files with 57 additions and 5 deletions

View File

@ -57,6 +57,9 @@ type
WithDefault = object
a, b, c, d: string
WithIgnoredField = object
x, y: int
markAsTransient(NonVariantWithTransient, a)
markAsTransient(NonVariantWithTransient, c)
@ -67,6 +70,8 @@ markAsTransient(VariantWithTransient, neverThere)
setDefaultValue(WithDefault, b, "b")
setDefaultValue(WithDefault, d, "d")
ignoreInputKey(WithIgnoredField, "z")
proc `$`(v: BetterInt): string {.borrow.}
proc `==`(left, right: BetterInt): bool {.borrow.}
@ -538,6 +543,24 @@ suite "Serialization":
-
kind: deD""", output
test "Load object with ignored key":
let input = "[{x: 1, y: 2}, {x: 3, z: 4, y: 5}, {z: [1, 2, 3], x: 4, y: 5}]"
var result: seq[WithIgnoredField]
load(input, result)
assert result.len == 3
assert result[0].x == 1
assert result[0].y == 2
assert result[1].x == 3
assert result[1].y == 5
assert result[2].x == 4
assert result[2].y == 5
test "Load object with ignored key - unknown field":
let input = "{x: 1, y: 2, zz: 3}"
var result: WithIgnoredField
expectConstructionError(1, 16, "While constructing WithIgnoredField: Unknown field: \"zz\""):
load(input, result)
test "Dump cyclic data structure":
var
a = newNode("a")

View File

@ -545,10 +545,13 @@ let
newIdentNode(":defaultBitvector")
defaultValueGetter {.compileTime.} =
newIdentNode(":defaultValueGetter")
ignoredKeyListProc {.compileTime.} =
newIdentNode(":ignoredKeyList")
var
transientVectors {.compileTime.} = newSeq[set[int16]]()
defaultVectors {.compileTime.} = newSeq[set[int16]]()
ignoredKeyLists {.compileTime.} = newSeq[seq[string]]()
proc addDefaultOr(tName: string, i: int, o: NimNode,
field, elseBranch, defaultValues: NimNode): NimNode {.compileTime.} =
@ -570,7 +573,6 @@ proc checkMissing(s: NimNode, t: typedesc, tName: string, field: NimNode,
newNimNode(nnkRaiseStmt).add(newCall(
bindSym("constructionError"), s, newLit("While constructing " &
tName & ": Missing field: " & escape($field)))), defaultValues)))
echo result.repr
proc markAsFound(i: int, matched: NimNode): NimNode {.compileTime.} =
newAssignment(newNimNode(nnkBracketExpr).add(matched, newLit(i)),
@ -722,6 +724,13 @@ proc isVariantObject(t: typedesc): bool {.compileTime.} =
if child.kind == nnkRecCase: return true
return false
macro injectIgnoredKeyList(t: typedesc, ident: untyped): typed =
result = quote do:
when compiles(`ignoredKeyListProc`(`t`)):
const `ident` = ignoredKeyLists[`ignoredKeyListproc`(`t`)]
else:
const `ident` = newSeq[string]()
proc constructObject*[O: object|tuple](
s: var YamlStream, c: ConstructionContext, result: var O)
{.raises: [YamlConstructionError, YamlStreamError].} =
@ -736,9 +745,8 @@ proc constructObject*[O: object|tuple](
raise s.constructionError("While constructing " &
typetraits.name(O) & ": Expected " & $startKind & ", got " & $e.kind)
when isVariantObject(O): reset(result) # make discriminants writeable
injectIgnoredKeyList(O, ignoredKeyList)
while s.peek.kind != endKind:
# todo: check for duplicates in input and raise appropriate exception
# also todo: check for missing items and raise appropriate exception
e = s.next()
when isVariantObject(O):
if e.kind != yamlStartMap:
@ -764,7 +772,17 @@ proc constructObject*[O: object|tuple](
raise s.constructionError("While constructing " &
typetraits.name(O) & ": Unknown field: " & escape(name))
else:
if name notin ignoredKeyList:
constructFieldValue(O, tIndex, s, c, name, result, matched)
else:
e = s.next()
var depth = int(e.kind in {yamlStartMap, yamlStartSeq})
while depth > 0:
case s.next().kind
of yamlStartMap, yamlStartSeq: inc(depth)
of yamlEndMap, yamlEndSeq: dec(depth)
of yamlScalar: discard
else: internalError("Unexpected event kind.")
when isVariantObject(O):
e = s.next()
if e.kind != yamlEndMap:
@ -1336,4 +1354,15 @@ macro setDefaultValue*(t: typedesc, field: untyped, value: typed): typed =
static:
`defaultValueGetter`(`t`).`field` = `value`
defaultVectors[`defaultBitvectorProc`(`t`)].incl(getFieldIndex(`t`, `field`))
echo result.repr
macro ignoreInputKey*(t: typedesc, name: string{lit}): typed =
let nextIgnoredKeyList = ignoredKeyLists.len
result = quote do:
when not compiles(`ignoredKeyListProc`(`t`)):
proc `ignoredKeyListProc`*(t: typedesc[`t`]): int {.compileTime.} =
`nextIgnoredKeyList`
static: ignoredKeyLists.add(@[])
when `name` in ignoredKeyLists[`ignoredKeyListProc`(`t`)]:
{.fatal: "Input key " & `name` & " is already ignored!".}
static:
ignoredKeyLists[`ignoredKeyListProc`(`t`)].add(`name`)