diff --git a/json_serialization/std/options.nim b/json_serialization/std/options.nim index 39be41a..fa974c0 100644 --- a/json_serialization/std/options.nim +++ b/json_serialization/std/options.nim @@ -1,6 +1,13 @@ import std/options, ../../json_serialization/[reader, writer, lexer] export options +template writeField*(w: var JsonWriter, + fieldName: static string, + field: Option, + record: auto) = + if field.isSome: + writeField(w, fieldName, field.get, record) + proc writeValue*(writer: var JsonWriter, value: Option) = if value.isSome: writer.writeValue value.get @@ -14,4 +21,3 @@ proc readValue*[T](reader: var JsonReader, value: var Option[T]) = reader.lexer.next() else: value = some reader.readValue(T) - diff --git a/json_serialization/stew/results.nim b/json_serialization/stew/results.nim new file mode 100644 index 0000000..36137b9 --- /dev/null +++ b/json_serialization/stew/results.nim @@ -0,0 +1,26 @@ +import + stew/results, ../../json_serialization/[reader, writer, lexer] + +export + results + +template writeField*[T](w: var JsonWriter, + fieldName: static string, + field: Result[T, void], + record: auto) = + if field.isOk: + writeField(w, fieldName, field.get, record) + +proc writeValue*[T](writer: var JsonWriter, value: Result[T, void]) = + if value.isOk: + writer.writeValue value.get + else: + writer.writeValue JsonString("null") + +proc readValue*[T](reader: var JsonReader, value: var Result[T, void]) = + let tok = reader.lexer.lazyTok + if tok == tkNull: + reset value + reader.lexer.next() + else: + value.ok reader.readValue(T) diff --git a/json_serialization/writer.nim b/json_serialization/writer.nim index a90646e..d82a30c 100644 --- a/json_serialization/writer.nim +++ b/json_serialization/writer.nim @@ -142,8 +142,21 @@ template isStringLike(v: string|cstring|openArray[char]|seq[char]): bool = true template isStringLike[N](v: array[N, char]): bool = true template isStringLike(v: auto): bool = false +template writeField*[FieldType, RecordType](w: var JsonWriter, + fieldName: static string, + field: FieldType, + record: RecordType) = + mixin writeFieldIMPL + + type + F = type field + R = type record + + w.writeFieldName(fieldName) + w.writeFieldIMPL(FieldTag[R, fieldName, F], field, record) + proc writeValue*(w: var JsonWriter, value: auto) = - mixin enumInstanceSerializedFields, writeValue, writeFieldIMPL + mixin enumInstanceSerializedFields, writeValue when value is JsonNode: append if w.hasPrettyOutput: value.pretty @@ -216,12 +229,11 @@ proc writeValue*(w: var JsonWriter, value: auto) = w.writeArray(value) elif value is (object or tuple): - w.beginRecord(type(value)) type RecordType = type value + w.beginRecord RecordType value.enumInstanceSerializedFields(fieldName, field): - type FieldType = type field - w.writeFieldName(fieldName) - w.writeFieldIMPL(FieldTag[RecordType, fieldName, FieldType], field, value) + mixin writeField + writeField(w, fieldName, field, value) w.state = AfterField w.endRecord() diff --git a/tests/test_serialization.nim b/tests/test_serialization.nim index ddf0692..a434eb8 100644 --- a/tests/test_serialization.nim +++ b/tests/test_serialization.nim @@ -4,7 +4,8 @@ import serialization/testing/generic_suite, ../json_serialization, ./utils, ../json_serialization/lexer, - ../json_serialization/std/[options, sets, tables] + ../json_serialization/std/[options, sets, tables], + ../json_serialization/stew/results type Foo = object @@ -72,6 +73,10 @@ type entry, exit: TokKind dup: bool + HoldsResultOpt* = object + r*: ref Simple + o*: Opt[Simple] + var customVisit: TokenRegistry @@ -327,7 +332,15 @@ suite "toJson tests": h2 = HoldsOption(r: newSimple(1, "2", Meter(3))) Json.roundtripTest h1, """{"r":null,"o":{"distance":3,"x":1,"y":"2"}}""" - Json.roundtripTest h2, """{"r":{"distance":3,"x":1,"y":"2"},"o":null}""" + Json.roundtripTest h2, """{"r":{"distance":3,"x":1,"y":"2"}}""" + + test "Result Opt types": + let + h1 = HoldsResultOpt(o: Opt[Simple].ok Simple(x: 1, y: "2", distance: Meter(3))) + h2 = HoldsResultOpt(r: newSimple(1, "2", Meter(3))) + + Json.roundtripTest h1, """{"r":null,"o":{"distance":3,"x":1,"y":"2"}}""" + Json.roundtripTest h2, """{"r":{"distance":3,"x":1,"y":"2"}}""" test "Case object as field": let