All Projects → planetis-m → Eminim

planetis-m / Eminim

Licence: other
JSON serialization framework for Nim, works from a Stream directly to any type and back. Depends only on stdlib.

Programming Languages

nim
578 projects
macro
33 projects

Projects that are alternatives of or similar to Eminim

Thorsserializer
C++ Serialization library for JSON
Stars: ✭ 241 (+653.13%)
Mutual labels:  json, serialization-library, serialization, json-serialization
Savegamefree
Save Game Free is a free and simple but powerful solution for saving and loading game data in unity.
Stars: ✭ 279 (+771.88%)
Mutual labels:  serializer, serialization-library, serialization, json-serialization
JsonFormatter
Easy, Fast and Lightweight Json Formatter. (Serializer and Deserializer)
Stars: ✭ 26 (-18.75%)
Mutual labels:  serialization, serializer, json-serialization, serialization-library
Json
Lighter and Faster Json Serialization tool.
Stars: ✭ 128 (+300%)
Mutual labels:  json, serialization-library, serialization
Go
A high-performance 100% compatible drop-in replacement of "encoding/json"
Stars: ✭ 10,248 (+31925%)
Mutual labels:  json, serializer, serialization
Java
jsoniter (json-iterator) is fast and flexible JSON parser available in Java and Go
Stars: ✭ 1,308 (+3987.5%)
Mutual labels:  json, serializer, serialization
Lora Serialization
LoraWAN serialization/deserialization library for The Things Network
Stars: ✭ 120 (+275%)
Mutual labels:  serializer, serialization-library, serialization
EndianBinaryIO
A C# library that can read and write primitives, enums, arrays, and strings to streams and byte arrays with specified endianness, string encoding, and boolean sizes.
Stars: ✭ 20 (-37.5%)
Mutual labels:  serialization, serializer, serialization-library
Borer
Efficient CBOR and JSON (de)serialization in Scala
Stars: ✭ 131 (+309.38%)
Mutual labels:  json, serialization, efficient
ikeapack
Compact data serializer/packer written in Go, intended to produce a cross-language usable format.
Stars: ✭ 18 (-43.75%)
Mutual labels:  serialization, serializer, serialization-library
Panko serializer
High Performance JSON Serialization for ActiveRecord & Ruby Objects
Stars: ✭ 266 (+731.25%)
Mutual labels:  serializer, serialization, json-serialization
Dictfier
Python library to convert/serialize class instances(Objects) both flat and nested into a dictionary data structure. It's very useful in converting Python Objects into JSON format
Stars: ✭ 67 (+109.38%)
Mutual labels:  json, serializer, serialization
Hprose Php
Hprose is a cross-language RPC. This project is Hprose 3.0 for PHP
Stars: ✭ 1,952 (+6000%)
Mutual labels:  serializer, serialization-library, serialization
Symfony Jsonapi
JSON API Transformer Bundle for Symfony 2 and Symfony 3
Stars: ✭ 114 (+256.25%)
Mutual labels:  json, serializer, serialization
Hprose Js
Hprose is a cross-language RPC. This project is Hprose 2.0 RPC for JavaScript
Stars: ✭ 133 (+315.63%)
Mutual labels:  serializer, serialization-library, serialization
Play Json
The Play JSON library
Stars: ✭ 254 (+693.75%)
Mutual labels:  json, serializer, serialization
Fastjson
A fast JSON parser/generator for Java.
Stars: ✭ 23,997 (+74890.63%)
Mutual labels:  json, serialization, json-serialization
Hprose Golang
Hprose is a cross-language RPC. This project is Hprose for Golang.
Stars: ✭ 1,143 (+3471.88%)
Mutual labels:  serializer, serialization-library, serialization
Hprose Delphi
Hprose is a cross-language RPC. This project is Hprose 2.0 for Delphi and FreePascal
Stars: ✭ 100 (+212.5%)
Mutual labels:  serializer, serialization-library, serialization
Surrealist
to_json but I wrote it myself
Stars: ✭ 271 (+746.88%)
Mutual labels:  json, serializer, serialization

Eminim — JSON serialization framework for Nim

About

This package provides the jsonTo, loadJson procs and jsonItems iterator which deserializes the specified type from a Stream. The storeJson procs are used to write the JSON representation of a location into a Stream. Low level initFromJson and storeJson procs can be overloaded, in order to support arbitary container types, i.e. jsmartptrs.nim.

Usage

import std/streams, eminim

type
  Foo = ref object
    value: int
    next: Foo

