From 706eb5740ecf509edaf64d59047069f414b1afca Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Thu, 18 Mar 2021 13:01:06 +0200 Subject: [PATCH] Add support for serialization flavors --- json_serialization/reader.nim | 11 +++++++--- json_serialization/writer.nim | 18 +++++++-------- tests/test_json_flavor.nim | 41 +++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 12 deletions(-) create mode 100644 tests/test_json_flavor.nim diff --git a/json_serialization/reader.nim b/json_serialization/reader.nim index 8ed597f..af8d7af 100644 --- a/json_serialization/reader.nim +++ b/json_serialization/reader.nim @@ -11,7 +11,7 @@ export types, errors type - JsonReader* = object + JsonReader*[Flavor = DefaultFlavor] = object lexer*: JsonLexer allowUnknownFields: bool @@ -176,7 +176,11 @@ proc parseJsonNode(r: var JsonReader): JsonNode = r.lexer.next() if r.lexer.tok != tkCurlyRi: while r.lexer.tok == tkString: - r.readJsonNodeField(result.fields.mgetOrPut(r.lexer.strVal, nil)) + r.readJsonNodeField( + try: + result.fields.mgetOrPut(r.lexer.strVal, nil) + except KeyError: + raiseAssert "mgetOrPut should never raise a KeyError") if r.lexer.tok == tkComma: r.lexer.next() else: @@ -368,6 +372,7 @@ template isCharArray(v: auto): bool = false proc readValue*[T](r: var JsonReader, value: var T) {.raises: [SerializationError, IOError, Defect].} = mixin readValue + type ReaderType = type r let tok {.used.} = r.lexer.tok @@ -495,7 +500,7 @@ proc readValue*[T](r: var JsonReader, value: var T) r.skipToken tkCurlyLe when T.totalSerializedFields > 0: - let fields = T.fieldReadersTable(JsonReader) + let fields = T.fieldReadersTable(ReaderType) var expectedFieldPos = 0 while r.lexer.tok == tkString: when T is tuple: diff --git a/json_serialization/writer.nim b/json_serialization/writer.nim index f64d4dc..9a87828 100644 --- a/json_serialization/writer.nim +++ b/json_serialization/writer.nim @@ -9,7 +9,7 @@ type RecordStarted AfterField - JsonWriter* = object + JsonWriter*[Flavor = DefaultFlavor] = object stream*: OutputStream hasTypeAnnotations: bool hasPrettyOutput*: bool # read-only @@ -19,13 +19,13 @@ type export JsonString -proc init*(T: type JsonWriter, stream: OutputStream, - pretty = false, typeAnnotations = false): T = - result.stream = stream - result.hasPrettyOutput = pretty - result.hasTypeAnnotations = typeAnnotations - result.nestingLevel = if pretty: 0 else: -1 - result.state = RecordExpected +proc init*(W: type JsonWriter, stream: OutputStream, + pretty = false, typeAnnotations = false): W = + W(stream: stream, + hasPrettyOutput: pretty, + hasTypeAnnotations: typeAnnotations, + nestingLevel: if pretty: 0 else: -1, + state: RecordExpected) proc beginRecord*(w: var JsonWriter, T: type) proc beginRecord*(w: var JsonWriter) @@ -228,7 +228,7 @@ proc toJson*(v: auto, pretty = false, typeAnnotations = false): string = mixin writeValue var s = memoryOutput() - var w = JsonWriter.init(s, pretty, typeAnnotations) + var w = JsonWriter[DefaultFlavor].init(s, pretty, typeAnnotations) w.writeValue v return s.getOutput(string) diff --git a/tests/test_json_flavor.nim b/tests/test_json_flavor.nim new file mode 100644 index 0000000..8921831 --- /dev/null +++ b/tests/test_json_flavor.nim @@ -0,0 +1,41 @@ +import + strutils, + serialization, + ../json_serialization + +Json.createFlavor StringyJson + +proc writeValue*(w: var JsonWriter[StringyJson], val: SomeInteger) = + writeValue(w, $val) + +proc readValue*(r: var JsonReader[StringyJson], v: var SomeSignedInt) = + try: + v = type(v) parseBiggestInt readValue(r, string) + except ValueError as err: + r.raiseUnexpectedValue("A signed integer encoded as string") + +proc readValue*(r: var JsonReader[StringyJson], v: var SomeUnsignedInt) = + try: + v = type(v) parseBiggestUInt readValue(r, string) + except ValueError as err: + r.raiseUnexpectedValue("An unsigned integer encoded as string") + +type + Container = object + name: string + x: int + y: uint64 + list: seq[int64] + +let c = Container(name: "c", x: -10, y: 20, list: @[1'i64, 2, 25]) +let encoded = StringyJson.encode(c) +echo "Encoded: ", encoded + +let decoded = try: + StringyJson.decode(encoded, Container) +except SerializationError as err: + echo err.formatMsg("") + quit 1 + +echo "Decoded: ", decoded +