mirror of https://github.com/status-im/NimYAML.git
Support nil strings and seqs
This commit is contained in:
parent
58b9b92895
commit
4ca4b2c87e
|
@ -62,7 +62,9 @@ supported. There is currently no problem with ``float``, because it is always a
|
||||||
``float64``.
|
``float64``.
|
||||||
|
|
||||||
``string`` is supported and one of the few Nim types which directly map to a
|
``string`` is supported and one of the few Nim types which directly map to a
|
||||||
standard YAML type. ``char`` is also supported.
|
standard YAML type. NimYAML is able to handle strings that are ``nil``, they
|
||||||
|
will be serialized with the special tag ``!nim:nil:string``. ``char`` is also
|
||||||
|
supported.
|
||||||
|
|
||||||
To support new scalar types, you must implement the ``constructObject()`` and
|
To support new scalar types, you must implement the ``constructObject()`` and
|
||||||
``representObject()`` procs on that type (see below).
|
``representObject()`` procs on that type (see below).
|
||||||
|
@ -86,6 +88,9 @@ cannot be loaded to Nim collection types. For example, this sequence:
|
||||||
Cannot be loaded to a Nim ``seq``. For this reason, you cannot load YAML's
|
Cannot be loaded to a Nim ``seq``. For this reason, you cannot load YAML's
|
||||||
native ``!!map`` and ``!!seq`` types directly into Nim types.
|
native ``!!map`` and ``!!seq`` types directly into Nim types.
|
||||||
|
|
||||||
|
Nim ``seq`` types may be ``nil``. This is handled by serializing them to an
|
||||||
|
empty scalar with the tag ``!nim:nil:seq``.
|
||||||
|
|
||||||
Reference Types
|
Reference Types
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
|
|
@ -488,6 +488,37 @@ proc constructChild*[T](s: var YamlStream, c: ConstructionContext,
|
||||||
else: assert false
|
else: assert false
|
||||||
constructObject(s, c, result)
|
constructObject(s, c, result)
|
||||||
|
|
||||||
|
proc constructChild*(s: var YamlStream, c: ConstructionContext,
|
||||||
|
result: var string) =
|
||||||
|
let item = s.peek()
|
||||||
|
if item.kind == yamlScalar:
|
||||||
|
if item.scalarTag == yTagNimNilString:
|
||||||
|
discard s.next()
|
||||||
|
result = nil
|
||||||
|
return
|
||||||
|
elif item.scalarTag notin
|
||||||
|
[yTagQuestionMark, yTagExclamationMark, yamlTag(string)]:
|
||||||
|
raise newException(YamlConstructionError, "Wrong tag for string")
|
||||||
|
elif item.scalarAnchor != yAnchorNone:
|
||||||
|
raise newException(YamlConstructionError, "Anchor on non-ref type")
|
||||||
|
constructObject(s, c, result)
|
||||||
|
|
||||||
|
proc constructChild*[T](s: var YamlStream, c: ConstructionContext,
|
||||||
|
result: var seq[T]) =
|
||||||
|
let item = s.peek()
|
||||||
|
if item.kind == yamlScalar:
|
||||||
|
if item.scalarTag == yTagNimNilSeq:
|
||||||
|
discard s.next()
|
||||||
|
result = nil
|
||||||
|
return
|
||||||
|
elif item.kind == yamlStartSeq:
|
||||||
|
if item.seqTag notin [yTagQuestionMark, yamlTag(seq[T])]:
|
||||||
|
raise newException(YamlConstructionError, "Wrong tag for " &
|
||||||
|
typetraits.name(seq[T]))
|
||||||
|
elif item.seqAnchor != yAnchorNone:
|
||||||
|
raise newException(YamlConstructionError, "Anchor on non-ref type")
|
||||||
|
constructObject(s, c, result)
|
||||||
|
|
||||||
proc constructChild*[O](s: var YamlStream, c: ConstructionContext,
|
proc constructChild*[O](s: var YamlStream, c: ConstructionContext,
|
||||||
result: var ref O) =
|
result: var ref O) =
|
||||||
var e = s.peek()
|
var e = s.peek()
|
||||||
|
@ -527,6 +558,20 @@ proc representChild*[O](value: O, ts: TagStyle, c: SerializationContext):
|
||||||
RawYamlStream =
|
RawYamlStream =
|
||||||
result = representObject(value, ts, c, presentTag(O, ts))
|
result = representObject(value, ts, c, presentTag(O, ts))
|
||||||
|
|
||||||
|
proc representChild*(value: string, ts: TagStyle, c: SerializationContext):
|
||||||
|
RawYamlStream =
|
||||||
|
if isNil(value):
|
||||||
|
result = iterator(): YamlStreamEvent =
|
||||||
|
yield scalarEvent("", yTagNimNilString)
|
||||||
|
else: result = representObject(value, ts, c, presentTag(string, ts))
|
||||||
|
|
||||||
|
proc representChild*[T](value: seq[T], ts: TagStyle, c: SerializationContext):
|
||||||
|
RawYamlStream =
|
||||||
|
if isNil(value):
|
||||||
|
result = iterator(): YamlStreamEvent =
|
||||||
|
yield scalarEvent("", yTagNimNilSeq)
|
||||||
|
else: result = representObject(value, ts, c, presentTag(seq[T], ts))
|
||||||
|
|
||||||
proc representChild*[O](value: ref O, ts: TagStyle, c: SerializationContext):
|
proc representChild*[O](value: ref O, ts: TagStyle, c: SerializationContext):
|
||||||
RawYamlStream =
|
RawYamlStream =
|
||||||
if value == nil:
|
if value == nil:
|
||||||
|
|
|
@ -78,4 +78,6 @@ proc initSerializationTagLibrary(): TagLibrary =
|
||||||
result.tags["tag:yaml.org,2002:timestamp"] = yTagTimestamp
|
result.tags["tag:yaml.org,2002:timestamp"] = yTagTimestamp
|
||||||
result.tags["tag:yaml.org,2002:value"] = yTagValue
|
result.tags["tag:yaml.org,2002:value"] = yTagValue
|
||||||
result.tags["tag:yaml.org,2002:binary"] = yTagBinary
|
result.tags["tag:yaml.org,2002:binary"] = yTagBinary
|
||||||
result.tags["!nim:field"] = yTagNimField
|
result.tags["!nim:field"] = yTagNimField
|
||||||
|
result.tags["!nim:nil:string"] = yTagNimNilString
|
||||||
|
result.tags["!nim:nil:seq"] = yTagNimNilSeq
|
|
@ -93,6 +93,18 @@ suite "Serialization":
|
||||||
except: gotException = true
|
except: gotException = true
|
||||||
assert gotException, "Expected exception, got none."
|
assert gotException, "Expected exception, got none."
|
||||||
|
|
||||||
|
test "Serialization: Load nil string":
|
||||||
|
let input = newStringStream("!nim:nil:string \"\"")
|
||||||
|
var result: string
|
||||||
|
load(input, result)
|
||||||
|
assert isNil(result)
|
||||||
|
|
||||||
|
test "Serialization: Dump nil string":
|
||||||
|
let input: string = nil
|
||||||
|
var output = newStringStream()
|
||||||
|
dump(input, output, tsNone, asTidy, blockOnly)
|
||||||
|
assertStringEqual "%YAML 1.2\n--- \n!nim:nil:string \"\"", output.data
|
||||||
|
|
||||||
test "Serialization: Load string sequence":
|
test "Serialization: Load string sequence":
|
||||||
let input = newStringStream(" - a\n - b")
|
let input = newStringStream(" - a\n - b")
|
||||||
var result: seq[string]
|
var result: seq[string]
|
||||||
|
@ -101,12 +113,24 @@ suite "Serialization":
|
||||||
assert result[0] == "a"
|
assert result[0] == "a"
|
||||||
assert result[1] == "b"
|
assert result[1] == "b"
|
||||||
|
|
||||||
test "Serialization: Represent string sequence":
|
test "Serialization: Dump string sequence":
|
||||||
var input = @["a", "b"]
|
var input = @["a", "b"]
|
||||||
var output = newStringStream()
|
var output = newStringStream()
|
||||||
dump(input, output, tsNone, asTidy, blockOnly)
|
dump(input, output, tsNone, asTidy, blockOnly)
|
||||||
assertStringEqual "%YAML 1.2\n--- \n- a\n- b", output.data
|
assertStringEqual "%YAML 1.2\n--- \n- a\n- b", output.data
|
||||||
|
|
||||||
|
test "Serialization: Load nil seq":
|
||||||
|
let input = newStringStream("!nim:nil:seq \"\"")
|
||||||
|
var result: seq[int]
|
||||||
|
load(input, result)
|
||||||
|
assert isNil(result)
|
||||||
|
|
||||||
|
test "Serialization: Dump nil seq":
|
||||||
|
let input: seq[int] = nil
|
||||||
|
var output = newStringStream()
|
||||||
|
dump(input, output, tsNone, asTidy, blockOnly)
|
||||||
|
assertStringEqual "%YAML 1.2\n--- \n!nim:nil:seq \"\"", output.data
|
||||||
|
|
||||||
test "Serialization: Load char set":
|
test "Serialization: Load char set":
|
||||||
let input = newStringStream("- a\n- b")
|
let input = newStringStream("- a\n- b")
|
||||||
var result: set[char]
|
var result: set[char]
|
||||||
|
@ -115,7 +139,7 @@ suite "Serialization":
|
||||||
assert 'a' in result
|
assert 'a' in result
|
||||||
assert 'b' in result
|
assert 'b' in result
|
||||||
|
|
||||||
test "Serialization: Represent char set":
|
test "Serialization: Dump char set":
|
||||||
var input = {'a', 'b'}
|
var input = {'a', 'b'}
|
||||||
var output = newStringStream()
|
var output = newStringStream()
|
||||||
dump(input, output, tsNone, asTidy, blockOnly)
|
dump(input, output, tsNone, asTidy, blockOnly)
|
||||||
|
@ -129,7 +153,7 @@ suite "Serialization":
|
||||||
assert result[1] == 42
|
assert result[1] == 42
|
||||||
assert result[2] == 47
|
assert result[2] == 47
|
||||||
|
|
||||||
test "Serialization: Represent array":
|
test "Serialization: Dump array":
|
||||||
let input = [23'i32, 42'i32, 47'i32]
|
let input = [23'i32, 42'i32, 47'i32]
|
||||||
var output = newStringStream()
|
var output = newStringStream()
|
||||||
dump(input, output, tsNone, asTidy, blockOnly)
|
dump(input, output, tsNone, asTidy, blockOnly)
|
||||||
|
@ -143,7 +167,7 @@ suite "Serialization":
|
||||||
assert result[23] == "dreiundzwanzig"
|
assert result[23] == "dreiundzwanzig"
|
||||||
assert result[42] == "zweiundvierzig"
|
assert result[42] == "zweiundvierzig"
|
||||||
|
|
||||||
test "Serialization: Represent Table[int, string]":
|
test "Serialization: Dump Table[int, string]":
|
||||||
var input = initTable[int32, string]()
|
var input = initTable[int32, string]()
|
||||||
input[23] = "dreiundzwanzig"
|
input[23] = "dreiundzwanzig"
|
||||||
input[42] = "zweiundvierzig"
|
input[42] = "zweiundvierzig"
|
||||||
|
@ -168,7 +192,7 @@ suite "Serialization":
|
||||||
else: assert false
|
else: assert false
|
||||||
i.inc()
|
i.inc()
|
||||||
|
|
||||||
test "Serialization: Represent OrderedTable[tuple[int32, int32], string]":
|
test "Serialization: Dump OrderedTable[tuple[int32, int32], string]":
|
||||||
var input = initOrderedTable[tuple[a, b: int32], string]()
|
var input = initOrderedTable[tuple[a, b: int32], string]()
|
||||||
input.add((a: 23'i32, b: 42'i32), "dreiundzwanzigzweiundvierzig")
|
input.add((a: 23'i32, b: 42'i32), "dreiundzwanzigzweiundvierzig")
|
||||||
input.add((a: 13'i32, b: 47'i32), "dreizehnsiebenundvierzig")
|
input.add((a: 13'i32, b: 47'i32), "dreizehnsiebenundvierzig")
|
||||||
|
@ -196,7 +220,7 @@ suite "Serialization":
|
||||||
assert result[1] == @[4.int32, 5.int32]
|
assert result[1] == @[4.int32, 5.int32]
|
||||||
assert result[2] == @[6.int32]
|
assert result[2] == @[6.int32]
|
||||||
|
|
||||||
test "Serialization: Represent Sequences in Sequence":
|
test "Serialization: Dump Sequences in Sequence":
|
||||||
let input = @[@[1.int32, 2.int32, 3.int32], @[4.int32, 5.int32], @[6.int32]]
|
let input = @[@[1.int32, 2.int32, 3.int32], @[4.int32, 5.int32], @[6.int32]]
|
||||||
var output = newStringStream()
|
var output = newStringStream()
|
||||||
dump(input, output, tsNone)
|
dump(input, output, tsNone)
|
||||||
|
@ -212,7 +236,7 @@ suite "Serialization":
|
||||||
assert result[1] == tlGreen
|
assert result[1] == tlGreen
|
||||||
assert result[2] == tlYellow
|
assert result[2] == tlYellow
|
||||||
|
|
||||||
test "Serialization: Represent Enum":
|
test "Serialization: Dump Enum":
|
||||||
let input = @[tlRed, tlGreen, tlYellow]
|
let input = @[tlRed, tlGreen, tlYellow]
|
||||||
var output = newStringStream()
|
var output = newStringStream()
|
||||||
dump(input, output, tsNone, asTidy, blockOnly)
|
dump(input, output, tsNone, asTidy, blockOnly)
|
||||||
|
@ -227,7 +251,7 @@ suite "Serialization":
|
||||||
assert result.i == 42
|
assert result.i == 42
|
||||||
assert result.b == true
|
assert result.b == true
|
||||||
|
|
||||||
test "Serialization: Represent Tuple":
|
test "Serialization: Dump Tuple":
|
||||||
let input = (str: "value", i: 42.int32, b: true)
|
let input = (str: "value", i: 42.int32, b: true)
|
||||||
var output = newStringStream()
|
var output = newStringStream()
|
||||||
dump(input, output, tsNone)
|
dump(input, output, tsNone)
|
||||||
|
@ -241,7 +265,7 @@ suite "Serialization":
|
||||||
assert result.surname == "Pan"
|
assert result.surname == "Pan"
|
||||||
assert result.age == 12
|
assert result.age == 12
|
||||||
|
|
||||||
test "Serialization: Represent custom object":
|
test "Serialization: Dump custom object":
|
||||||
let input = Person(firstnamechar: 'P', surname: "Pan", age: 12)
|
let input = Person(firstnamechar: 'P', surname: "Pan", age: 12)
|
||||||
var output = newStringStream()
|
var output = newStringStream()
|
||||||
dump(input, output, tsNone, asTidy, blockOnly)
|
dump(input, output, tsNone, asTidy, blockOnly)
|
||||||
|
@ -256,7 +280,7 @@ suite "Serialization":
|
||||||
assert result[0] == "one"
|
assert result[0] == "one"
|
||||||
assert result[1] == "two"
|
assert result[1] == "two"
|
||||||
|
|
||||||
test "Serialization: Represent sequence with explicit tags":
|
test "Serialization: Dump sequence with explicit tags":
|
||||||
let input = @["one", "two"]
|
let input = @["one", "two"]
|
||||||
var output = newStringStream()
|
var output = newStringStream()
|
||||||
dump(input, output, tsAll, asTidy, blockOnly)
|
dump(input, output, tsAll, asTidy, blockOnly)
|
||||||
|
@ -272,7 +296,7 @@ suite "Serialization":
|
||||||
assert result.surname == "Pan"
|
assert result.surname == "Pan"
|
||||||
assert result.age == 12
|
assert result.age == 12
|
||||||
|
|
||||||
test "Serialization: Represent custom object with explicit root tag":
|
test "Serialization: Dump custom object with explicit root tag":
|
||||||
let input = Person(firstnamechar: 'P', surname: "Pan", age: 12)
|
let input = Person(firstnamechar: 'P', surname: "Pan", age: 12)
|
||||||
var output = newStringStream()
|
var output = newStringStream()
|
||||||
dump(input, output, tsRootOnly, asTidy, blockOnly)
|
dump(input, output, tsRootOnly, asTidy, blockOnly)
|
||||||
|
@ -280,7 +304,7 @@ suite "Serialization":
|
||||||
"--- !nim:custom:Person \nfirstnamechar: P\nsurname: Pan\nage: 12",
|
"--- !nim:custom:Person \nfirstnamechar: P\nsurname: Pan\nage: 12",
|
||||||
output.data)
|
output.data)
|
||||||
|
|
||||||
test "Serialization: Represent cyclic data structure":
|
test "Serialization: Dump cyclic data structure":
|
||||||
var
|
var
|
||||||
a = newNode("a")
|
a = newNode("a")
|
||||||
b = newNode("b")
|
b = newNode("b")
|
||||||
|
@ -342,7 +366,7 @@ next:
|
||||||
assert(result[0] == nil)
|
assert(result[0] == nil)
|
||||||
assert(result[1][] == "~")
|
assert(result[1][] == "~")
|
||||||
|
|
||||||
test "Serialization: Represent nil values":
|
test "Serialization: Dump nil values":
|
||||||
var input = newSeq[ref string]()
|
var input = newSeq[ref string]()
|
||||||
input.add(nil)
|
input.add(nil)
|
||||||
input.add(new string)
|
input.add(new string)
|
||||||
|
|
17
yaml.nim
17
yaml.nim
|
@ -369,6 +369,11 @@ const
|
||||||
yTagNimField* : TagId = 100.TagId ## \
|
yTagNimField* : TagId = 100.TagId ## \
|
||||||
## This tag is used in serialization for the name of a field of an
|
## This tag is used in serialization for the name of a field of an
|
||||||
## object. It may contain any string scalar that is a valid Nim symbol.
|
## object. It may contain any string scalar that is a valid Nim symbol.
|
||||||
|
|
||||||
|
yTagNimNilString* : TagId = 101.TagId ## for strings that are nil
|
||||||
|
yTagNimNilSeq* : TagId = 102.TagId ## \
|
||||||
|
## for seqs that are nil. This tag is used regardless of the seq's generic
|
||||||
|
## type parameter.
|
||||||
|
|
||||||
yFirstCustomTagId* : TagId = 1000.TagId ## \
|
yFirstCustomTagId* : TagId = 1000.TagId ## \
|
||||||
## The first ``TagId`` which should be assigned to an URI that does not
|
## The first ``TagId`` which should be assigned to an URI that does not
|
||||||
|
@ -571,6 +576,18 @@ proc constructChild*[T](s: var YamlStream, c: ConstructionContext,
|
||||||
## for constructing the value. The ``ConstructionContext`` is needed for
|
## for constructing the value. The ``ConstructionContext`` is needed for
|
||||||
## potential child objects which may be refs.
|
## potential child objects which may be refs.
|
||||||
|
|
||||||
|
proc constructChild*(s: var YamlStream, c: ConstructionContext,
|
||||||
|
result: var string)
|
||||||
|
{.raises: [YamlConstructionError, YamlStreamError].}
|
||||||
|
## Constructs a Nim value that is a string from a part of a YAML stream.
|
||||||
|
## This specialization takes care of possible nil strings.
|
||||||
|
|
||||||
|
proc constructChild*[T](s: var YamlStream, c: ConstructionContext,
|
||||||
|
result: var seq[T])
|
||||||
|
{.raises: [YamlConstructionError, YamlStreamError].}
|
||||||
|
## Constructs a Nim value that is a string from a part of a YAML stream.
|
||||||
|
## This specialization takes care of possible nil seqs.
|
||||||
|
|
||||||
proc constructChild*[O](s: var YamlStream, c: ConstructionContext,
|
proc constructChild*[O](s: var YamlStream, c: ConstructionContext,
|
||||||
result: var ref O)
|
result: var ref O)
|
||||||
{.raises: [YamlConstructionError, YamlStreamError].}
|
{.raises: [YamlConstructionError, YamlStreamError].}
|
||||||
|
|
Loading…
Reference in New Issue