GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — GitHub - Marcono1234/struson: Streaming JSON reader and writer written in Rust

BranchesTags
Open more actions menu

Latest commit

 

History

405 Commits
405 Commits

Folders and files

NameName
Last commit message
Last commit date
.github
.github
 
 
benches
benches
 
 
src
src
 
 
tests
tests
 
 
.gitignore
.gitignore
 
 
Cargo.lock
Cargo.lock
 
 
Cargo.toml
Cargo.toml
 
 
LICENSE-APACHE
LICENSE-APACHE
 
 
LICENSE-MIT
LICENSE-MIT
 
 
Makefile.toml
Makefile.toml
 
 
README.md
README.md
 
 
ReleaseProcess.md
ReleaseProcess.md
 
 
SECURITY.md
SECURITY.md
 
 
rust-toolchain.toml
rust-toolchain.toml
 
 

Repository files navigation

Struson
crates.io docs.rs

Struson is an RFC 8259 compliant streaming JSON reader and writer.

Its main purpose is to allow reading and writing JSON documents in a memory efficient way without having to store the complete JSON document structure in memory.

The API of Struson was inspired by the streaming API of the Java library Gson (classes JsonReader and JsonWriter). It is rather low-level and its methods correspond to the elements of a JSON document, with little abstraction on top of it, allowing to read and write any valid JSON document regardless of its structure or content.

Note

This library is still experimental. The performance is not very good yet and the API might be changed in future versions; releases < 1.0.0 might not follow Semantic Versioning, breaking changes may occur.
Feedback and suggestions for improvements are welcome!

Why?

The most popular JSON Rust crates Serde JSON (serde_json) and json-rust (json) mainly provide high level APIs for working with JSON.

  • Serde JSON provides an API for converting JSON into DOM like structures (module serde_json::value) and object mapper functionality by converting structs to JSON and vice versa. Both requires the complete value to be present in memory. The trait serde_json::ser::Formatter actually allows writing JSON in a streaming way, but its API is arguably too low level and inconvenient to use: You have to handle string escaping yourself, and you always have to provide the writer as argument for every method call.
    Note however, that Serde JSON's StreamDeserializer allows reading multiple top-level values in a streaming way, and that certain streaming use cases can be solved with custom Visitor implementations, see the documentation for examples of streaming an array and discarding data.

  • json-rust provides an API for converting JSON into DOM like structures (enum json::JsonValue), this requires the complete value to be present in memory. The trait json::codegen::Generator offers a partial API for writing JSON in a streaming way, however it misses methods for writing JSON arrays and objects in a streaming way.

If you need to process JSON in a DOM like way or want object mapper functionality to convert structs to JSON and vice versa, then Struson is not suited for your use case and you should instead use one of the libraries above.

Main features

  • Low level streaming API, no implicit value conversion
  • Strong enforcement of correct API usage
  • Panics only for incorrect API usage
    Malformed JSON and unexpected JSON structure only causes errors
  • API does not require recursion for JSON arrays and objects
    Can theoretically read and write arbitrarily deeply nested JSON data
  • Read and write arbitrarily precise JSON numbers as string
    (JsonReader::next_number_as_str and JsonWriter::number_value_from_string)
  • Seek to specific location in JSON data (JsonReader::seek_to)
  • Transfer JSON data from a reader to a writer (JsonReader::transfer_to)
  • Read and write arbitrarily large JSON string values
    (JsonReader::next_string_reader and JsonWriter::string_value_writer)
  • Optional Serde integration

Usage examples

Two variants of the API are provided:

  • simple: ensures correct API usage at compile-time
  • advanced: ensures correct API usage only at runtime (by panicking); more flexible and provides more functionality

Simple API

Note

🔬 Experimental
The simple API and its naming is currently experimental, please provide feedback here. It has to be enabled by specifying the simple-api feature in Cargo.toml:

[dependencies]
struson = { version = "...", features = ["simple-api"] }

Any feedback is appreciated!

Reading

See SimpleJsonReader.

use struson::reader::simple::*;

// In this example JSON data comes from a string;
// normally it would come from a file or a network connection
let json_reader = SimpleJsonReader::new(r#"["a", "short", "example"]"#.as_bytes());
let mut words = Vec::<String>::new();
json_reader.read_array_items(|item_reader| {
    let word = item_reader.read_string()?;
    words.push(word);
    Ok(())
})?;
assert_eq!(words, vec!["a", "short", "example"]);

For reading nested values, the methods read_seeked and read_seeked_multi can be used:

use struson::reader::simple::*;
use struson::reader::simple::multi_json_path::multi_json_path;

// In this example JSON data comes from a string;
// normally it would come from a file or a network connection
let json = r#"{
    "users": [
        {"name": "John", "age": 32},
        {"name": "Jane", "age": 41}
    ]
}"#;
let json_reader = SimpleJsonReader::new(json.as_bytes());

