diff --git a/private/serialization.nim b/private/serialization.nim index 60504c6..b3bf4d7 100644 --- a/private/serialization.nim +++ b/private/serialization.nim @@ -385,7 +385,7 @@ proc representObject*[K, V](value: OrderedTable[K, V], ts: TagStyle, yield endSeqEvent() template yamlTag*(T: typedesc[object|enum]): expr = - var uri = when compiles(yamlTagId(T)): yamlTagId(T) else: + var uri = when compiles(yamlTag(T)): yamlTag(T) else: "!nim:custom:" & (typetraits.name(type(T))) try: serializationTagLibrary.tags[uri] except KeyError: serializationTagLibrary.registerUri(uri) @@ -554,10 +554,6 @@ proc constructChild*[O](s: var YamlStream, c: ConstructionContext, e.parent = getCurrentException() raise e -proc representChild*[O](value: O, ts: TagStyle, c: SerializationContext): - RawYamlStream = - result = representObject(value, ts, c, presentTag(O, ts)) - proc representChild*(value: string, ts: TagStyle, c: SerializationContext): RawYamlStream = if isNil(value): diff --git a/test1.nim b/test1.nim new file mode 100644 index 0000000..cb7e656 --- /dev/null +++ b/test1.nim @@ -0,0 +1,27 @@ +import yaml, macros + +type + FooKind = enum + fooInt, fooBool, fooNone + FooKind2 = enum + fooAddString, fooAddNone + + Foo = object + a: string + case b: FooKind + of fooInt: + c: int32 + of fooBool: + d: bool + of fooNone: + discard + case c2: FooKind2 + of fooAddString: + e: string + of fooAddNone: + discard + +var o = newFileStream(stdout) +var f = Foo(a: "a", b: fooBool, d: true) + +dump(f, o) \ No newline at end of file diff --git a/yaml.nim b/yaml.nim index 323e91e..4482efb 100644 --- a/yaml.nim +++ b/yaml.nim @@ -602,9 +602,61 @@ proc representChild*[O](value: ref O, ts: TagStyle, c: SerializationContext): ## may be represented as alias node if it is already present in the ## ``SerializationContext``. -proc representChild*[O](value: O, ts: TagStyle, c: SerializationContext): +proc representChild*(value: string, ts: TagStyle, c: SerializationContext): RawYamlStream {.inline.} + ## Represents a Nim string. Supports nil strings. + +proc isVariant(t: typedesc): bool {.compileTime.} = + let typeDesc = getType(t) + if typeDesc.len > 1: + for child in typeDesc[1].children: + if child.kind == nnkRecCase: + return true + return false + +macro presentTagDiscriminators(target: string, t: typedesc, val: expr): stmt = + var first = true + let typeDesc = getType(getType(t)[1]) + for child in typeDesc[1].children: + if child.kind != nnkRecCase: continue + + template discriminantToString(): NimNode = + newNimNode(nnkInfix).add( + newIdentNode("$"), newDotExpr(val, child[0]) + ) + + if first: + first = false + result = newNimNode(nnkInfix).add( + newIdentNode("&"), newStrLitNode("("), discriminantToString() + ) + else: + result = newNimNode(nnkInfix).add( + newIdentNode("&"), result, newNimNode(nnkInfix).add( + newIdentNode("&"), newStrLitNode(","), discriminantToString()) + ) + if first: # no discriminators + result = newNimNode(nnkDiscardStmt).add(newNimNode(nnkEmpty)) + else: + result = newNimNode(nnkInfix).add(newIdentNode("&="), target, + newNimNode(nnkInfix).add(newIdentNode("&"), result, newStrLitNode(")"))) + +template presentVariantObjectTag[O](t: typedesc[object], val: O): TagId = + var oTag = name(t) + presentTagDiscriminators(oTag, t, val) + try: serializationTagLibrary.tags[oTag] + except KeyError: serializationTagLibrary.registerUri(oTag) + +proc representChild*[O](value: O, ts: TagStyle, + c: SerializationContext): + RawYamlStream {.raises: [].} = ## Represents an arbitrary Nim object as YAML object. + const isVar = isVariant(O) + when isVar: + result = representObject(value, ts, c, presentVariantObjectTag(O, value)) + else: + result = representObject(value, ts, c, if ts == tsNone: + yTagQuestionMark else: yamlTag(O)) proc construct*[T](s: var YamlStream, target: var T) {.raises: [YamlConstructionError, YamlStreamError].}