json5

A Rust JSON5 parser and serializer built directly on the Serde framework.

Library
Cargo
v1.3.1
241stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
40/100Fair
Development Activity4
Maintenance20
Community56
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
76/100Good
Architecture74
Code Quality78
Innovation68
Learning Curve82

json5 (crate name json5, repo json5-rs) implements the JSON5 specification for Rust, letting you deserialize JSON5 text — with comments, trailing commas, unquoted keys, single-quoted strings, hex numbers, and multi-line strings — straight into any type that implements serde::Deserialize, and serialize Rust values back out to readable JSON5 with serde::Serialize.

It targets the common case of hand-written or hand-edited configuration files rather than machine-to-machine payloads, where serde_json remains the better fit. The crate is intentionally scoped to strict adherence to the JSON5 spec with no extensions, keeping the implementation small (roughly 3,200 lines across six source files) and easy to reason about.

What You Get

  • from_str::<T>() to parse a JSON5 string directly into any Deserialize type, including borrowed &str fields for zero-copy parsing
  • to_string() and to_writer() to serialize any Serialize type to JSON5 text, with automatic indentation and unquoted object keys where possible
  • Full JSON5 spec support: comments, trailing commas, unquoted/single-quoted keys, single-quoted strings, hexadecimal numbers, leading/trailing decimal points, explicit + signs, and line-continuation strings
  • Structured errors via Error, ErrorCode, and Position, so parse failures report an exact line/column and a specific error code rather than an opaque message
  • Byte-array support through serde_bytes, encoded as hex strings, covering the full Serde data model

Common Use Cases

  • Loading application or CLI configuration files written in JSON5 so humans can add comments and trailing commas without hand-rolling a parser
  • Round-tripping Rust config structs to a JSON5 file for a generated, human-editable settings file
  • Accepting a more forgiving JSON5 input format in tools where strict JSON would be too brittle for hand-editing
  • Swapping in as a Serde-compatible deserializer/serializer alongside serde_json where the format needs to be JSON5 instead of strict JSON

Under The Hood

Architecture — The crate is organized as three cooperating modules behind a thin lib.rs facade: de.rs (1,088 lines) implements Deserializer, a hand-written recursive-descent parser over a Peekable<CharIndices> iterator that walks the input character-by-character and drives Serde’s Visitor pattern via deserialize_any and friends; ser.rs (599 lines) implements the mirror-image Serializer, writing indented JSON5 to any std::io::Write; and error.rs (241 lines) centralizes a boxed ErrorInner { content, position } with a large ErrorCode enum (EofParsingArray, ExpectedColon, InvalidEscapeSequence, etc.) so every failure carries a precise Position { line, column }. A separate unicode.rs (1,110 lines, generated Unicode tables) backs char.rs’s identifier-character classification, kept out of the public clippy lint scope via #[allow(clippy::all, clippy::pedantic, dead_code)].

Tech Stack — Rust 2024 edition, built directly on serde (required) and ucd-trie for Unicode trie lookups used in identifier validation. Dev-dependencies include criterion for benchmarking, serde_derive/serde_json/serde_bytes for tests, and comparison crates json-five and serde_json5 used in the crate’s own throughput benchmarks against competing JSON5 implementations. The crate carries no runtime dependencies beyond serde and ucd-trie, keeping the dependency footprint minimal.

Code Quality#![warn(clippy::pedantic)] is set crate-wide, and public functions use #[must_use] and documented # Errors sections consistently. Tests live in tests/de.rs (14 #[test] functions) and tests/ser.rs (10 #[test] functions), covering the JSON5 spec section-by-section (e.g. parse_null, tests referencing ECMA-262 §7.8.1) with exact error-code and position assertions rather than just success-path checks. Error handling is explicit throughout — no unwrap()-heavy parsing — with every failure mode mapped to a named ErrorCode variant.

API Design — The public surface is deliberately small: from_str, to_string, to_writer, plus the Deserializer/Serializer structs and Error/ErrorCode/Position types. Because both traits piggyback on Serde derive macros, getting started requires zero boilerplate beyond #[derive(Deserialize)] — the README’s own quickstart is a 5-line struct plus one from_str call. The crate module doc comments double as runnable doctests, so the published documentation on docs.rs stays verified against the actual API.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search