Files
Jacek Sieka bc49ad85ec Add array streaming helpers (#115)
An implementation of
https://github.com/status-im/nim-json-serialization/issues/112 that
introduces `beginArray`/`endArray` for the streaming creation of arrays.

In order to accomodate the need for intra-element plumbing, we add
`begin`/`end` marker calls to the `writeValue` implementation which
helps the writer keep track of each value being written and therefore
allows it to inject the correct delimiters and indents.

Here's an example of writing a `writeValue` overload that writes an
array nested in an object:

```nim
proc writeValue(w: var JsonWriter, t: MyType) =
  w.beginArray()

  for i in 0 ..< t.children:
    writer.beginObject()

    writer.writeMember("id", i)
    writer.writeMember("name", "item" & t.childName[i])

    writer.endObject()

  writer.endArray()
```

Similar to the existing `beginRecord`/`endRecord` fields we add
`beginArray` and `endArray` - we also take the opportunity to name
`beginObject` according to its json-spec-derived name. The old name
remains available.

This change introduces a backwards-compatibility break for custom
writers that try to access the stream directly: they now have to delimit
their value writing with `w.streamElement(s): s.write ...` where `s` is
the stream variable. The block template enforces begin/end markers on
behalf of the writer.

Further examples are available in the documentation.

With this change, we also deprecate workarounds like `fieldWritten` and
`endRecordField` since a regular replacement exists in the form of
consistent begin/end pairs.

* doc fixes

* make beginElement/endElement private

Should not be called directly as `writeValue` / `streamElement` take
care of it.
2025-07-04 10:50:17 +02:00

67 lines
1.6 KiB
Nim

import std/json, json_serialization
# ANCHOR: Decode
const rawJson = """{"name": "localhost", "port": 42}"""
type
NimServer = object
name: string
port: int
MixedServer = object
name: JsonValueRef[uint64]
port: int
StringServer = object
name: JsonString
port: JsonString
var conf = defaultJsonReaderConf
conf.nestedDepthLimit = 0
# decode into native Nim
let native = Json.decode(rawJson, NimServer)
# decode into mixed Nim + JsonValueRef
let mixed = Json.decode(rawJson, MixedServer)
# decode any value into nested json string
let str = Json.decode(rawJson, StringServer)
# decode any valid JSON, using the `json_serialization` node type
let value = Json.decode(rawJson, JsonValueRef[uint64])
# decode any valid JSON, using the `std/json` node type
let stdjson = Json.decode(rawJson, JsonNode)
# read JSON document from file instead
let file = Json.loadFile("filename.json", NimServer)
# ANCHOR_END: Decode
# ANCHOR: Reader
var reader = JsonReader[DefaultFlavor].init(memoryInput(rawJson))
let native2 = reader.readValue(NimServer)
# Overwrite an existing instance
var reader2 = JsonReader[DefaultFlavor].init(memoryInput(rawJson))
var native3: NimServer
reader2.readValue(native3)
# ANCHOR_END: Reader
# ANCHOR: Encode
# Convert object to string
echo Json.encode(native)
# Write JSON to file
Json.saveFile("filename.json", native)
# Pretty-print a tuple
echo Json.encode((x: 4, y: 5), pretty = true)
# ANCHOR_END: Encode
# ANCHOR: Writer
var output = memoryOutput()
var writer = JsonWriter[DefaultFlavor].init(output)
writer.writeValue(native)
echo output.getOutput(string)
# ANCHOR_END: Writer