WIP Deserialization of the JsonString literal fields

This commit is contained in:
Zahary Karadjov 2020-07-17 23:58:02 +03:00
parent 1cf51931f1
commit 4d8145c67b
No known key found for this signature in database
GPG Key ID: C8936F8A3073D609
4 changed files with 98 additions and 7 deletions

View File

@ -41,7 +41,7 @@ type
errNonPortableInt = "number is outside the range of portable values" errNonPortableInt = "number is outside the range of portable values"
JsonLexer* = object JsonLexer* = object
stream: InputStream stream*: InputStream
mode*: JsonMode mode*: JsonMode
line*: int line*: int
@ -61,6 +61,23 @@ const
1e20, 1e21, 1e22] # TODO: this table should be much larger 1e20, 1e21, 1e22] # TODO: this table should be much larger
# The largest JSON number value is 1E308 # The largest JSON number value is 1E308
proc renderTok*(s: JsonLexer): string =
case s.tok
of tkError, tkEof: ""
of tkString: ""
of tkInt: ""
of tkNegativeInt: ""
of tkFloat: ""
of tkTrue: "true"
of tkFalse: "false"
of tkNull: "null"
of tkCurlyLe: "{"
of tkCurlyRi: "}"
of tkBracketLe: "["
of tkBracketRi: "]"
of tkColon: ":"
of tkComma: ","
template peek(s: InputStream): char = template peek(s: InputStream): char =
char inputs.peek(s) char inputs.peek(s)

View File

