jsonutils: add customization for toJson via ToJsonOptions; generalize symbolName; add symbolRank (#18029)
* jsonutils: add customization for toJson via `ToJsonOptions` * add enumutils.symbolRank * lookup table implementation for HoleyEnum * cleanup * changelog * fixup * Update lib/std/jsonutils.nim Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
This commit is contained in:
parent
6e0fe965da
commit
7f077a76fe
4 changed files with 112 additions and 14 deletions
|
|
@ -31,9 +31,11 @@ add a way to customize serialization, for e.g.:
|
|||
]#
|
||||
|
||||
import macros
|
||||
from enumutils import symbolName
|
||||
from typetraits import OrdinalEnum
|
||||
|
||||
type
|
||||
Joptions* = object
|
||||
Joptions* = object # xxx rename FromJsonOptions
|
||||
## Options controlling the behavior of `fromJson`.
|
||||
allowExtraKeys*: bool
|
||||
## If `true` Nim's object to which the JSON is parsed is not required to
|
||||
|
|
@ -42,6 +44,17 @@ type
|
|||
## If `true` Nim's object to which JSON is parsed is allowed to have
|
||||
## fields without corresponding JSON keys.
|
||||
# in future work: a key rename could be added
|
||||
EnumMode* = enum
|
||||
joptEnumOrd
|
||||
joptEnumSymbol
|
||||
joptEnumString
|
||||
ToJsonOptions* = object
|
||||
enumMode*: EnumMode
|
||||
# xxx charMode
|
||||
|
||||
proc initToJsonOptions*(): ToJsonOptions =
|
||||
## initializes `ToJsonOptions` with sane options.
|
||||
ToJsonOptions(enumMode: joptEnumOrd)
|
||||
|
||||
proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".}
|
||||
proc distinctBase(T: typedesc): typedesc {.magic: "TypeTrait".}
|
||||
|
|
@ -261,33 +274,41 @@ proc jsonTo*(b: JsonNode, T: typedesc, opt = Joptions()): T =
|
|||
## reverse of `toJson`
|
||||
fromJson(result, b, opt)
|
||||
|
||||
proc toJson*[T](a: T): JsonNode =
|
||||
proc toJson*[T](a: T, opt = initToJsonOptions()): JsonNode =
|
||||
## serializes `a` to json; uses `toJsonHook(a: T)` if it's in scope to
|
||||
## customize serialization, see strtabs.toJsonHook for an example.
|
||||
when compiles(toJsonHook(a)): result = toJsonHook(a)
|
||||
elif T is object | tuple:
|
||||
when T is object or isNamedTuple(T):
|
||||
result = newJObject()
|
||||
for k, v in a.fieldPairs: result[k] = toJson(v)
|
||||
for k, v in a.fieldPairs: result[k] = toJson(v, opt)
|
||||
else:
|
||||
result = newJArray()
|
||||
for v in a.fields: result.add toJson(v)
|
||||
for v in a.fields: result.add toJson(v, opt)
|
||||
elif T is ref | ptr:
|
||||
if system.`==`(a, nil): result = newJNull()
|
||||
else: result = toJson(a[])
|
||||
else: result = toJson(a[], opt)
|
||||
elif T is array | seq | set:
|
||||
result = newJArray()
|
||||
for ai in a: result.add toJson(ai)
|
||||
elif T is pointer: result = toJson(cast[int](a))
|
||||
for ai in a: result.add toJson(ai, opt)
|
||||
elif T is pointer: result = toJson(cast[int](a), opt)
|
||||
# edge case: `a == nil` could've also led to `newJNull()`, but this results
|
||||
# in simpler code for `toJson` and `fromJson`.
|
||||
elif T is distinct: result = toJson(a.distinctBase)
|
||||
elif T is distinct: result = toJson(a.distinctBase, opt)
|
||||
elif T is bool: result = %(a)
|
||||
elif T is SomeInteger: result = %a
|
||||
elif T is Ordinal: result = %(a.ord)
|
||||
elif T is enum:
|
||||
when defined(nimLegacyJsonutilsHoleyEnum): result = %a
|
||||
else: result = %(a.ord)
|
||||
case opt.enumMode
|
||||
of joptEnumOrd:
|
||||
when T is Ordinal or not defined(nimLegacyJsonutilsHoleyEnum): %(a.ord)
|
||||
else: toJson($a, opt)
|
||||
of joptEnumSymbol:
|
||||
when T is OrdinalEnum:
|
||||
toJson(symbolName(a), opt)
|
||||
else:
|
||||
toJson($a, opt)
|
||||
of joptEnumString: toJson($a, opt)
|
||||
elif T is Ordinal: result = %(a.ord)
|
||||
elif T is cstring: (if a == nil: result = newJNull() else: result = % $a)
|
||||
else: result = %a
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue