From c32da78f2a6014c491aa3e975fb83ddb7c80610e Mon Sep 17 00:00:00 2001 From: Crozet Sébastien Date: Mon, 26 Apr 2021 17:59:25 +0200 Subject: Split rigid-bodies and colliders into multiple components --- src/data/arena.rs | 87 ++++++++++++++++++++++--------------- src/data/coarena.rs | 30 +++++++------ src/data/component_set.rs | 106 ++++++++++++++++++++++++++++++++++++++++++++++ src/data/mod.rs | 3 ++ 4 files changed, 177 insertions(+), 49 deletions(-) create mode 100644 src/data/component_set.rs (limited to 'src/data') diff --git a/src/data/arena.rs b/src/data/arena.rs index 9d057b8..bc7176d 100644 --- a/src/data/arena.rs +++ b/src/data/arena.rs @@ -19,16 +19,16 @@ use std::vec; #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] pub struct Arena { items: Vec>, - generation: u64, - free_list_head: Option, + generation: u32, + free_list_head: Option, len: usize, } #[derive(Clone, Debug)] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] enum Entry { - Free { next_free: Option }, - Occupied { generation: u64, value: T }, + Free { next_free: Option }, + Occupied { generation: u32, value: T }, } /// An index (and generation) into an `Arena`. @@ -48,17 +48,17 @@ enum Entry { #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] pub struct Index { - index: usize, - generation: u64, + index: u32, + generation: u32, } impl IndexedData for Index { fn default() -> Self { - Self::from_raw_parts(crate::INVALID_USIZE, crate::INVALID_U64) + Self::from_raw_parts(crate::INVALID_U32, crate::INVALID_U32) } fn index(&self) -> usize { - self.into_raw_parts().0 + self.into_raw_parts().0 as usize } } @@ -70,7 +70,7 @@ impl Index { /// /// Providing arbitrary values will lead to malformed indices and ultimately /// panics. - pub fn from_raw_parts(a: usize, b: u64) -> Index { + pub fn from_raw_parts(a: u32, b: u32) -> Index { Index { index: a, generation: b, @@ -84,7 +84,7 @@ impl Index { /// `Index` like `pub struct MyIdentifier(Index);`. However, for external /// types whose definition you can't customize, but which you can construct /// instances of, this method can be useful. - pub fn into_raw_parts(self) -> (usize, u64) { + pub fn into_raw_parts(self) -> (u32, u32) { (self.index, self.generation) } } @@ -161,7 +161,7 @@ impl Arena { pub fn clear(&mut self) { self.items.clear(); - let end = self.items.capacity(); + let end = self.items.capacity() as u32; self.items.extend((0..end).map(|i| { if i == end - 1 { Entry::Free { next_free: None } @@ -206,7 +206,7 @@ impl Arena { match self.try_alloc_next_index() { None => Err(value), Some(index) => { - self.items[index.index] = Entry::Occupied { + self.items[index.index as usize] = Entry::Occupied { generation: self.generation, value, }; @@ -247,7 +247,7 @@ impl Arena { match self.try_alloc_next_index() { None => Err(create), Some(index) => { - self.items[index.index] = Entry::Occupied { + self.items[index.index as usize] = Entry::Occupied { generation: self.generation, value: create(index), }; @@ -260,13 +260,13 @@ impl Arena { fn try_alloc_next_index(&mut self) -> Option { match self.free_list_head { None => None, - Some(i) => match self.items[i] { + Some(i) => match self.items[i as usize] { Entry::Occupied { .. } => panic!("corrupt free list"), Entry::Free { next_free } => { self.free_list_head = next_free; self.len += 1; Some(Index { - index: i, + index: i as u32, generation: self.generation, }) } @@ -355,14 +355,14 @@ impl Arena { /// assert_eq!(arena.remove(idx), None); /// ``` pub fn remove(&mut self, i: Index) -> Option { - if i.index >= self.items.len() { + if i.index >= self.items.len() as u32 { return None; } - match self.items[i.index] { + match self.items[i.index as usize] { Entry::Occupied { generation, .. } if i.generation == generation => { let entry = mem::replace( - &mut self.items[i.index], + &mut self.items[i.index as usize], Entry::Free { next_free: self.free_list_head, }, @@ -402,8 +402,8 @@ impl Arena { /// assert!(crew_members.next().is_none()); /// ``` pub fn retain(&mut self, mut predicate: impl FnMut(Index, &mut T) -> bool) { - for i in 0..self.capacity() { - let remove = match &mut self.items[i] { + for i in 0..self.capacity() as u32 { + let remove = match &mut self.items[i as usize] { Entry::Occupied { generation, value } => { let index = Index { index: i, @@ -462,7 +462,7 @@ impl Arena { /// assert!(arena.get(idx).is_none()); /// ``` pub fn get(&self, i: Index) -> Option<&T> { - match self.items.get(i.index) { + match self.items.get(i.index as usize) { Some(Entry::Occupied { generation, value }) if *generation == i.generation => { Some(value) } @@ -488,7 +488,7 @@ impl Arena { /// assert!(arena.get_mut(idx).is_none()); /// ``` pub fn get_mut(&mut self, i: Index) -> Option<&mut T> { - match self.items.get_mut(i.index) { + match self.items.get_mut(i.index as usize) { Some(Entry::Occupied { generation, value }) if *generation == i.generation => { Some(value) } @@ -526,7 +526,7 @@ impl Arena { /// assert_eq!(arena[idx2], 4); /// ``` pub fn get2_mut(&mut self, i1: Index, i2: Index) -> (Option<&mut T>, Option<&mut T>) { - let len = self.items.len(); + let len = self.items.len() as u32; if i1.index == i2.index { assert!(i1.generation != i2.generation); @@ -544,11 +544,13 @@ impl Arena { } let (raw_item1, raw_item2) = { - let (xs, ys) = self.items.split_at_mut(cmp::max(i1.index, i2.index)); + let (xs, ys) = self + .items + .split_at_mut(cmp::max(i1.index, i2.index) as usize); if i1.index < i2.index { - (&mut xs[i1.index], &mut ys[0]) + (&mut xs[i1.index as usize], &mut ys[0]) } else { - (&mut ys[0], &mut xs[i2.index]) + (&mut ys[0], &mut xs[i2.index as usize]) } }; @@ -666,11 +668,11 @@ impl Arena { } } else { Entry::Free { - next_free: Some(i + 1), + next_free: Some(i as u32 + 1), } } })); - self.free_list_head = Some(start); + self.free_list_head = Some(start as u32); } /// Iterate over shared references to the elements in this arena. @@ -774,7 +776,7 @@ impl Arena { value, Index { generation: *generation, - index: i, + index: i as u32, }, )), _ => None, @@ -797,7 +799,7 @@ impl Arena { value, Index { generation: *generation, - index: i, + index: i as u32, }, )), _ => None, @@ -941,7 +943,10 @@ impl<'a, T> Iterator for Iter<'a, T> { }, )) => { self.len -= 1; - let idx = Index { index, generation }; + let idx = Index { + index: index as u32, + generation, + }; return Some((idx, value)); } None => { @@ -970,7 +975,10 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> { }, )) => { self.len -= 1; - let idx = Index { index, generation }; + let idx = Index { + index: index as u32, + generation, + }; return Some((idx, value)); } None => { @@ -1039,7 +1047,10 @@ impl<'a, T> Iterator for IterMut<'a, T> { }, )) => { self.len -= 1; - let idx = Index { index, generation }; + let idx = Index { + index: index as u32, + generation, + }; return Some((idx, value)); } None => { @@ -1068,7 +1079,10 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { }, )) => { self.len -= 1; - let idx = Index { index, generation }; + let idx = Index { + index: index as u32, + generation, + }; return Some((idx, value)); } None => { @@ -1126,7 +1140,10 @@ impl<'a, T> Iterator for Drain<'a, T> { match self.inner.next() { Some((_, Entry::Free { .. })) => continue, Some((index, Entry::Occupied { generation, value })) => { - let idx = Index { index, generation }; + let idx = Index { + index: index as u32, + generation, + }; return Some((idx, value)); } None => return None, diff --git a/src/data/coarena.rs b/src/data/coarena.rs index c25cc55..cd64910 100644 --- a/src/data/coarena.rs +++ b/src/data/coarena.rs @@ -4,7 +4,7 @@ use crate::data::arena::Index; #[derive(Clone, Debug)] /// A container for data associated to item existing into another Arena. pub struct Coarena { - data: Vec<(u64, T)>, + data: Vec<(u32, T)>, } impl Coarena { @@ -17,7 +17,7 @@ impl Coarena { pub fn get(&self, index: Index) -> Option<&T> { let (i, g) = index.into_raw_parts(); self.data - .get(i) + .get(i as usize) .and_then(|(gg, t)| if g == *gg { Some(t) } else { None }) } @@ -25,7 +25,7 @@ impl Coarena { pub fn get_mut(&mut self, index: Index) -> Option<&mut T> { let (i, g) = index.into_raw_parts(); self.data - .get_mut(i) + .get_mut(i as usize) .and_then(|(gg, t)| if g == *gg { Some(t) } else { None }) } @@ -36,11 +36,11 @@ impl Coarena { { let (i1, g1) = a.into_raw_parts(); - if self.data.len() <= i1 { - self.data.resize(i1 + 1, (u32::MAX as u64, T::default())); + if self.data.len() <= i1 as usize { + self.data.resize(i1 as usize + 1, (u32::MAX, T::default())); } - self.data[i1] = (g1, value); + self.data[i1 as usize] = (g1, value); } /// Ensure that elements at the two given indices exist in this coarena, and return their reference. @@ -56,20 +56,22 @@ impl Coarena { assert_ne!(i1, i2, "Cannot index the same object twice."); let (elt1, elt2) = if i1 > i2 { - if self.data.len() <= i1 { - self.data.resize(i1 + 1, (u32::MAX as u64, default.clone())); + if self.data.len() <= i1 as usize { + self.data + .resize(i1 as usize + 1, (u32::MAX, default.clone())); } - let (left, right) = self.data.split_at_mut(i1); - (&mut right[0], &mut left[i2]) + let (left, right) = self.data.split_at_mut(i1 as usize); + (&mut right[0], &mut left[i2 as usize]) } else { // i2 > i1 - if self.data.len() <= i2 { - self.data.resize(i2 + 1, (u32::MAX as u64, default.clone())); + if self.data.len() <= i2 as usize { + self.data + .resize(i2 as usize + 1, (u32::MAX, default.clone())); } - let (left, right) = self.data.split_at_mut(i2); - (&mut left[i1], &mut right[0]) + let (left, right) = self.data.split_at_mut(i2 as usize); + (&mut left[i1 as usize], &mut right[0]) }; if elt1.0 != g1 { diff --git a/src/data/component_set.rs b/src/data/component_set.rs new file mode 100644 index 0000000..76e076a --- /dev/null +++ b/src/data/component_set.rs @@ -0,0 +1,106 @@ +use crate::data::Index; + +// TODO ECS: use this to handle optional components properly. +// pub trait OptionalComponentSet { +// fn get(&self, handle: Index) -> Option<&T>; +// } + +pub trait ComponentSetOption { + fn get(&self, handle: Index) -> Option<&T>; +} + +pub trait ComponentSet: ComponentSetOption { + fn size_hint(&self) -> usize; + // TODO ECS: remove this, its only needed by the query pipeline update + // which should only take the modified colliders into account. + fn for_each(&self, f: impl FnMut(Index, &T)); + fn index(&self, handle: Index) -> &T { + self.get(handle).unwrap() + } +} + +pub trait ComponentSetMut: ComponentSet { + fn map_mut_internal( + &mut self, + handle: crate::data::Index, + f: impl FnOnce(&mut T) -> Result, + ) -> Option; + fn set_internal(&mut self, handle: crate::data::Index, val: T); +} + +pub trait BundleSet<'a, T> { + fn index_bundle(&'a self, handle: Index) -> T; +} + +impl<'a, T, A, B> BundleSet<'a, (&'a A, &'a B)> for T +where + T: ComponentSet + ComponentSet, +{ + #[inline(always)] + fn index_bundle(&'a self, handle: Index) -> (&'a A, &'a B) { + (self.index(handle), self.index(handle)) + } +} + +impl<'a, T, A, B, C> BundleSet<'a, (&'a A, &'a B, &'a C)> for T +where + T: ComponentSet + ComponentSet + ComponentSet, +{ + #[inline(always)] + fn index_bundle(&'a self, handle: Index) -> (&'a A, &'a B, &'a C) { + (self.index(handle), self.index(handle), self.index(handle)) + } +} + +impl<'a, T, A, B, C, D> BundleSet<'a, (&'a A, &'a B, &'a C, &'a D)> for T +where + T: ComponentSet + ComponentSet + ComponentSet + ComponentSet, +{ + #[inline(always)] + fn index_bundle(&'a self, handle: Index) -> (&'a A, &'a B, &'a C, &'a D) { + ( + self.index(handle), + self.index(handle), + self.index(handle), + self.index(handle), + ) + } +} + +impl<'a, T, A, B, C, D, E> BundleSet<'a, (&'a A, &'a B, &'a C, &'a D, &'a E)> for T +where + T: ComponentSet + ComponentSet + ComponentSet + ComponentSet + ComponentSet, +{ + #[inline(always)] + fn index_bundle(&'a self, handle: Index) -> (&'a A, &'a B, &'a C, &'a D, &'a E) { + ( + self.index(handle), + self.index(handle), + self.index(handle), + self.index(handle), + self.index(handle), + ) + } +} + +impl<'a, T, A, B, C, D, E, F> BundleSet<'a, (&'a A, &'a B, &'a C, &'a D, &'a E, &'a F)> for T +where + T: ComponentSet + + ComponentSet + + ComponentSet + + ComponentSet + + ComponentSet + + ComponentSet, +{ + #[inline(always)] + fn index_bundle(&'a self, handle: Index) -> (&'a A, &'a B, &'a C, &'a D, &'a E, &'a F) { + ( + self.index(handle), + self.index(handle), + self.index(handle), + self.index(handle), + self.index(handle), + self.index(handle), + ) + } +} diff --git a/src/data/mod.rs b/src/data/mod.rs index 7c49314..f20e433 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -1,8 +1,11 @@ //! Data structures modified with guaranteed deterministic behavior after deserialization. +pub use self::arena::{Arena, Index}; pub use self::coarena::Coarena; +pub use self::component_set::{BundleSet, ComponentSet, ComponentSetMut, ComponentSetOption}; pub mod arena; mod coarena; +mod component_set; pub(crate) mod graph; pub mod pubsub; -- cgit From 5cf805075ec8612249d692c319d099f4454931da Mon Sep 17 00:00:00 2001 From: Crozet Sébastien Date: Thu, 29 Apr 2021 11:42:44 +0200 Subject: Fix compilation of the parallel version --- src/data/component_set.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/data') diff --git a/src/data/component_set.rs b/src/data/component_set.rs index 76e076a..ca7df67 100644 --- a/src/data/component_set.rs +++ b/src/data/component_set.rs @@ -5,7 +5,7 @@ use crate::data::Index; // fn get(&self, handle: Index) -> Option<&T>; // } -pub trait ComponentSetOption { +pub trait ComponentSetOption: Sync { fn get(&self, handle: Index) -> Option<&T>; } -- cgit From 2dfbd9ae92c139e306afc87994adac82489f30eb Mon Sep 17 00:00:00 2001 From: Crozet Sébastien Date: Fri, 30 Apr 2021 11:37:58 +0200 Subject: Add comments. --- src/data/arena.rs | 12 ++++++------ src/data/component_set.rs | 17 +++++++++++++++++ 2 files changed, 23 insertions(+), 6 deletions(-) (limited to 'src/data') diff --git a/src/data/arena.rs b/src/data/arena.rs index bc7176d..c7cbf07 100644 --- a/src/data/arena.rs +++ b/src/data/arena.rs @@ -770,13 +770,13 @@ impl Arena { /// other kinds of bit-efficient indexing. /// /// You should use the `get` method instead most of the time. - pub fn get_unknown_gen(&self, i: usize) -> Option<(&T, Index)> { - match self.items.get(i) { + pub fn get_unknown_gen(&self, i: u32) -> Option<(&T, Index)> { + match self.items.get(i as usize) { Some(Entry::Occupied { generation, value }) => Some(( value, Index { generation: *generation, - index: i as u32, + index: i, }, )), _ => None, @@ -793,13 +793,13 @@ impl Arena { /// other kinds of bit-efficient indexing. /// /// You should use the `get_mut` method instead most of the time. - pub fn get_unknown_gen_mut(&mut self, i: usize) -> Option<(&mut T, Index)> { - match self.items.get_mut(i) { + pub fn get_unknown_gen_mut(&mut self, i: u32) -> Option<(&mut T, Index)> { + match self.items.get_mut(i as usize) { Some(Entry::Occupied { generation, value }) => Some(( value, Index { generation: *generation, - index: i as u32, + index: i, }, )), _ => None, diff --git a/src/data/component_set.rs b/src/data/component_set.rs index ca7df67..6e0461c 100644 --- a/src/data/component_set.rs +++ b/src/data/component_set.rs @@ -5,30 +5,47 @@ use crate::data::Index; // fn get(&self, handle: Index) -> Option<&T>; // } +/// A set of optional elements of type `T`. pub trait ComponentSetOption: Sync { + /// Get the element associated to the given `handle`, if there is one. fn get(&self, handle: Index) -> Option<&T>; } +/// A set of elements of type `T`. pub trait ComponentSet: ComponentSetOption { + /// The estimated number of elements in this set. + /// + /// This value is typically used for preallocating some arrays for + /// better performances. fn size_hint(&self) -> usize; // TODO ECS: remove this, its only needed by the query pipeline update // which should only take the modified colliders into account. + /// Iterate through all the elements on this set. fn for_each(&self, f: impl FnMut(Index, &T)); + /// Get the element associated to the given `handle`. fn index(&self, handle: Index) -> &T { self.get(handle).unwrap() } } +/// A set of mutable elements of type `T`. pub trait ComponentSetMut: ComponentSet { + /// Applies the given closure to the element associated to the given `handle`. + /// + /// Return `None` if the element doesn't exist. fn map_mut_internal( &mut self, handle: crate::data::Index, f: impl FnOnce(&mut T) -> Result, ) -> Option; + + /// Set the value of this element. fn set_internal(&mut self, handle: crate::data::Index, val: T); } +/// Helper trait to address multiple elements at once. pub trait BundleSet<'a, T> { + /// Access multiple elements from this set. fn index_bundle(&'a self, handle: Index) -> T; } -- cgit