@ -11,7 +11,7 @@ export
type type
JsonReader* = object JsonReader* = object
lexer*: JsonLexer lexer*: JsonLexer
forwardCompatible: bool allowUnknownFields: bool
JsonReaderError* = object of JsonError JsonReaderError* = object of JsonError
line*, col*: int line*, col*: int
@ -120,8 +120,8 @@ proc handleReadException*(r: JsonReader,
proc init*(T: type JsonReader, proc init*(T: type JsonReader,
stream: InputStream, stream: InputStream,
mode = defaultJsonMode, mode = defaultJsonMode,
forwardCompatible = false): T = allowUnknownFields = false): T =
result.forwardCompatible = forwardCompatible result.allowUnknownFields = allowUnknownFields
result.lexer = JsonLexer.init(stream, mode) result.lexer = JsonLexer.init(stream, mode)
result.lexer.next() result.lexer.next()
@ -177,13 +177,24 @@ proc skipSingleJsValue(r: var JsonReader) =
of tkString, tkInt, tkNegativeInt, tkFloat, tkTrue, tkFalse, tkNull: of tkString, tkInt, tkNegativeInt, tkFloat, tkTrue, tkFalse, tkNull:
r.lexer.next() r.lexer.next()
proc captureSingleJsValue(r: var JsonReader, value: var string) =
value = $r.lexer.tok
let pos = r.lexer.stream.createRewindPoint()
echo "skipiing ", pos
r.skipSingleJsValue()
let finalPos = r.lexer.stream.pos
echo "done ", finalPos
echo "Rewiding ", finalPos - pos
r.lexer.stream.rewindTo pos
value.setLen(finalPos - pos)
doAssert r.lexer.stream.readInto(value)
proc allocPtr[T](p: var ptr T) = proc allocPtr[T](p: var ptr T) =
p = create(T) p = create(T)
proc allocPtr[T](p: var ref T) = proc allocPtr[T](p: var ref T) =
p = new(T) p = new(T)
iterator readArray*(r: var JsonReader, ElemType: typedesc): ElemType = iterator readArray*(r: var JsonReader, ElemType: typedesc): ElemType =
mixin readValue mixin readValue
@ -240,12 +251,14 @@ proc readValue*[T](r: var JsonReader, value: var T)
r.requireToken tkString r.requireToken tkString
value = r.lexer.strVal value = r.lexer.strVal
r.lexer.next() r.lexer.next()
elif value is seq[char]: elif value is seq[char]:
r.requireToken tkString r.requireToken tkString
value.setLen(r.lexer.strVal.len) value.setLen(r.lexer.strVal.len)
for i in 0..<r.lexer.strVal.len: for i in 0..<r.lexer.strVal.len:
value[i] = r.lexer.strVal[i] value[i] = r.lexer.strVal[i]
r.lexer.next() r.lexer.next()
elif isCharArray(value): elif isCharArray(value):
r.requireToken tkString r.requireToken tkString
if r.lexer.strVal.len != value.len: if r.lexer.strVal.len != value.len:
@ -254,6 +267,7 @@ proc readValue*[T](r: var JsonReader, value: var T)
for i in 0..<value.len: for i in 0..<value.len:
value[i] = r.lexer.strVal[i] value[i] = r.lexer.strVal[i]
r.lexer.next() r.lexer.next()
elif value is bool: elif value is bool:
case tok case tok
of tkTrue: value = true of tkTrue: value = true
@ -342,6 +356,9 @@ proc readValue*[T](r: var JsonReader, value: var T)
readValue(r, value[high(value)]) readValue(r, value[high(value)])
r.skipToken tkBracketRi r.skipToken tkBracketRi
elif value is JsonString:
r.captureSingleJsValue(string value)
elif value is (object or tuple): elif value is (object or tuple):
type T = type(value) type T = type(value)
r.skipToken tkCurlyLe r.skipToken tkCurlyLe
@ -359,7 +376,7 @@ proc readValue*[T](r: var JsonReader, value: var T)
r.skipToken tkColon r.skipToken tkColon
if reader != nil: if reader != nil:
reader(value, r) reader(value, r)
elif r.forwardCompatible: elif r.allowUnknownFields:
r.skipSingleJsValue() r.skipSingleJsValue()
else: else:
const typeName = typetraits.name(T) const typeName = typetraits.name(T)

View File

@ -1,4 +1,5 @@
import import
tables,
serialization/errors serialization/errors
export export
@ -18,3 +19,6 @@ const
minPortableInt* = -9007199254740991 # -2**53 + 1 minPortableInt* = -9007199254740991 # -2**53 + 1
maxPortableInt* = 9007199254740991 # +2**53 - 1 maxPortableInt* = 9007199254740991 # +2**53 - 1
template `==`*(lhs, rhs: JsonString): bool =
string(lhs) == string(rhs)

View File

@ -36,6 +36,11 @@ type
MyUseCaseObject = object MyUseCaseObject = object
field: MyCaseObject field: MyCaseObject
HasJsonString = object
name: string
data: JsonString
id: int
# TODO `borrowSerialization` still doesn't work # TODO `borrowSerialization` still doesn't work
# properly when it's placed in another module: # properly when it's placed in another module:
Meter.borrowSerialization int Meter.borrowSerialization int
@ -111,7 +116,7 @@ suite "toJson tests":
} }
""" """
let decoded = Json.decode(json, Simple, forwardCompatible = true) let decoded = Json.decode(json, Simple, allowUnknownFields = true)
check: check:
decoded.x == -20 decoded.x == -20
@ -184,3 +189,51 @@ suite "toJson tests":
expect JsonReaderError: # too long expect JsonReaderError: # too long
discard Json.decode(Json.encode(@['a', 'b']), array[1, char]) discard Json.decode(Json.encode(@['a', 'b']), array[1, char])
test "Holders of JsonString":
let
data1 = dedent"""
{
"name": "Data 1",
"data": [1, 2, 3, 4],
"id": 101
}
"""
let
data2 = dedent"""
{
"name": "Data 2",
"data": "some string",
"id": 1002
}
"""
let
data3 = dedent"""
{
"name": "Data 3",
"data": {"field1": 10, "field2": [1, 2, 3], "field3": "test"},
"id": 10003
}
"""
try:
let
d1 = Json.decode(data1, HasJsonString)
d2 = Json.decode(data2, HasJsonString)
d3 = Json.decode(data3, HasJsonString)
check:
d1.name == "Data 1"
d1.data == JsonString "[1, 2, 3, 4]"
d1.id == 101
d2.name == "Data 2"
d2.data == JsonString "\"some string\""
d2.id == 1002
d3.name == "Data 3"
d3.data == JsonString """{"field1": 10, "field2": [1, 2, 3], "field3": "test"}"""
d3.id == 10003
except SerializationError as e:
echo e.formatMsg("<>")