Hello,
I am the author of the gltf
crate and need some help generating a wrapper interface for some unfriendly data structures.
Context
glTF is a standard for loading 3D models which are described by JSON data. The
gltf
crate deserialises this JSON into Rust data structures. I would like to
provide a wrapper interface around this data to make the crate more friendly to
use and to provide extra features.
The main problem I want to address is that the JSON references other data
using indices into arrays contained in the root JSON object. Dereferencing this
data is cumbersome and perhaps error-prone as demonstrated below.
// We have to pass the root object around whenever we access other data
fn process_node(gltf: &Gltf, node: &Node) -> Result {
for child_node_id in &node.children {
// What if `node` does not belong to `gltf`? (potential `panic!`)
let child_node = gltf.nodes.get(child_node_id);
process_node(gltf, child_node)?;
}
if let Some(mesh_id) = node.mesh.as_ref() {
let mesh = gltf.meshes.get(mesh_id);
process_mesh(gltf, mesh)?;
}
...
}
fn process_gltf() -> Result {
let gltf = import("Foo.gltf")?;
for scene in &gltf.scenes {
for node_id in &scene.nodes {
let node = gltf.scenes.get(node_id);
process_node(gltf, node)?;
}
}
...
}
Instead I would like to provide a wrapper interface that allows easy retrieval
of referenced data. The result might look like this:
fn process_node(node: &Node) -> Result {
// `child` is guaranteed to belong to the same glTF as `node`
for child in node.iter_child_nodes() {
process_node(child)?;
}
// Easy and safe retrieval of referenced data
if let Some(mesh) = node.mesh() {
process_mesh(mesh)?;
}
...
}
fn process_gltf() -> Result {
let gltf = import("Foo.gltf")?;
for scene in gltf.iter_scenes() {
for node in scene.iter_nodes() {
process_node(node)?;
}
}
...
}
Question
In order to write this interface I have to turn all the pub
data members
into methods and the documentation must match exactly. For example, consider
buffer::View
which holds a reference to a buffer::Buffer
:
/// Doc A
pub struct View {
/// Doc B
pub buffer: Index<Buffer>,
...
}
A corresponding wrapper struct might look like this:
/// Doc A
pub struct View<'a> {
root: &'a json::Root,
view: &'a json::buffer::View,
}
impl<'a> View<'a> {
/// Doc B
pub fn buffer(&self) -> Buffer<'a> {
Buffer {
root: self.root,
buffer: self.root.get(&self.view.buffer),
}
}
}
In the implemenation of the wrapper I want to avoid:
- Using
Deref
as a way of inheriting data items - Manually (re-)writing all the code
Does anyone know a way of generating such code?