Skip to content

Commit a69cb1e

Browse files
committed
Implement Custom Component Ids
This replaces the use of TypeId for identifying components and instead uses ComponentId which is an enum that can represent either a Rust TypeId or an external id represented by a u64.
1 parent 7ba4584 commit a69cb1e

File tree

12 files changed

+179
-88
lines changed

12 files changed

+179
-88
lines changed

crates/bevy_ecs/hecs/macros/src/lib.rs

+11-11
Original file line numberDiff line numberDiff line change
@@ -58,17 +58,17 @@ pub fn derive_bundle(input: TokenStream) -> TokenStream {
5858
let n = tys.len();
5959
let code = quote! {
6060
impl #path::DynamicBundle for #ident {
61-
fn with_ids<T>(&self, f: impl FnOnce(&[std::any::TypeId]) -> T) -> T {
61+
fn with_ids<T>(&self, f: impl FnOnce(&[#path::ComponentId]) -> T) -> T {
6262
Self::with_static_ids(f)
6363
}
6464

6565
fn type_info(&self) -> Vec<#path::TypeInfo> {
6666
Self::static_type_info()
6767
}
6868

69-
unsafe fn put(mut self, mut f: impl FnMut(*mut u8, std::any::TypeId, usize) -> bool) {
69+
unsafe fn put(mut self, mut f: impl FnMut(*mut u8, #path::ComponentId, usize) -> bool) {
7070
#(
71-
if f((&mut self.#fields as *mut #tys).cast::<u8>(), std::any::TypeId::of::<#tys>(), std::mem::size_of::<#tys>()) {
71+
if f((&mut self.#fields as *mut #tys).cast::<u8>(), std::any::TypeId::of::<#tys>().into(), std::mem::size_of::<#tys>()) {
7272
#[allow(clippy::forget_copy)]
7373
std::mem::forget(self.#fields);
7474
}
@@ -77,22 +77,22 @@ pub fn derive_bundle(input: TokenStream) -> TokenStream {
7777
}
7878

7979
impl #path::Bundle for #ident {
80-
fn with_static_ids<T>(f: impl FnOnce(&[std::any::TypeId]) -> T) -> T {
80+
fn with_static_ids<T>(f: impl FnOnce(&[#path::ComponentId]) -> T) -> T {
8181
use std::any::TypeId;
8282
use std::mem;
8383

8484
#path::lazy_static::lazy_static! {
85-
static ref ELEMENTS: [TypeId; #n] = {
85+
static ref ELEMENTS: [#path::ComponentId; #n] = {
8686
let mut dedup = #path::bevy_utils::HashSet::default();
87-
for &(ty, name) in [#((std::any::TypeId::of::<#tys>(), std::any::type_name::<#tys>())),*].iter() {
87+
for &(ty, name) in [#((#path::ComponentId::from(std::any::TypeId::of::<#tys>()), std::any::type_name::<#tys>())),*].iter() {
8888
if !dedup.insert(ty) {
8989
panic!("{} has multiple {} fields; each type must occur at most once!", stringify!(#ident), name);
9090
}
9191
}
9292

93-
let mut tys = [#((mem::align_of::<#tys>(), TypeId::of::<#tys>())),*];
93+
let mut tys = [#((mem::align_of::<#tys>(), #path::ComponentId::from(TypeId::of::<#tys>()))),*];
9494
tys.sort_unstable_by(|x, y| x.0.cmp(&y.0).reverse().then(x.1.cmp(&y.1)));
95-
let mut ids = [TypeId::of::<()>(); #n];
95+
let mut ids: [#path::ComponentId; #n] = [TypeId::of::<()>().into(); #n];
9696
for (id, info) in ids.iter_mut().zip(tys.iter()) {
9797
*id = info.1;
9898
}
@@ -104,16 +104,16 @@ pub fn derive_bundle(input: TokenStream) -> TokenStream {
104104
}
105105

106106
fn static_type_info() -> Vec<#path::TypeInfo> {
107-
let mut info = vec![#(#path::TypeInfo::of::<#tys>()),*];
107+
let mut info = vec![#(#path::TypeInfo::of::<#tys>().into()),*];
108108
info.sort_unstable();
109109
info
110110
}
111111

112112
unsafe fn get(
113-
mut f: impl FnMut(std::any::TypeId, usize) -> Option<std::ptr::NonNull<u8>>,
113+
mut f: impl FnMut(#path::ComponentId, usize) -> Option<std::ptr::NonNull<u8>>,
114114
) -> Result<Self, #path::MissingComponent> {
115115
#(
116-
let #fields = f(std::any::TypeId::of::<#tys>(), std::mem::size_of::<#tys>())
116+
let #fields = f(std::any::TypeId::of::<#tys>().into(), std::mem::size_of::<#tys>())
117117
.ok_or_else(#path::MissingComponent::new::<#tys>)?
118118
.cast::<#tys>()
119119
.as_ptr();

crates/bevy_ecs/hecs/src/archetype.rs

+47-26
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,12 @@ use crate::{
1919
alloc::{alloc, dealloc, Layout},
2020
vec::Vec,
2121
},
22+
world::ComponentId,
2223
Entity,
2324
};
2425
use bevy_utils::{HashMap, HashMapExt};
2526
use core::{
26-
any::{type_name, TypeId},
27+
any::TypeId,
2728
cell::UnsafeCell,
2829
mem,
2930
ptr::{self, NonNull},
@@ -38,7 +39,7 @@ use crate::{borrow::AtomicBorrow, query::Fetch, Access, Component, Query};
3839
#[derive(Debug)]
3940
pub struct Archetype {
4041
types: Vec<TypeInfo>,
41-
state: HashMap<TypeId, TypeState>,
42+
state: HashMap<ComponentId, TypeState>,
4243
len: usize,
4344
entities: Vec<Entity>,
4445
// UnsafeCell allows unique references into `data` to be constructed while shared references
@@ -93,23 +94,23 @@ impl Archetype {
9394
#[allow(missing_docs)]
9495
#[inline]
9596
pub fn has<T: Component>(&self) -> bool {
96-
self.has_dynamic(TypeId::of::<T>())
97+
self.has_dynamic(TypeId::of::<T>().into())
9798
}
9899

99100
#[allow(missing_docs)]
100101
#[inline]
101-
pub fn has_type(&self, ty: TypeId) -> bool {
102+
pub fn has_component(&self, ty: ComponentId) -> bool {
102103
self.has_dynamic(ty)
103104
}
104105

105-
pub(crate) fn has_dynamic(&self, id: TypeId) -> bool {
106+
pub(crate) fn has_dynamic(&self, id: ComponentId) -> bool {
106107
self.state.contains_key(&id)
107108
}
108109

109110
#[allow(missing_docs)]
110111
#[inline]
111112
pub fn get<T: Component>(&self) -> Option<NonNull<T>> {
112-
let state = self.state.get(&TypeId::of::<T>())?;
113+
let state = self.state.get(&TypeId::of::<T>().into())?;
113114
Some(unsafe {
114115
NonNull::new_unchecked(
115116
(*self.data.get()).as_ptr().add(state.offset).cast::<T>() as *mut T
@@ -120,7 +121,7 @@ impl Archetype {
120121
#[allow(missing_docs)]
121122
#[inline]
122123
pub fn get_with_type_state<T: Component>(&self) -> Option<(NonNull<T>, &TypeState)> {
123-
let state = self.state.get(&TypeId::of::<T>())?;
124+
let state = self.state.get(&TypeId::of::<T>().into())?;
124125
Some(unsafe {
125126
(
126127
NonNull::new_unchecked(
@@ -132,51 +133,71 @@ impl Archetype {
132133
}
133134

134135
#[allow(missing_docs)]
135-
pub fn get_type_state(&self, ty: TypeId) -> Option<&TypeState> {
136+
pub fn get_type_state(&self, ty: ComponentId) -> Option<&TypeState> {
136137
self.state.get(&ty)
137138
}
138139

139140
#[allow(missing_docs)]
140-
pub fn get_type_state_mut(&mut self, ty: TypeId) -> Option<&mut TypeState> {
141+
pub fn get_type_state_mut(&mut self, ty: ComponentId) -> Option<&mut TypeState> {
141142
self.state.get_mut(&ty)
142143
}
143144

144145
#[allow(missing_docs)]
145146
#[inline]
146147
pub fn borrow<T: Component>(&self) {
147-
if self
148-
.state
149-
.get(&TypeId::of::<T>())
150-
.map_or(false, |x| !x.borrow.borrow())
151-
{
152-
panic!("{} already borrowed uniquely", type_name::<T>());
148+
self.borrow_component(std::any::TypeId::of::<T>().into())
149+
}
150+
151+
#[allow(missing_docs)]
152+
#[inline]
153+
pub fn borrow_component(&self, id: ComponentId) {
154+
if self.state.get(&id).map_or(false, |x| !x.borrow.borrow()) {
155+
panic!("{:?} already borrowed uniquely", id);
153156
}
154157
}
155158

156159
#[allow(missing_docs)]
157160
#[inline]
158161
pub fn borrow_mut<T: Component>(&self) {
162+
self.borrow_component_mut(std::any::TypeId::of::<T>().into())
163+
}
164+
165+
#[allow(missing_docs)]
166+
#[inline]
167+
pub fn borrow_component_mut(&self, id: ComponentId) {
159168
if self
160169
.state
161-
.get(&TypeId::of::<T>())
170+
.get(&id)
162171
.map_or(false, |x| !x.borrow.borrow_mut())
163172
{
164-
panic!("{} already borrowed", type_name::<T>());
173+
panic!("{:?} already borrowed", id);
165174
}
166175
}
167176

168177
#[allow(missing_docs)]
169178
#[inline]
170179
pub fn release<T: Component>(&self) {
171-
if let Some(x) = self.state.get(&TypeId::of::<T>()) {
180+
self.release_component(std::any::TypeId::of::<T>().into());
181+
}
182+
183+
#[allow(missing_docs)]
184+
#[inline]
185+
pub fn release_component(&self, id: ComponentId) {
186+
if let Some(x) = self.state.get(&id) {
172187
x.borrow.release();
173188
}
174189
}
175190

176191
#[allow(missing_docs)]
177192
#[inline]
178193
pub fn release_mut<T: Component>(&self) {
179-
if let Some(x) = self.state.get(&TypeId::of::<T>()) {
194+
self.release_component_mut(std::any::TypeId::of::<T>().into())
195+
}
196+
197+
#[allow(missing_docs)]
198+
#[inline]
199+
pub fn release_component_mut(&self, id: ComponentId) {
200+
if let Some(x) = self.state.get(&id) {
180201
x.borrow.release_mut();
181202
}
182203
}
@@ -216,7 +237,7 @@ impl Archetype {
216237
/// `index` must be in-bounds
217238
pub(crate) unsafe fn get_dynamic(
218239
&self,
219-
ty: TypeId,
240+
ty: ComponentId,
220241
size: usize,
221242
index: usize,
222243
) -> Option<NonNull<u8>> {
@@ -356,7 +377,7 @@ impl Archetype {
356377
pub(crate) unsafe fn move_to(
357378
&mut self,
358379
index: usize,
359-
mut f: impl FnMut(*mut u8, TypeId, usize, bool, bool),
380+
mut f: impl FnMut(*mut u8, ComponentId, usize, bool, bool),
360381
) -> Option<Entity> {
361382
let last = self.len - 1;
362383
for ty in &self.types {
@@ -400,7 +421,7 @@ impl Archetype {
400421
pub unsafe fn put_dynamic(
401422
&mut self,
402423
component: *mut u8,
403-
ty: TypeId,
424+
ty: ComponentId,
404425
size: usize,
405426
index: usize,
406427
added: bool,
@@ -484,7 +505,7 @@ impl TypeState {
484505
/// Metadata required to store a component
485506
#[derive(Debug, Copy, Clone)]
486507
pub struct TypeInfo {
487-
id: TypeId,
508+
id: ComponentId,
488509
layout: Layout,
489510
drop: unsafe fn(*mut u8),
490511
}
@@ -497,15 +518,15 @@ impl TypeInfo {
497518
}
498519

499520
Self {
500-
id: TypeId::of::<T>(),
521+
id: TypeId::of::<T>().into(),
501522
layout: Layout::new::<T>(),
502523
drop: drop_ptr::<T>,
503524
}
504525
}
505526

506527
#[allow(missing_docs)]
507528
#[inline]
508-
pub fn id(&self) -> TypeId {
529+
pub fn id(&self) -> ComponentId {
509530
self.id
510531
}
511532

@@ -527,7 +548,7 @@ impl PartialOrd for TypeInfo {
527548
}
528549

529550
impl Ord for TypeInfo {
530-
/// Order by alignment, descending. Ties broken with TypeId.
551+
/// Order by alignment, descending. Ties broken with ComponentId.
531552
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
532553
self.layout
533554
.align()

crates/bevy_ecs/hecs/src/bundle.rs

+16-13
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@
1414

1515
// modified by Bevy contributors
1616

17-
use crate::alloc::{vec, vec::Vec};
17+
use crate::{
18+
alloc::{vec, vec::Vec},
19+
world::ComponentId,
20+
};
1821
use core::{
1922
any::{type_name, TypeId},
2023
fmt, mem,
@@ -27,7 +30,7 @@ use crate::{archetype::TypeInfo, Component};
2730
pub trait DynamicBundle {
2831
/// Invoke a callback on the fields' type IDs, sorted by descending alignment then id
2932
#[doc(hidden)]
30-
fn with_ids<T>(&self, f: impl FnOnce(&[TypeId]) -> T) -> T;
33+
fn with_ids<T>(&self, f: impl FnOnce(&[ComponentId]) -> T) -> T;
3134
/// Obtain the fields' TypeInfos, sorted by descending alignment then id
3235
#[doc(hidden)]
3336
fn type_info(&self) -> Vec<TypeInfo>;
@@ -36,13 +39,13 @@ pub trait DynamicBundle {
3639
/// Must invoke `f` only with a valid pointer, its type, and the pointee's size. A `false`
3740
/// return value indicates that the value was not moved and should be dropped.
3841
#[doc(hidden)]
39-
unsafe fn put(self, f: impl FnMut(*mut u8, TypeId, usize) -> bool);
42+
unsafe fn put(self, f: impl FnMut(*mut u8, ComponentId, usize) -> bool);
4043
}
4144

4245
/// A statically typed collection of components
4346
pub trait Bundle: DynamicBundle {
4447
#[doc(hidden)]
45-
fn with_static_ids<T>(f: impl FnOnce(&[TypeId]) -> T) -> T;
48+
fn with_static_ids<T>(f: impl FnOnce(&[ComponentId]) -> T) -> T;
4649

4750
/// Obtain the fields' TypeInfos, sorted by descending alignment then id
4851
#[doc(hidden)]
@@ -56,7 +59,7 @@ pub trait Bundle: DynamicBundle {
5659
/// pointers if any call to `f` returns `None`.
5760
#[doc(hidden)]
5861
unsafe fn get(
59-
f: impl FnMut(TypeId, usize) -> Option<NonNull<u8>>,
62+
f: impl FnMut(ComponentId, usize) -> Option<NonNull<u8>>,
6063
) -> Result<Self, MissingComponent>
6164
where
6265
Self: Sized;
@@ -85,7 +88,7 @@ impl std::error::Error for MissingComponent {}
8588
macro_rules! tuple_impl {
8689
($($name: ident),*) => {
8790
impl<$($name: Component),*> DynamicBundle for ($($name,)*) {
88-
fn with_ids<T>(&self, f: impl FnOnce(&[TypeId]) -> T) -> T {
91+
fn with_ids<T>(&self, f: impl FnOnce(&[ComponentId]) -> T) -> T {
8992
Self::with_static_ids(f)
9093
}
9194

@@ -94,13 +97,13 @@ macro_rules! tuple_impl {
9497
}
9598

9699
#[allow(unused_variables, unused_mut)]
97-
unsafe fn put(self, mut f: impl FnMut(*mut u8, TypeId, usize) -> bool) {
100+
unsafe fn put(self, mut f: impl FnMut(*mut u8, ComponentId, usize) -> bool) {
98101
#[allow(non_snake_case)]
99102
let ($(mut $name,)*) = self;
100103
$(
101104
if f(
102105
(&mut $name as *mut $name).cast::<u8>(),
103-
TypeId::of::<$name>(),
106+
TypeId::of::<$name>().into(),
104107
mem::size_of::<$name>()
105108
) {
106109
mem::forget($name)
@@ -110,11 +113,11 @@ macro_rules! tuple_impl {
110113
}
111114

112115
impl<$($name: Component),*> Bundle for ($($name,)*) {
113-
fn with_static_ids<T>(f: impl FnOnce(&[TypeId]) -> T) -> T {
116+
fn with_static_ids<T>(f: impl FnOnce(&[ComponentId]) -> T) -> T {
114117
const N: usize = count!($($name),*);
115-
let mut xs: [(usize, TypeId); N] = [$((mem::align_of::<$name>(), TypeId::of::<$name>())),*];
118+
let mut xs: [(usize, ComponentId); N] = [$((mem::align_of::<$name>(), TypeId::of::<$name>().into())),*];
116119
xs.sort_unstable_by(|x, y| x.0.cmp(&y.0).reverse().then(x.1.cmp(&y.1)));
117-
let mut ids = [TypeId::of::<()>(); N];
120+
let mut ids = [TypeId::of::<()>().into(); N];
118121
for (slot, &(_, id)) in ids.iter_mut().zip(xs.iter()) {
119122
*slot = id;
120123
}
@@ -128,10 +131,10 @@ macro_rules! tuple_impl {
128131
}
129132

130133
#[allow(unused_variables, unused_mut)]
131-
unsafe fn get(mut f: impl FnMut(TypeId, usize) -> Option<NonNull<u8>>) -> Result<Self, MissingComponent> {
134+
unsafe fn get(mut f: impl FnMut(ComponentId, usize) -> Option<NonNull<u8>>) -> Result<Self, MissingComponent> {
132135
#[allow(non_snake_case)]
133136
let ($(mut $name,)*) = ($(
134-
f(TypeId::of::<$name>(), mem::size_of::<$name>()).ok_or_else(MissingComponent::new::<$name>)?
137+
f(TypeId::of::<$name>().into(), mem::size_of::<$name>()).ok_or_else(MissingComponent::new::<$name>)?
135138
.as_ptr()
136139
.cast::<$name>(),)*
137140
);

0 commit comments

Comments
 (0)