I'm trying to implement what's called a half-edge data structure in Rust, to represent a mesh. The naive approach obviously doesn't work in Rust:
struct HalfEdge {
face: Face,
prev: HalfEdge,
next: HalfEdge,
opposite: HalfEdge
}
So I'm trying this:
struct Mesh {
edges: Vec<HalfEdge>
}
struct HalfEdge {
mesh: Mesh, // <--- Feels weird for every HalfEdge to have to know about the mesh it's in.
prev_id: Option<usize>, // <-- This has to be optional, as the previous half edge may not have be there, while building the mesh, and forms a cycle representing a face.
... etc
}
impl HalfEdge {
fn prev(&self) -> &HalfEdge {
&self.mesh.edges[self.prev_id.expect("Explode")] // From the point of view of the mesh user, this is absolutely not optional.
}
}
It feels a bit weird - but from Rust perspective my reasoning is that the Mesh struct is the ultimate owner. When it goes - all HalfEdges, Faces, Vertices go.
is that idiomatic Rust? Various blog posts I've seen have all manner of nested Rc, RefCell, Box etc.
The downside is it still comes down to me to ensure all half-edges in a completed mesh correctly point to something (which they should - part of the reason I'm using this structure is this guarantee - and edge can't be dangling, otherwise it would represent an open or 'non-manifold' boundary). Just like unsafe code, I still leave the potential for 'edge.prev()' to blow up. So might I as well use raw pointers in my Mesh half-edge data structure? I get no help from the compiler either way. It seems, essentially, that in Rust one can't guarantee a valid cycle of structs any more than any other language?
Another thing that feels strange is the public nature of struct fields within a module - I'd like the details of HalfEdge to be entirely private, so noone ever sees 'prev_id. I know outside the module that will be true, but I want my tests, which are in the module, to have the same API.