1 unstable release
Uses new Rust 2024
| 0.1.0 | Feb 18, 2026 |
|---|
#396 in Procedural macros
74KB
1.5K
SLoC
jsonforge
A Rust procedural macro that automatically generates typed Rust data structures from local JSON files.
Features
- Zero-boilerplate type generation — point the macro at a JSON file and get a fully-typed struct instantly.
- Schema inference — field types, optional fields (
null-able), arrays, and nested objects are inferred automatically. - Runtime mode (default) — structs use owned types (
String,Vec<T>); the raw JSON is embedded as a&strconstant viainclude_str!. - Embedded mode (opt-in) — structs use
&'static str/&'static [T]fields; data is baked into the binary as a perfect-hash-function (phf) map or a fixed-length static array — no runtime file I/O, no heap allocation. - Fine-grained visibility — control the visibility of the generated struct type and its data item independently.
- Per-call embedded override — opt individual
json_forge!calls in or out of embedded mode regardless of the Cargo feature flag.
Installation
Add to your Cargo.toml:
[dependencies]
jsonforge = "0.1"
For embedded mode, enable the feature and add the phf runtime crate:
[dependencies]
jsonforge = { version = "0.1", features = ["embedded"] }
phf = "0.13"
Usage
Basic (runtime mode)
use jsonforge::json_forge;
json_forge! {
path = "data/content_types.json",
name = "ContentTypeEntry",
}
fn main() {
// A typed struct is generated from the JSON schema.
// The raw JSON is available as a `&'static str` constant.
let parsed: serde_json::Value = serde_json::from_str(CONTENT_TYPE_ENTRY_JSON).unwrap();
println!("{}", parsed["3gp"]["mime_type"]);
}
Embedded mode
use jsonforge::json_forge;
json_forge! {
path = "data/content_types.json",
name = "ContentTypeEntry",
}
fn main() {
// A static `::phf::Map` is generated — O(1) lookup, zero heap allocation.
let entry = CONTENT_TYPE_ENTRY.get("3gp").unwrap();
println!("{}", entry.mime_type.unwrap_or("unknown"));
}
All parameters
json_forge! {
path = "data/content_types.json", // path relative to CARGO_MANIFEST_DIR (required)
name = "ContentTypeEntry", // name for the generated struct (required)
vis = pub(crate), // struct visibility (default: pub)
data_vis = pub, // static / const visibility (default: same as vis)
embedded = false, // embedded mode override (default: follows feature)
}
Visibility tokens
| Token | Meaning |
|---|---|
pub |
Fully public |
pub(crate) |
Visible within the current crate |
pub(super) |
Visible to the parent module |
pub(self) |
Private to the current module (same as private) |
private |
No visibility modifier |
embedded override
| Value | Behaviour |
|---|---|
| omitted | Follows the embedded Cargo feature flag |
false |
Forces runtime mode even when the feature is enabled |
true |
Forces embedded mode; requires the embedded feature |
#[json_forge_typed] — Validate and embed a hand-written struct
When you want full control over the struct definition (field names, types, derives,
doc-comments, etc.) but still want compile-time JSON validation and automatic data
embedding, use the #[json_forge_typed] attribute macro.
How it works
- You write the struct with the exact field types you need.
- The macro reads the JSON file at compile time and verifies that every value in it is compatible with the declared field types, reporting precise errors if not.
- A companion data item is emitted right after the struct definition.
Usage
use jsonforge::json_forge_typed;
// Embedded mode (requires `embedded` feature + phf = "0.13" in deps)
#[json_forge_typed(path = "data/content_types.json")]
#[derive(Clone, Copy)]
pub struct ContentTypeEntry {
pub mime_type: Option<&'static str>,
pub group: Option<&'static str>,
pub description: Option<&'static str>,
pub extensions: &'static [&'static str],
pub is_text: bool,
}
// Runtime mode (no feature needed)
#[json_forge_typed(path = "data/content_types.json")]
#[derive(Clone)]
pub struct ContentTypeEntry {
pub mime_type: Option<String>,
pub extensions: Vec<String>,
pub is_text: bool,
}
Parameters
| Key | Description |
|---|---|
path |
JSON file path relative to CARGO_MANIFEST_DIR (required) |
data_vis |
Visibility of the emitted static/const (default: inherits the struct's vis) |
embedded |
true/false override; defaults to the embedded feature flag |
Supported field types
| Rust type | JSON type | Mode |
|---|---|---|
&'static str |
string | embedded |
String |
string | runtime |
bool |
boolean | both |
i8 … i64, u8 … u64, isize, usize |
integer number | both |
f32, f64 |
number | both |
&'static [T] |
array | embedded |
Vec<T> |
array | runtime |
Option<T> |
null or T | both |
Fields with an unrecognised type produce a compile error with the field name. JSON values incompatible with a field's declared type produce a compile error with the exact entry key and field path.
Generated items
| JSON shape | Embedded | Item |
|---|---|---|
| Object of objects | yes | static NAME: ::phf::Map<&str, Struct> |
| Array | yes | static NAME_DATA: [Struct; N] |
| Single object | yes | static NAME: Struct |
| Any shape | no | const NAME_JSON: &'static str (inlined validated JSON) |
Generated items (json_forge!)
Runtime mode
| Item | Kind | Name pattern |
|---|---|---|
| Struct | struct |
<Name> |
| Raw JSON | const &str |
<SCREAMING_SNAKE_NAME>_JSON |
Embedded mode
| Top-level JSON shape | Data item | Name pattern |
|---|---|---|
| Object of objects | static ::phf::Map<&str, Name> |
<SCREAMING_SNAKE_NAME> |
| Array | static [T; N] |
<SCREAMING_SNAKE_NAME>_DATA |
| Single object | static Name |
<SCREAMING_SNAKE_NAME> |
Type inference rules
| JSON type | Rust type (runtime) | Rust type (embedded) |
|---|---|---|
string |
String |
&'static str |
number (integer) |
i64 |
i64 |
number (float) |
f64 |
f64 |
boolean |
bool |
bool |
array |
Vec<T> |
&'static [T] |
object |
nested struct |
nested struct |
null / missing |
Option<T> |
Option<T> |
Fields that are null in any entry across the dataset are automatically promoted to Option<T>.
License
Apache-2.0
Dependencies
~0.4–1.2MB
~26K SLoC