json-bourne 0.2.1

Type-driven JSON parser. no_std-first. Zero-dep.
Documentation

Type-driven JSON: parse straight into the caller's chosen type and serialize from it, with no generic Value middle layer.

json-bourne skips the dynamic-tree intermediate that crates like serde_json use. Each type knows how to deserialize itself from a [Lexer] (via FromJson) or write itself to a [JsonWrite] sink (via [ToJson]). The typed structure already enforces JSON's grammar, so the per-event state machine is pure overhead for typed consumers — skipping it makes the typed path ~2× faster on integer / string-heavy payloads.

  • Derive-driven. #[derive(FromJson, ToJson)] (the derive feature, on by default) generates the typed impls. The generated code is itself no_std; only the compile-time derive pulls in the proc-macro stack.
  • no_std everywhere. The streaming [Lexer] / [Parser] layer is no_std always; with the default std feature off the crate is no_std + alloc, and with alloc off too it is pure no_std.
  • Borrowed strings by default. &'input str and Cow<'input, str> parse zero-copy when the input contains no escapes.
  • Bounded by construction. Container nesting is depth-limited (default 128, const-generic). The streaming parser is a state machine with no recursion.

Quick start

Parse a primitive directly into a Rust type:

use json_bourne::parse_str;
let n: u32 = parse_str("42").unwrap();
assert_eq!(n, 42);

Parse a struct with #[derive(FromJson)]:

use json_bourne::{FromJson, parse_str};

#[derive(Debug, PartialEq, FromJson)]
struct User<'input> {
    id: u64,
    name: &'input str,
    active: bool,
}

let u: User<'_> = parse_str(r#"{"id":1,"name":"alice","active":true}"#).unwrap();
assert_eq!(u.name, "alice");

Serialize back out with #[derive(ToJson)]:

use json_bourne::{ToJson, to_string};

#[derive(ToJson)]
struct Point { x: i32, y: i32 }

let s = to_string(&Point { x: 3, y: -7 }).unwrap();
assert_eq!(s, r#"{"x":3,"y":-7}"#);

Output destinations

Sink Entry point
String [to_string]
Vec<u8> [to_vec]
String (pretty-printed) [to_string_pretty]
any [std::io::Write] [to_writer] (std only)
any [core::fmt::Write] [to_fmt]

Custom sinks implement [JsonWrite] directly.

Features

Feature Default Purpose
std yes HashMap, std::net, std::path, to_writer
alloc yes String, Vec, Box/Rc/Arc, escape decoding
indexmap no IndexMap / IndexSet (insertion order)

default-features = false plus ["alloc"] gives a no_std + alloc build. default-features = false alone gives pure no_std: only the streaming [Lexer] / [Parser] and typed APIs that don't need a heap (e.g. parsing into stack-allocated primitives) are available.