diff --git a/json_serialization/reader.nim b/json_serialization/reader.nim index 4ab9749..e89cc52 100644 --- a/json_serialization/reader.nim +++ b/json_serialization/reader.nim @@ -17,10 +17,6 @@ type encounteredField*: cstring deserializedType*: cstring - CustomSerializationError* = object of JsonReaderError - deserializedField*: string - innerException*: ref CatchableError - ExpectedTokenCategory* = enum etBool = "bool literal" etInt = "integer" @@ -33,6 +29,10 @@ type etCurrlyLe = "object start bracket" etCurrlyRi = "object end bracket" + GenericJsonReaderError* = object of JsonReaderError + deserializedField*: string + innerException*: ref CatchableError + UnexpectedToken* = object of JsonReaderError encountedToken*: TokKind expectedToken*: ExpectedTokenCategory @@ -46,8 +46,8 @@ method formatMsg*(err: ref UnexpectedField, filename: string): string = method formatMsg*(err: ref UnexpectedToken, filename: string): string = fmt"{filename}({err.line}, {err.col}) Unexpected token '{err.encountedToken}' in place of '{err.expectedToken}'" -method formatMsg*(err: ref CustomSerializationError, filename: string): string = - fmt"{filename}({err.line}, {err.col}) Custom serialization exception while deserializing '{err.deserializedField}': [{err.innerException.name}] {err.innerException.msg}" +method formatMsg*(err: ref GenericJsonReaderError, filename: string): string = + fmt"{filename}({err.line}, {err.col}) Exception encountered while deserializing '{err.deserializedField}': [{err.innerException.name}] {err.innerException.msg}" template init*(T: type JsonReader, stream: ByteStreamVar, mode = defaultJsonMode): auto = init JsonReader, AsciiStreamVar(stream), mode @@ -70,10 +70,12 @@ proc raiseUnexpectedField(r: JsonReader, fieldName, deserializedType: cstring) = ex.deserializedType = deserializedType raise ex -proc readValueFailed*(r: JsonReader, - Record: type, fieldName: string, field: var auto, - err: ref CatchableError) = - var ex = new CustomSerializationError +proc handleReadException*(r: JsonReader, + Record: type, + fieldName: string, + field: var auto, + err: ref CatchableError) = + var ex = new GenericJsonReaderError ex.assignLineNumber(r) ex.deserializedField = fieldName ex.innerException = err diff --git a/json_serialization/writer.nim b/json_serialization/writer.nim index f164a00..dae4e14 100644 --- a/json_serialization/writer.nim +++ b/json_serialization/writer.nim @@ -125,6 +125,8 @@ proc writeArray[T](w: var JsonWriter, elements: openarray[T]) = writeIterable(w, elements) proc writeValue*(w: var JsonWriter, value: auto) = + mixin enumInstanceSerializedFields + template addChar(c) = append c @@ -161,7 +163,6 @@ proc writeValue*(w: var JsonWriter, value: auto) = # TODO: Should this really use a decimal representation? # Or perhaps $ord(c) returns hex? # This is potentially a bug in Nim's json module. - # In any case, we can call appendNumber here. append $ord(c) of '\\': addPrefixSlash '\\' else: addChar c @@ -170,16 +171,16 @@ proc writeValue*(w: var JsonWriter, value: auto) = elif value is bool: append if value: "true" else: "false" elif value is enum: - w.stream.appendNumber ord(value) + w.stream.append $ord(value) elif value is SomeInteger: - w.stream.appendNumber value + w.stream.append $value elif value is SomeFloat: append $value elif value is (seq or array): w.writeArray(value) elif value is (object or tuple): w.beginRecord(type(value)) - value.serializeFields(k, v): + value.enumInstanceSerializedFields(k, v): w.writeField k, v w.endRecord() else: diff --git a/tests/test_serialization.nim b/tests/test_serialization.nim index c6f535a..0560443 100644 --- a/tests/test_serialization.nim +++ b/tests/test_serialization.nim @@ -1,5 +1,6 @@ import strutils, unittest, + serialization/object_serialization, serialization/testing/generic_suite, ../json_serialization, ./utils, ../json_serialization/std/[options, sets] @@ -12,10 +13,11 @@ type x: int y: string distance: Meter + ignored: int Foo = object i: int - b: Bar + b {.dontSerialize.}: Bar s: string Bar = object @@ -41,6 +43,8 @@ template reject(code) = borrowSerialization(Meter, int) +Simple.setSerializedFields distance, x, y + proc `==`(lhs, rhs: Meter): bool = int(lhs) == int(rhs) @@ -74,21 +78,21 @@ suite "toJson tests": var s = Simple(x: 10, y: "test", distance: Meter(20)) check: - s.toJson == """{"x":10,"y":"test","distance":20}""" - s.toJson(typeAnnotations = true) == """{"$type":"Simple","x":10,"y":"test","distance":20}""" + s.toJson == """{"distance":20,"x":10,"y":"test"}""" + s.toJson(typeAnnotations = true) == """{"$type":"Simple","distance":20,"x":10,"y":"test"}""" s.toJson(pretty = true) == dedent""" { + "distance": 20, "x": 10, - "y": "test", - "distance": 20 + "y": "test" } """ test "handle missing fields": let json = dedent""" { - "y": "test", - "distance": 20 + "distance": 20, + "y": "test" } """ @@ -135,8 +139,8 @@ suite "toJson tests": h1 = HoldsOption(o: some Simple(x: 1, y: "2", distance: Meter(3))) h2 = HoldsOption(r: newSimple(1, "2", Meter(3))) - Json.roundtripTest h1, """{"r":null,"o":{"x":1,"y":"2","distance":3}}""" - Json.roundtripTest h2, """{"r":{"x":1,"y":"2","distance":3},"o":null}""" + Json.roundtripTest h1, """{"r":null,"o":{"distance":3,"x":1,"y":"2"}}""" + Json.roundtripTest h2, """{"r":{"distance":3,"x":1,"y":"2"},"o":null}""" test "Set types": type HoldsSet = object