let mut ages = Vec::<u32>::new();
// Select the ages of all users
let json_path = multi_json_path!["users", [*], "age"];
json_reader.read_seeked_multi(&json_path, false, |value_reader| {
    let age = value_reader.read_number()??;
    ages.push(age);
    Ok(())
})?;
assert_eq!(ages, vec![32, 41]);

Writing

See SimpleJsonWriter.

use struson::writer::simple::*;

// In this example JSON bytes are stored in a Vec;
// normally they would be written to a file or network connection
let mut writer = Vec::<u8>::new();
let json_writer = SimpleJsonWriter::new(&mut writer);
json_writer.write_object(|object_writer| {
    object_writer.write_number_member("a", 1)?;
    object_writer.write_bool_member("b", true)?;
    Ok(())
})?;

let json = String::from_utf8(writer)?;
assert_eq!(json, r#"{"a":1,"b":true}"#);

Advanced API

Reading

See JsonStreamReader.

use struson::reader::*;

// In this example JSON data comes from a string;
// normally it would come from a file or a network connection
let json = r#"{"a": [1, true]}"#;
let mut json_reader = JsonStreamReader::new(json.as_bytes());

json_reader.begin_object()?;
assert_eq!(json_reader.next_name()?, "a");

json_reader.begin_array()?;
assert_eq!(json_reader.next_number::<u32>()??, 1);
assert_eq!(json_reader.next_bool()?, true);
json_reader.end_array()?;

json_reader.end_object()?;
// Ensures that there is no trailing data
json_reader.consume_trailing_whitespace()?;

Writing

See JsonStreamWriter.

use struson::writer::*;

// In this example JSON bytes are stored in a Vec;
// normally they would be written to a file or network connection
let mut writer = Vec::<u8>::new();
let mut json_writer = JsonStreamWriter::new(&mut writer);

json_writer.begin_object()?;
json_writer.name("a")?;

json_writer.begin_array()?;
json_writer.number_value(1)?;
json_writer.bool_value(true)?;
json_writer.end_array()?;

json_writer.end_object()?;
// Ensures that the JSON document is complete and flushes the buffer
json_writer.finish_document()?;

let json = String::from_utf8(writer)?;
assert_eq!(json, r#"{"a":[1,true]}"#);

Serde integration

Optional integration with Serde exists to allow writing a Serialize to a JsonWriter and reading a Deserialize from a JsonReader. See the serde module of this crate for more information.

Changelog

See GitHub releases.

Building

This project uses cargo-make for building:

cargo make

If you don't want to install cargo-make, you can instead manually run the tasks declared in the Makefile.toml.

Similar projects

Similar Rust streaming JSON libraries by other authors. These might be suitable alternatives in case Struson does not meet your needs. Alternatively feel free to create a new feature request for Struson (in case there is no existing request yet).

These projects were selected based on their description and API documentation. I have not checked them for correctness or performance, use at your own risk.

  • https://github.com/alexmaco/json_stream

    A streaming JSON parser/emitter library for rust

  • https://github.com/sarum90/qjsonrs

    JSON Tokenizer written in Rust

  • https://github.com/jeremiah-shaulov/nop-json

    JSON serialization/deserialization (full-featured, modern, streaming, direct into struct/enum)

  • https://github.com/isagalaev/ijson-rust

    Rust re-implementation of the Python streaming JSON parser ijson

  • https://github.com/byron/json-tools

    A zero-copy json-lexer, filters and serializer.

  • https://github.com/01mf02/hifijson

    High-fidelity JSON lexer and parser

  • https://github.com/khonsulabs/justjson's justjson::parser::Tokenizer

    A JSON tokenizer, which converts JSON source to a series of Tokens

  • https://github.com/iovxw/jsonpull

    Json pull parser

  • https://github.com/zotta/json-writer-rs

    Simple and fast crate for writing JSON to a string without creating intermediate objects

  • https://crates.io/crates/jsn

    A queryable, streaming, JSON pull-parser with low allocation overhead.

  • https://github.com/michel-kraemer/actson-rs

    Actson is a low-level JSON parser for reactive applications and non-blocking I/O.

  • https://github.com/core-json/core-json

    A non-allocating no-std JSON deserializer in Rust

  • https://github.com/pydantic/jiter

    Fast iterable JSON parser

  • rustc-serialize Parser (deprecated)

    A streaming JSON parser implemented as an iterator of JsonEvent, consuming an iterator of char.

License

Licensed under either of

  • Apache License, Version 2.0
  • MIT License

at your option.

All contributions you make to this project are licensed implicitly under both licenses mentioned above, without any additional terms or conditions.

Note: This dual-licensing is the same you see for the majority of Rust projects, see also the Rust API Guidelines.

About

Streaming JSON reader and writer written in Rust

crates.io/crates/struson

Topics

jsonjson-streampull-parserserde

Resources

Readme

Security policy

Security policy
Activity

Stars

106 stars

Watchers

1 watching

Forks

11 forks
Report repository

Releases

Used by

Contributors

Languages

You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.