Skip to content

Commit 9ca5f52

Browse files
committed
entity: add bundle_map.
1 parent 54e3d4f commit 9ca5f52

File tree

3 files changed

+221
-1
lines changed

3 files changed

+221
-1
lines changed

public/entity/src/bundle_map.rs

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
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;
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
use bincode::{BorrowDecode, Decode, Encode};
2+
3+
use crate::{EntityBundleIndex, EntityBundleMap, EntityId};
4+
5+
impl<I: EntityId, T: Encode> Encode for EntityBundleMap<I, T> {
6+
fn encode<E: bincode::enc::Encoder>(
7+
&self,
8+
encoder: &mut E,
9+
) -> Result<(), bincode::error::EncodeError> {
10+
self.bundles.len().encode(encoder)?;
11+
for (key, (idx, val)) in &self.bundles {
12+
let num = match idx {
13+
EntityBundleIndex::Single(_) => None,
14+
EntityBundleIndex::Array(range) => Some(range.len()),
15+
};
16+
num.encode(encoder)?;
17+
key.encode(encoder)?;
18+
val.encode(encoder)?;
19+
}
20+
Ok(())
21+
}
22+
}
23+
24+
impl<I: EntityId, Context, T: Decode<Context>> Decode<Context> for EntityBundleMap<I, T> {
25+
fn decode<D: bincode::de::Decoder<Context = Context>>(
26+
decoder: &mut D,
27+
) -> Result<Self, bincode::error::DecodeError> {
28+
let len = usize::decode(decoder)?;
29+
let mut res = Self::new();
30+
for _ in 0..len {
31+
let num: Option<usize> = Decode::decode(decoder)?;
32+
let key = String::decode(decoder)?;
33+
let val = T::decode(decoder)?;
34+
match num {
35+
None => {
36+
if res.insert(key, val).is_none() {
37+
return Err(bincode::error::DecodeError::Other("duplicate key"));
38+
}
39+
}
40+
Some(num) => {
41+
if res.insert_array(key, num, val).is_none() {
42+
return Err(bincode::error::DecodeError::Other("duplicate key"));
43+
}
44+
}
45+
}
46+
}
47+
Ok(res)
48+
}
49+
}
50+
51+
impl<'de, I: EntityId, Context, T: BorrowDecode<'de, Context>> BorrowDecode<'de, Context>
52+
for EntityBundleMap<I, T>
53+
{
54+
fn borrow_decode<D: bincode::de::BorrowDecoder<'de, Context = Context>>(
55+
decoder: &mut D,
56+
) -> Result<Self, bincode::error::DecodeError> {
57+
let len = usize::decode(decoder)?;
58+
let mut res = Self::new();
59+
for _ in 0..len {
60+
let num: Option<usize> = BorrowDecode::borrow_decode(decoder)?;
61+
let key = String::borrow_decode(decoder)?;
62+
let val = T::borrow_decode(decoder)?;
63+
match num {
64+
None => {
65+
if res.insert(key, val).is_none() {
66+
return Err(bincode::error::DecodeError::Other("duplicate key"));
67+
}
68+
}
69+
Some(num) => {
70+
if res.insert_array(key, num, val).is_none() {
71+
return Err(bincode::error::DecodeError::Other("duplicate key"));
72+
}
73+
}
74+
}
75+
}
76+
Ok(res)
77+
}
78+
}

public/entity/src/lib.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,18 @@ pub use id::{EntityId, EntityRange};
66
pub use part::EntityPartVec;
77
pub use vec::EntityVec;
88

9+
#[cfg(feature = "map")]
10+
pub mod bundle_map;
911
#[cfg(feature = "map")]
1012
pub mod map;
1113
#[cfg(feature = "map")]
1214
pub mod set;
1315

1416
#[cfg(feature = "map")]
15-
pub use {map::EntityMap, set::EntitySet};
17+
pub use {
18+
bundle_map::EntityBundleIndex, bundle_map::EntityBundleItemIndex, bundle_map::EntityBundleMap,
19+
map::EntityMap, set::EntitySet,
20+
};
1621

1722
#[cfg(feature = "bitvec")]
1823
pub mod bitvec;

0 commit comments

Comments
 (0)