From 219261b7042fba1a54ecd478b56e902d9ca8787b Mon Sep 17 00:00:00 2001 From: Charlotte Pabst Date: Thu, 7 Mar 2024 21:52:30 +0100 Subject: --- src/entity.rs | 288 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 288 insertions(+) create mode 100644 src/entity.rs (limited to 'src/entity.rs') diff --git a/src/entity.rs b/src/entity.rs new file mode 100644 index 0000000..7cce82d --- /dev/null +++ b/src/entity.rs @@ -0,0 +1,288 @@ +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 { + f(item, token); + item = item.next(token); + !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> {} + }}; +} -- cgit v1.2.3