如何在Rust中实现无UB的Half Edge(半边)数据结构接口?
在Rust中实现无UB的半边(Half Edge)链式接口
我已经和Rust的借用检查器、未定义行为(UB)斗争了好几天,无比沮丧。
半边(Half Edge,又称双连通边列表)是一种几何数据结构,我曾多次在C++中实现它,一直用着这样简洁的接口:
edge.next() face.edge() vert.edge()
这种接口允许元素直接访问关联对象,完全不需要显式引用所属的Mesh结构,可读性极强。但Rust里常见的实现方式却繁琐晦涩,我完全无法接受:
mesh.hedges[edge_id] mesh.get_edge(edge_id)
比如链式调用edge.next().next().next(),用这种繁琐接口得写成:
mesh.get_edge(mesh.get_edge(mesh.get_edge(id).next_id).next_id)
哪怕拆分也需要多行代码,徒增心智负担。
为此我尝试用unsafe代码实现理想接口:
pub struct HEdge<'a, V, E, F> where V: Clone, E: Clone, F: Clone, { pub(crate) id: GeomId, pub(crate) next_id: GeomId, pub(crate) prev_id: GeomId, pub(crate) pair_id: GeomId, pub(crate) vert_id: GeomId, pub(crate) face_id: GeomId, pub data: E, pub(crate) mesh: *mut HalfMesh<'a, V, E, F>, } impl<'a, V, E, F> HEdge<'a, V, E, F> where V: Clone, E: Clone, F: Clone, { pub fn next_mut(&self) -> &mut HEdge<'a, V, E, F> { unsafe { debug_assert!(self.next_id != ABSENT); debug_assert!(usize::from(self.next_id) < (*self.mesh).hedges.len()); &mut (*self.mesh).hedges[usize::from(self.next_id)] } } }
但在示例用法的split方法中出现了段错误:
pub fn split(&mut self) -> &mut Vert<'a, V, E, F> { unsafe { let v2_id = self.pair().prev().source().id; let v3_id = self.dest().id; let v4_id = self.prev().source().id; let vn_id = (*self.mesh).add_vert(self.source().data.clone()); let e1_id = self.id; let e2_id = self.pair().id; let e3_id = self.next().id; let e4_id = self.prev().id; let e5_id = self.pair().next().id; let e6_id = self.pair().prev().id; let (e7_id, e8_id) = (*self.mesh).add_edge(vn_id, v2_id, self.data.clone(), self.data.clone()); let (e9_id, e10_id) = (*self.mesh).add_edge(v4_id, vn_id, self.data.clone(), self.data.clone()); println!("{}", (*self.mesh).hedges.len()); let (e11_id, e12_id) = (*self.mesh).add_edge(v3_id, vn_id, self.data.clone(), self.data.clone()); let f1_id = self.face_id; let f2_id = self.pair().face_id; let f3_id = (*self.mesh).add_face(e10_id, self.face().data.clone()); let f4_id = (*self.mesh).add_face(e8_id, self.pair().face().data.clone()); attach_face( &mut (*self.mesh).faces[f1_id.0 as usize], &mut (*self.mesh).hedges[e1_id.0 as usize], &mut (*self.mesh).hedges[e3_id.0 as usize], &mut (*self.mesh).hedges[e9_id.0 as usize], ); attach_face( &mut (*self.mesh).faces[f2_id.0 as usize], &mut (*self.mesh).hedges[e2_id.0 as usize], &mut (*self.mesh).hedges[e7_id.0 as usize], &mut (*self.mesh).hedges[e6_id.0 as usize], ); attach_face( &mut (*self.mesh).faces[f3_id.0 as usize], &mut (*self.mesh).hedges[e10_id.0 as usize], &mut (*self.mesh).hedges[e4_id.0 as usize], &mut (*self.mesh).hedges[e11_id.0 as usize], ); attach_face( &mut (*self.mesh).faces[f4_id.0 as usize], &mut (*self.mesh).hedges[e8_id.0 as usize], &mut (*self.mesh).hedges[e12_id.0 as usize], &mut (*self.mesh).hedges[e5_id.0 as usize], ); return &mut (*self.mesh).verts[vn_id.0 as usize]; } }
这个设计存在大量UB,完全无法正常工作。我查了各种资料、尝试了多种方案,始终没法在Rust中实现类似C++的edge.next()接口,所有建议最终都退化成mesh.get_edge(id)这类繁琐形式。
我的核心诉求是:把一套经过3年实战检验的C++接口适配到Rust中——实现struct Mesh与struct Edge,让Edge内部引用Mesh,支持edge.next()链式调用且无UB或运行错误。当前的实现已经崩溃。
内容的提问来源于stack exchange,提问作者Makogan
相关产品推荐
相关产品推荐

