JRef implementation in Rust
A lightweight Rust utility for serializing and deserializing complex object graphs using JSON Pointers (RFC 6901).
- 🔄 Circular Reference Support: Serialize objects that reference themselves without recursion errors.
- 🤝 Object Sharing: Preserve object identity. If multiple keys point to the same object, they will point to the same instance after deserialization.
- 📂 JSON Pointer Syntax: Fully compliant with RFC 6901, including character escaping (
~0,~1). - 🛠️ Custom Object Support: Automatically handles standard Python classes by serializing their
__dict__. - ⚙️ Customizable: Supply your own reference builders or object identification logic.
This rust code was generated from the jref_python implementation.
- Identity and Graph Representation: Python's
listanddictare inherently reference types that allow shared references and cycles. In Rust,serde_json::Valueis a tree-like structure and does not support identity or cycles. To preserve the library's functionality, I introducedJRefValue, which usesRc<RefCell<...>>for arrays and objects. This allows multiple references to the same data and circular structures, matching Python's behavior. serializeFunction:- In Python,
id(subject)is used to track seen objects. In Rust, we useRc::as_ptr(rc) as usizeto get a stable identity for containers. objectnamefieldsupport: If an object (Map) contains the specified field, its value is used as the identity key instead of the pointer address, exactly as in the Python implementation.- The
pointersmap uses anIdentityenum to handle both memory addresses and custom names.
- In Python,
deserializeFunction:- The Python implementation modifies the structure in-place and relies on Python's reference behavior.
- The Rust implementation builds the
JRefValuegraph from theserde_json::Value. - To handle circularity and forward/backward references correctly, a
location_maptrackslocation -> JRefValuemappings as objects are created (before their children are fully processed), ensuring that$refresolution can find partially-built containers.
- JSON Pointer Logic:
- Implemented
escape,unescape,append, andpointer_segmentsto match Python's logic. apply_segmentfollows the Python logic, including error messages (mapped topanic!in this translation as an equivalent to Python'sTypeError/ValueErrorwhen navigating an object).
- Implemented
- URI Encoding:
- Used
urlencodingcrate. Note that Python'squoteleaves/safe by default. The Rust code replicates this by encoding and then replacing%2Fback to/to match the$refformat seen in the tests.
- Used
- Types:
- Python
intandfloatare handled byserde_json::Number. - Python
Noneis mapped toJRefValue::Null.
- Python
- Testing:
- Translated all provided unit tests from
test_serializer.pyinto Rust#[test]functions, including scalar tests, reference tests, circularity tests, and custom naming field tests. - Identity checks in Rust use
Rc::ptr_eqto correspond to Python'sisoperator.
- Translated all provided unit tests from
- Dependencies: The code requires
serde,serde_json, andurlencoding.