3 releases (breaking)
0.3.0 | Sep 5, 2023 |
---|---|
0.2.0 | Aug 6, 2023 |
0.1.0 | Apr 22, 2023 |
#232 in Parser implementations
2,219 downloads per month
Used in sindit-senml
555KB
10K
SLoC
Struson is an RFC 8259 compliant streaming JSON reader and writer.
Its main purpose is to allow 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.
ℹ 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 traitserde_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'sStreamDeserializer
allows reading multiple top-level values in a streaming way, and that certain streaming use cases can be solved with customVisitor
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 traitjson::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 arbitrarily precise JSON numbers as 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
andJsonWriter::string_value_writer
) - Optional Serde integration
Usage examples
Reading
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!("a", json_reader.next_name()?);
json_reader.begin_array()?;
assert_eq!(1_u32, json_reader.next_number()??);
assert_eq!(true, json_reader.next_bool()?);
json_reader.end_array()?;
json_reader.end_object()?;
// Ensures that there is no trailing data
json_reader.consume_trailing_whitespace()?;
Writing
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()?;
assert_eq!(r#"{"a":[1,true]}"#, String::from_utf8(writer)?);
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
- 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
- rustc-serialize
Parser
(deprecated)A streaming JSON parser implemented as an iterator of JsonEvent, consuming an iterator of char.
License
Licensed under either of
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.
Dependencies
~0.4–0.9MB
~21K SLoC