Skip to content

Commit c81c1f0

Browse files
committed
add more hooks
Signed-off-by: George Lemon <georgelemon@protonmail.com>
1 parent bd630ae commit c81c1f0

1 file changed

Lines changed: 59 additions & 24 deletions

File tree

src/openparser/json.nim

Lines changed: 59 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,23 @@
88
##
99
## It can convert Nim objects, tables and arrays to JSON strings and vice versa.
1010
## It also provides compile-time options for customizing the serialization process.
11+
##
12+
## This JSON implementation has a similar API to [pkg/jsony](https://github.com/treeform/jsony)
13+
## but is designed to work with memory-mapped files and provide a more flexible and extensible
14+
## serialization/deserialization mechanism.
1115

1216
import std/[macros, macrocache, json, sequtils,
1317
strutils, options, tables, enumutils, memfiles,
14-
critbits]
18+
critbits, typetraits]
1519

1620
export json # re-exporting the standard JSON module for JsonNode and related types
1721

1822
type
19-
Integers* = int | int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64
23+
Integers* = int | int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64 | uint
24+
2025
AnyTable*[K, V] =
2126
Table[K, V] | OrderedTable[K, V] | TableRef[K, V] | OrderedTableRef[K, V]
27+
2228
JsonOptions* = ref object
2329
## Options for JSON serialization
2430
pretty: bool
@@ -111,10 +117,9 @@ proc dumpHook*(s: var string, val: tuple)
111117
proc dumpHook*(s: var string, val: object)
112118
proc dumpHook*[T: ref object](s: var string, val: T)
113119
proc dumpHook*(s: var string, v: enum)
114-
115120
proc dumpHook*[K: string, V](s: var string, val: AnyTable[K, V])
116-
117-
proc tableToJson*[K: string, V](t: AnyTable[K, V]): string
121+
proc dumpHook*[T](s: var string, val: set[T])
122+
proc dumpHook*[T: distinct](s: var string, v: T)
118123

119124
proc toJson*[T](v: T, opts: JsonOptions = nil): string =
120125
## Convert a Nim object to its JSON string representation using dump hooks.
@@ -148,16 +153,9 @@ macro toStaticJson*(v: typed, opts: static JsonOptions = nil): untyped =
148153
#
149154
# Dump Hooks for JSON Serialization
150155
#
151-
proc dumpTableImpl[K: string, V, T](s: var string, t: T) =
152-
s.add("{")
153-
var i = 0
154-
for k, item in t.pairs:
155-
if i > 0: s.add(",")
156-
dumpHook(s, k)
157-
s.add(":")
158-
dumpHook(s, item)
159-
inc i
160-
s.add("}")
156+
proc dumpHook*[T: distinct](s: var string, v: T) =
157+
var x = cast[T.distinctBase](v)
158+
s.dumpHook(x)
161159

162160
proc dumpHook*[K: string, V](s: var string, val: AnyTable[K, V]) =
163161
## Converts Table/OrderedTable and ref variants to JSON object.
@@ -186,6 +184,16 @@ proc dumpHook*[K: string, V](s: var string, val: AnyTable[K, V]) =
186184

187185
s.add("}")
188186

187+
proc dumpHook*[T](s: var string, val: set[T]) =
188+
## Converts a set to a JSON array.
189+
s.add("[")
190+
var i = 0
191+
for item in val:
192+
if i > 0: s.add(",")
193+
dumpHook(s, item)
194+
inc i
195+
s.add("]")
196+
189197
proc dumpHook*[T](s: var string, arr: seq[T]) =
190198
## Converts a sequence of items to a JSON array string.
191199
s.add("[")
@@ -289,12 +297,6 @@ proc objectToJson*(v, valImpl: NimNode, opts: JsonOptions = nil): NimNode =
289297
`res`.add("}")
290298
`res`
291299

292-
proc tableToJson*[K: string, V](t: AnyTable[K, V]): string =
293-
## Converts a Nim table to JSON string.
294-
var s = ""
295-
dumpTableImpl(s, t)
296-
result = s
297-
298300
proc arrayToJson*(v, valImpl: NimNode, opts: JsonOptions = nil): NimNode =
299301
## Converts a Nim array or sequence to its JSON representation.
300302
var strArrayItems = newStmtList()
@@ -521,6 +523,7 @@ proc parseHook*[T](parser: var Parser, field: string, v: var seq[T])
521523
proc parseHook*[T: ref object](parser: var Parser, field: string, v: var T)
522524
proc parseHook*[T: enum](parser: var Parser, field: string, v: var T)
523525
proc parseHook*[K: string, V](parser: var Parser, field: string, v: var AnyTable[K, V])
526+
proc parseHook*[T](parser: var Parser, field: string, v: var set[T])
524527

525528
proc skipValue*(parser: var Parser)
526529

@@ -655,6 +658,27 @@ proc parseHook*[T: enum](parser: var Parser, field: string, v: var T) =
655658
else:
656659
parser.error(unexpectedTokenExpected % [$parser.curr.kind, "string or number"])
657660

661+
proc parseHook*[T](parser: var Parser, field: string, v: var set[T]) =
662+
## A hook to parse set fields from JSON arrays
663+
parser.expectSkip(tkLBracket) # start of array
664+
while parser.curr.kind != tkRBracket:
665+
var item: T
666+
parser.parseHook("", item)
667+
v.incl(item)
668+
if parser.curr.kind == tkComma:
669+
parser.walk()
670+
parser.expectSkip(tkRBracket) # end of array
671+
672+
proc parseHook*[T: distinct](parser: var Parser, field: string, v: var T) =
673+
## A hook to parse distinct types by parsing their base type and then converting
674+
var tmp: T.distinctBase
675+
parser.parseHook("", tmp)
676+
v = T(tmp)
677+
678+
proc parseHook*[T: Integers](parser: var Parser, field: string, v: var T) =
679+
## A hook to parse integer fields
680+
v = cast[v.type](parser.curr.value.get().parseInt())
681+
658682
macro getObjectFields(obj: typed): untyped =
659683
let objImpl = obj.getType()
660684
let tempFields =
@@ -675,7 +699,7 @@ macro getObjectFields(obj: typed): untyped =
675699
else: discard
676700
result = newStmtList().add(nnkPrefix.newTree(ident"@", fieldList))
677701

678-
proc parseHook*(parser: var Parser, field: string, v: var object) =
702+
proc parseHook*[T: object|ref object](parser: var Parser, field: string, v: var T) =
679703
## Custom parsing for Address field
680704
parser.expectSkip(tkLBrace) # start of object
681705
const objectFields: seq[string] = getObjectFields(v)
@@ -689,8 +713,19 @@ proc parseHook*(parser: var Parser, field: string, v: var object) =
689713
if key == objField:
690714
parser.walk() # advance to field name
691715
parser.expectSkip(tkColon)
692-
# call the appropriate parseHook based on field type
693-
parser.parseHook(objField, objVal)
716+
717+
when compiles(parser.parseHook(objField, objVal)):
718+
# normal mutable fields
719+
parser.parseHook(objField, objVal)
720+
else:
721+
# immutable fields (e.g. variant discriminator like `type`)
722+
var tmp: type(objVal)
723+
parser.parseHook(objField, tmp)
724+
when compiles(objVal = tmp):
725+
objVal = tmp
726+
else:
727+
parser.error("Field `" & objField & "` is immutable")
728+
694729
if parser.curr.kind != tkRBrace:
695730
parser.walk() # advance to next token
696731
break all

0 commit comments

Comments
 (0)