let d = Foo(value: 1, next: Foo(value: 2, next: nil))
var s = newStringStream()
# Make a roundtrip
s.storeJson(d) # writes JSON from a location
# Stream's data now contain:
# {"value":1,"next":{"value":2,"next":null}}
s.setPosition(0)
let a = s.jsonTo(Foo) # reads JSON and transform to a type
# Alternatively load directly into a location
s = newStringStream()
s.storeJson(d)
s.setPosition(0)
var b: Foo
s.loadJson(b)

Features

  • Serializing and deserializing directly into Stream. For common usage it is done automatically. Generally speaking intervation is needed when working with ptr types.
  • Supports options, sets and tables by default.
  • Uses nim identifier equality algorithm to compare JSON fields. Which means fields written in camelCase or snake_case are equal.
  • Overloading serialization procs. See Examples
  • Strict field checking can be disabled at compile-time with -d:emiLenient. Meaning you can parse complex JSON structures like the World Bank dataset and retrieve only the fields you're interested.

How it works

It generates code, in compile time, to use directly the JsonParser, without creating an intermediate JsonNode tree.

For example:

type
  Bar = object
    case kind: Fruit
    of Banana:
      bad: float
      banana: int
    of Apple: apple: string

let s = newStringStream("""{"kind":"Apple","apple":"world"}""")
let a = s.jsonTo(Bar)

Produces this code:

proc initFromJson(dst: var Bar, p: var JsonParser) =
  eat(p, tkCurlyLe)
  while p.tok != tkCurlyRi:
    if p.tok != tkString:
      raiseParseErr(p, "string literal as key")
    case p.a
    of "kind":
      discard getTok(p)
      eat(p, tkColon)
      var kindTmp`gensym0: Fruit
      initFromJson(kindTmp`gensym0, p)
      dst = (typeof dst)(kind: kindTmp`gensym0)
      if p.tok != tkComma:
        break
      discard getTok(p)
      while p.tok != tkCurlyRi:
        if p.tok != tkString:
          raiseParseErr(p, "string literal as key")
        case dst.kind
        of Banana:
          case p.a
          of "bad":
            discard getTok(p)
            eat(p, tkColon)
            initFromJson(dst.bad, p)
          of "banana":
            discard getTok(p)
            eat(p, tkColon)
            initFromJson(dst.banana, p)
          else:
            raiseParseErr(p, "valid object field")
        of Apple:
          case p.a
          of "apple":
            discard getTok(p)
            eat(p, tkColon)
            initFromJson(dst.apple, p)
          else:
            raiseParseErr(p, "valid object field")
        if p.tok != tkComma:
          break
        discard getTok(p)
    else:
      raiseParseErr(p, "valid object field")
    if p.tok != tkComma:
      break
    discard getTok(p)
  eat(p, tkCurlyRi)

proc jsonTo(s: Stream, t: typedesc[Bar]): Bar =
  var p: JsonParser
  open(p, s, "unknown file")
  try:
    discard getTok(p)
    initFromJson(result, p)
    eat(p, tkEof)
  finally:
    close(p)

The jsonItems iterator

Inspired by the Machine Learning over JSON article, I originally designed eminim as a way to parse JSON datasets directly into Tensors. It's still very capable in this application.

type
  IrisPlant = object
    sepalLength: float32
    sepalWidth: float32
    petalLength: float32
    petalWidth: float32
    species: string

let fs = newFileStream("iris.json")
for x in jsonItems(fs, IrisPlant):
  # you have read an item from the iris dataset,
  # use it to create a Tensor

Limitations

  • Limited support of object variants. The discriminant field is expected first. Also there can be no fields before and after the case section. In all other cases it fails with a JsonParserError. This limitation is hard to improve. The current state might fit some use-cases and it's better than nothing.

  • Borrowing proc initFromJson[T](dst: var T; p: var JsonParser) for distinct types isn't currently working. Blocked by a Nim bug. Use overloads for now. Or you can easily override this behaviour by copying these lines in your project:

    from typetraits import distinctBase
    proc storeJson*[T: distinct](s: Stream; x: T) = storeJson(s, x.distinctBase)
    proc initFromJson*[T: distinct](dst: var T; p: var JsonParser) = initFromJson(dst.distinctBase, p)
    
  • Custom pragmas are not supported. Unless hasCustomPragma improves, this feature won't be added. You can currently substitute skipped fields by creating empty overloads.

Binary serialization

If you need binary serialization instead, check planetis-m/bingo.

Acknowledgements

  • Thanks to @krux02 for his review and valuable feedback. This rewrite wouldn't be possible without his work on json.to.
  • treeform, for his "not-strict" idea, also check out his package treeform/jsony.
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].