|
| 1 | +use crate::{EntityId, EntityRange, EntityVec}; |
| 2 | +use indexmap::IndexMap; |
| 3 | + |
| 4 | +#[derive(Copy, Clone, Debug, PartialEq, Eq)] |
| 5 | +pub enum EntityBundleIndex<I: EntityId> { |
| 6 | + Single(I), |
| 7 | + Array(EntityRange<I>), |
| 8 | +} |
| 9 | + |
| 10 | +#[derive(Copy, Clone, Debug, PartialEq, Eq)] |
| 11 | +pub enum EntityBundleItemIndex { |
| 12 | + Single, |
| 13 | + Array { index: usize, total: usize }, |
| 14 | +} |
| 15 | + |
| 16 | +#[derive(Clone, Debug, PartialEq, Eq)] |
| 17 | +pub struct EntityBundleMap<I: EntityId, T> { |
| 18 | + ids: EntityVec<I, usize>, |
| 19 | + bundles: IndexMap<String, (EntityBundleIndex<I>, T)>, |
| 20 | +} |
| 21 | + |
| 22 | +impl<I: EntityId, T> EntityBundleMap<I, T> { |
| 23 | + pub fn new() -> Self { |
| 24 | + Self { |
| 25 | + ids: Default::default(), |
| 26 | + bundles: Default::default(), |
| 27 | + } |
| 28 | + } |
| 29 | + |
| 30 | + pub fn len(&self) -> usize { |
| 31 | + self.ids.len() |
| 32 | + } |
| 33 | + |
| 34 | + pub fn is_empty(&self) -> bool { |
| 35 | + self.ids.is_empty() |
| 36 | + } |
| 37 | + |
| 38 | + pub fn ids(&self) -> EntityRange<I> { |
| 39 | + self.ids.ids() |
| 40 | + } |
| 41 | + |
| 42 | + pub fn get(&self, key: &str) -> Option<(EntityBundleIndex<I>, &T)> { |
| 43 | + let &(idx, ref val) = self.bundles.get(key)?; |
| 44 | + Some((idx, val)) |
| 45 | + } |
| 46 | + |
| 47 | + pub fn get_mut(&mut self, key: &str) -> Option<(EntityBundleIndex<I>, &mut T)> { |
| 48 | + let &mut (idx, ref mut val) = self.bundles.get_mut(key)?; |
| 49 | + Some((idx, val)) |
| 50 | + } |
| 51 | + |
| 52 | + pub fn contains_key(&self, key: &str) -> bool { |
| 53 | + self.bundles.contains_key(key) |
| 54 | + } |
| 55 | + |
| 56 | + pub fn key(&self, id: I) -> (&str, EntityBundleItemIndex) { |
| 57 | + let (key, &(bidx, _)) = self.bundles.get_index(self.ids[id]).unwrap(); |
| 58 | + match bidx { |
| 59 | + EntityBundleIndex::Single(sid) => { |
| 60 | + assert_eq!(id, sid); |
| 61 | + (key, EntityBundleItemIndex::Single) |
| 62 | + } |
| 63 | + EntityBundleIndex::Array(range) => ( |
| 64 | + key, |
| 65 | + EntityBundleItemIndex::Array { |
| 66 | + index: range.index_of(id).unwrap(), |
| 67 | + total: range.len(), |
| 68 | + }, |
| 69 | + ), |
| 70 | + } |
| 71 | + } |
| 72 | + |
| 73 | + pub fn insert(&mut self, name: String, value: T) -> Option<I> { |
| 74 | + match self.bundles.entry(name) { |
| 75 | + indexmap::map::Entry::Occupied(_) => None, |
| 76 | + indexmap::map::Entry::Vacant(e) => { |
| 77 | + let id = self.ids.push(e.index()); |
| 78 | + e.insert((EntityBundleIndex::Single(id), value)); |
| 79 | + Some(id) |
| 80 | + } |
| 81 | + } |
| 82 | + } |
| 83 | + |
| 84 | + pub fn insert_array(&mut self, name: String, num: usize, value: T) -> Option<EntityRange<I>> { |
| 85 | + match self.bundles.entry(name) { |
| 86 | + indexmap::map::Entry::Occupied(_) => None, |
| 87 | + indexmap::map::Entry::Vacant(e) => { |
| 88 | + let id = self.ids.next_id(); |
| 89 | + let range = EntityRange::new(id.to_idx(), id.to_idx() + num); |
| 90 | + for _ in 0..num { |
| 91 | + self.ids.push(e.index()); |
| 92 | + } |
| 93 | + e.insert((EntityBundleIndex::Array(range), value)); |
| 94 | + Some(range) |
| 95 | + } |
| 96 | + } |
| 97 | + } |
| 98 | + |
| 99 | + pub fn bundles(&self) -> impl Iterator<Item = (EntityBundleIndex<I>, &String, &T)> { |
| 100 | + self.bundles.iter().map(|(k, &(i, ref v))| (i, k, v)) |
| 101 | + } |
| 102 | + |
| 103 | + pub fn bundles_mut(&mut self) -> impl Iterator<Item = (EntityBundleIndex<I>, &String, &mut T)> { |
| 104 | + self.bundles |
| 105 | + .iter_mut() |
| 106 | + .map(|(k, &mut (i, ref mut v))| (i, k, v)) |
| 107 | + } |
| 108 | + |
| 109 | + pub fn into_bundles(self) -> impl Iterator<Item = (EntityBundleIndex<I>, String, T)> { |
| 110 | + self.bundles.into_iter().map(|(k, (i, v))| (i, k, v)) |
| 111 | + } |
| 112 | +} |
| 113 | + |
| 114 | +impl<I: EntityId, T> Default for EntityBundleMap<I, T> { |
| 115 | + fn default() -> Self { |
| 116 | + Self::new() |
| 117 | + } |
| 118 | +} |
| 119 | + |
| 120 | +impl<I: EntityId, T> core::ops::Index<I> for EntityBundleMap<I, T> { |
| 121 | + type Output = T; |
| 122 | + |
| 123 | + fn index(&self, index: I) -> &Self::Output { |
| 124 | + let idx = self.ids[index]; |
| 125 | + &self.bundles.get_index(idx).unwrap().1.1 |
| 126 | + } |
| 127 | +} |
| 128 | + |
| 129 | +impl<I: EntityId, T> core::ops::IndexMut<I> for EntityBundleMap<I, T> { |
| 130 | + fn index_mut(&mut self, index: I) -> &mut Self::Output { |
| 131 | + let idx = self.ids[index]; |
| 132 | + &mut self.bundles.get_index_mut(idx).unwrap().1.1 |
| 133 | + } |
| 134 | +} |
| 135 | + |
| 136 | +#[cfg(feature = "bincode")] |
| 137 | +mod bincode; |
0 commit comments