use crate::*; // trait for a kind of topological element (i.e. Vertex, HalfEdge, Face) pub(crate) trait Entity<'brand, 'arena>: Eq + Sized { fn clear(&mut self); fn type_name() -> &'static str; fn maybe_id(&self) -> Option; fn id(&self) -> usize { self.maybe_id().unwrap() } fn alive(&self) -> bool { self.maybe_id().is_some() } fn maybe_next(&self) -> Option; fn next(&self) -> ptr_t!(Self) { self.maybe_next().unwrap() } fn set_next(&mut self, x: ptr_t!(Self)) { self.set_next_opt(Some(x)); } fn set_next_opt(&mut self, x: Option); fn maybe_prev(&self) -> Option; fn prev(&self) -> ptr_t!(Self) { self.maybe_prev().unwrap() } fn set_prev(&mut self, x: ptr_t!(Self)) { self.set_prev_opt(Some(x)); } fn set_prev_opt(&mut self, x: Option); fn list_add( this: ptr_t!(Self), list: Option, token: &mut impl ReflAsMut>, ) -> ptr_t!(Self) { let (next, prev) = if let Some(first) = list { (first, first.prev(token)) } else { (this, this) }; this.set_next(next, token); this.set_prev(prev, token); prev.set_next(this, token); next.set_prev(this, token); next } fn list_remove( this: ptr_t!(Self), token: &mut impl ReflAsMut>, ) -> Option { let next = this.next(token); let prev = this.prev(token); if this.eq(next, token) { return None; } prev.set_next(next, token); next.set_prev(prev, token); Some(next) } } macro_rules! entity { ($name:ident : $T:ident $(($init_name:ident : $init_ty:ty))? $(, $($custom_field:ident : $custom_ty:ty = $custom_expr:expr),* )? $(; $( $field_vis:vis $field:ident $([ $list_singular:ident : $list_name:ident $(($list_init:ty))? $($list_back:ident)? ])? : $field_ty:ident ),* )? ) => { paste! { pub struct $T<'brand, 'arena, V> { id: Option, next: Option, prev: Option, $($($custom_field: $custom_ty,)*)? $($($field: Option,)*)? } impl<'brand, 'arena, V> $T<'brand, 'arena, V> { fn new($($init_name: $init_ty,)? dcel: &mut Dcel<'brand, 'arena, V>) -> own_t!(Self) { let id = Some(dcel.$name.next_id()); dcel.$name.alloc(Self { id, prev: None, next: None, $($($custom_field: $custom_expr,)*)? $($($field: None,)*)? }, &mut dcel.token) } } impl<'brand, 'arena, V> Entity<'brand, 'arena> for $T<'brand, 'arena, V> { fn clear(&mut self) { self.id = None; #[cfg(debug_assertions)] { self.prev = None; self.next = None; $($(self.$field = None;)*)? } } fn type_name() -> &'static str { stringify!($T) } fn maybe_id(&self) -> Option { self.id } fn maybe_next(&self) -> Option { self.next } fn set_next_opt(&mut self, x: Option) { self.next = x; } fn maybe_prev(&self) -> Option { self.prev } fn set_prev_opt(&mut self, x: Option) { self.prev = x; } } #[allow(unused)] impl<'brand, 'arena, V> ptr!($T) { $($( $field_vis fn $field(self, token: &impl ReflAsRef>) -> ptr!($field_ty) { self.[](token).unwrap() } fn [](self, token: &impl ReflAsRef>) -> Option { self.borrow(token).$field } fn [](self, x: ptr!($field_ty), token: &mut impl ReflAsMut>) { self.[](Some(x), token); } fn [](self, x: Option, token: &mut impl ReflAsMut>,) { self.borrow_mut(token).$field = x; } $( pub fn []<'tok>( self, token: &'tok impl ReflAsRef>, ) -> EntityIterator<'tok, 'brand, 'arena, $field_ty<'brand, 'arena, V>> { EntityIterator::new(self.[](token), token) } pub fn []>>( self, token: &mut T, mut f: impl FnMut(ptr!($field_ty), &mut T), ) { let Some(mut item) = self.[](token) else { return; }; let last = item; while { let next_item = item.next(token); f(item, token); item = next_item; !item.eq(last, token) } {} } fn []( self, x: ptr!($field_ty), token: &mut impl ReflAsMut>, ) { let list = Entity::list_add(x, self.[](token), token); self.[](list, token); $( let [<_ $list_back>] = (); x.[](self, token); )? } fn []( self, $(init: $list_init,)? dcel: &mut Dcel<'brand, 'arena, V>, ) -> own!($field_ty) { let x = $field_ty::new($(init as $list_init,)? dcel); self.[](*x, dcel); x } fn []( self, x: ptr!($field_ty), token: &mut impl ReflAsMut>, ) { let list = Entity::list_remove(x, token); self.[](list, token); } )? )*)? } #[allow(unused)] impl<'tok, 'brand, 'arena, V> lens!($T) { $($( $field_vis fn $field(self) -> lens!($field_ty) { self.item.$field(&self).lens(self.token) } fn [](self) -> Option { self.item.[](&self).map(|x| x.lens(self.token)) } $( pub fn [](self) -> EntityIterator<'tok, 'brand, 'arena, $field_ty<'brand, 'arena, V>> { let [<_ $list_singular>] = (); self.item.[](self.token) } )? fn [](self, f: &mut Formatter) -> fmt::Result where V: Debug { $({ let [<_ $list_singular>] = (); if true { // return short_debug_list(self.[](), f); return f.debug_list().entries(self.[]()).finish(); } })? short_debug(self.$field(), f) } )*)? } impl<'tok, 'brand, 'arena, V: Debug> Debug for lens!($T) { fn fmt(&self, f: &mut Formatter) -> fmt::Result { f.debug_struct(stringify!($T)) .field("id", &self.id()) .field("prev", &short_debug_fn(self.prev())) .field("next", &short_debug_fn(self.next())) $($( .field(stringify!($field), &DisplayFn(|f| self.[](f))) )*)? $($( .field(stringify!($custom_field), &DisplayFn(|f| self.[](f))) )*)? .finish() } } #[allow(unused)] impl<'brand, 'arena, V> Own<'brand, 'arena, $T<'brand, 'arena, V>> { fn free(self, dcel: &mut Dcel<'brand, 'arena, V>) { dcel.$name.free(&mut dcel.token, self) } } impl<'brand, 'arena, V> Hash for $T<'brand, 'arena, V> { fn hash(&self, state: &mut H) { self.id.hash(state); } } impl<'brand, 'arena, V> PartialEq for $T<'brand, 'arena, V> { fn eq(&self, other: &Self) -> bool { self.id() == other.id() } } impl<'brand, 'arena, V> Eq for $T<'brand, 'arena, V> {} }}; }