16 releases (breaking)
Uses new Rust 2024
| new 0.13.0 | May 22, 2026 |
|---|---|
| 0.11.0 | Mar 29, 2026 |
| 0.2.0 | Dec 30, 2025 |
#339 in Rust patterns
421 downloads per month
Used in 4 crates
(2 directly)
47KB
1K
SLoC
ploidy-pointer
This crate provides a way to traverse typed Rust data structures using JSON Pointers (RFC 6901). At its heart is the JsonPointee trait, which can be implemented on types to make them traversable.
ploidy-pointer is part of the Ploidy OpenAPI compiler, but can be used standalone.
Features
- Parse and resolve JSON Pointer strings.
- Built-in
JsonPointeeandJsonPointerTargetimplementations for primitives, collections, and common external types. - Derive
JsonPointeeandJsonPointerTargetimplementations for your own types.
Cargo features
derive(default): Enables the#[derive(JsonPointee)]and#[derive(JsonPointerTarget)]macros.did-you-mean: Adds suggestions for typos to error messages.serde_json: ImplementsJson{Pointee, PointerTarget}forserde_json::Value.chrono: ImplementsJson{Pointee, PointerTarget}forchrono::DateTime<Utc>.url: ImplementsJson{Pointee, PointerTarget}forurl::Url.indexmap: ImplementsJson{Pointee, PointerTarget}forindexmap::IndexMap.full: Enables all features.
JSON Pointer Syntax
JSON Pointers are strings that identify a specific value within a JSON structure:
""(empty string) - References the root value."/foo"- References thefoofield."/foo/0"- References the first element of thefooarray."/foo/bar"- References thebarfield of thefooobject.
Two special characters need to be escaped: ~ is written as ~0, and / is written as ~1.
Note that "/" (a single slash) does not reference the root; it references a field named "" (the empty string). If you see an "unknown key" error for a field that you know exists, double-check that an extra slash hasn't snuck in to the pointer string.
Usage
use ploidy_pointer::JsonPointeeExt;
use std::collections::HashMap;
let mut data = HashMap::new();
data.insert("foo".to_owned(), vec![1, 2, 3]);
assert_eq!(data.pointer::<i32>("/foo/1").unwrap(), 2);
Deriving JsonPointee for your own types
The #[derive(JsonPointee)] macro generates implementations of JsonPointee for structs and enums, with Serde-like attributes for customization. #[derive(JsonPointerTarget)] generates an implementation of JsonPointerTarget that extracts a reference to the concrete type from a type-erased JsonPointee.
For more details, please see the ploidy-pointer-derive docs.
use ploidy_pointer::{JsonPointee, JsonPointer, JsonPointerTarget, JsonPointeeExt};
#[derive(JsonPointee, JsonPointerTarget)]
struct User {
name: String,
age: u32,
}
let user = User {
name: "Alice".to_owned(),
age: 30,
};
// Use `pointer()` to resolve and extract in one step...
let name: &str = user.pointer("/name").unwrap();
assert_eq!(name, "Alice");
// ...Or parse and `follow()` the pointer separately.
let pointer = JsonPointer::parse("/age").unwrap();
let age: u32 = pointer.follow(&user).unwrap();
assert_eq!(age, 30);
Errors
Type errors and missing key errors omit details by default, but you can enable the did-you-mean Cargo feature to add more context to error messages. Ploidy does this to provide more helpful errors when parsing OpenAPI documents:
let pointer = JsonPointer::parse("/naem").unwrap();
match user.resolve(pointer) {
Ok(_) => unreachable!(),
Err(err) => {
// Error: unknown key "naem" for value of struct `User`;
// did you mean "name"?
println!("{}", err);
}
}
Similar crates
There are many great options for working with JSON Pointers in Rust: jsonptr, json-pointer and its forks, and serde_json::Value::pointer.
For native Rust data structures, bevy_reflect and facet offer much more powerful runtime reflection capabilities.
ploidy-pointer fills a niche somewhere in between these two, providing JSON Pointers for native Rust data structures. This is especially useful for code generators like Ploidy, and strongly-typed API clients that want to navigate structured responses.
In short:
- If you're working with structured data, and want to add type-safe JSON Pointer traversal, ploidy-pointer could be a good fit.
- If you're working with dynamic JSON documents, and want to read and write values, consider jsonptr or json-pointer.
- If you're working with simpler JSON values, and don't need more advanced features, the
pointer()method onserde_json::Valuemight be enough. - If you'd like full runtime reflection for your structured data, give bevy_reflect or facet a try.
Dependencies
~0.1–1.7MB
~30K SLoC