Refactor ECS to reduce the dependency on a 1-to-1 mapping between components and real rust types (#2490)
# Objective There is currently a 1-to-1 mapping between components and real rust types. This means that it is impossible for multiple components to be represented by the same rust type or for a component to not have a rust type at all. This means that component types can't be defined in languages other than rust like necessary for scripting or sandboxed (wasm?) plugins. ## Solution Refactor `ComponentDescriptor` and `Bundle` to remove `TypeInfo`. `Bundle` now uses `ComponentId` instead. `ComponentDescriptor` is now always created from a rust type instead of through the `TypeInfo` indirection. A future PR may make it possible to construct a `ComponentDescriptor` from it's fields without a rust type being involved.
This commit is contained in:
		
							parent
							
								
									4b6238d35a
								
							
						
					
					
						commit
						86cc70b902
					
				@ -110,15 +110,15 @@ pub fn derive_bundle(input: TokenStream) -> TokenStream {
 | 
			
		||||
        .map(|field| &field.ty)
 | 
			
		||||
        .collect::<Vec<_>>();
 | 
			
		||||
 | 
			
		||||
    let mut field_type_infos = Vec::new();
 | 
			
		||||
    let mut field_component_ids = Vec::new();
 | 
			
		||||
    let mut field_get_components = Vec::new();
 | 
			
		||||
    let mut field_from_components = Vec::new();
 | 
			
		||||
    for ((field_type, is_bundle), field) in
 | 
			
		||||
        field_type.iter().zip(is_bundle.iter()).zip(field.iter())
 | 
			
		||||
    {
 | 
			
		||||
        if *is_bundle {
 | 
			
		||||
            field_type_infos.push(quote! {
 | 
			
		||||
                type_info.extend(<#field_type as #ecs_path::bundle::Bundle>::type_info());
 | 
			
		||||
            field_component_ids.push(quote! {
 | 
			
		||||
                component_ids.extend(<#field_type as #ecs_path::bundle::Bundle>::component_ids(components));
 | 
			
		||||
            });
 | 
			
		||||
            field_get_components.push(quote! {
 | 
			
		||||
                self.#field.get_components(&mut func);
 | 
			
		||||
@ -127,8 +127,8 @@ pub fn derive_bundle(input: TokenStream) -> TokenStream {
 | 
			
		||||
                #field: <#field_type as #ecs_path::bundle::Bundle>::from_components(&mut func),
 | 
			
		||||
            });
 | 
			
		||||
        } else {
 | 
			
		||||
            field_type_infos.push(quote! {
 | 
			
		||||
                type_info.push(#ecs_path::component::TypeInfo::of::<#field_type>());
 | 
			
		||||
            field_component_ids.push(quote! {
 | 
			
		||||
                component_ids.push(components.get_or_insert_id::<#field_type>());
 | 
			
		||||
            });
 | 
			
		||||
            field_get_components.push(quote! {
 | 
			
		||||
                func((&mut self.#field as *mut #field_type).cast::<u8>());
 | 
			
		||||
@ -147,10 +147,12 @@ pub fn derive_bundle(input: TokenStream) -> TokenStream {
 | 
			
		||||
    TokenStream::from(quote! {
 | 
			
		||||
        /// SAFE: TypeInfo is returned in field-definition-order. [from_components] and [get_components] use field-definition-order
 | 
			
		||||
        unsafe impl #impl_generics #ecs_path::bundle::Bundle for #struct_name#ty_generics #where_clause {
 | 
			
		||||
            fn type_info() -> Vec<#ecs_path::component::TypeInfo> {
 | 
			
		||||
                let mut type_info = Vec::with_capacity(#field_len);
 | 
			
		||||
                #(#field_type_infos)*
 | 
			
		||||
                type_info
 | 
			
		||||
            fn component_ids(
 | 
			
		||||
                components: &mut #ecs_path::component::Components,
 | 
			
		||||
            ) -> Vec<#ecs_path::component::ComponentId> {
 | 
			
		||||
                let mut component_ids = Vec::with_capacity(#field_len);
 | 
			
		||||
                #(#field_component_ids)*
 | 
			
		||||
                component_ids
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            #[allow(unused_variables, unused_mut, non_snake_case)]
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@ pub use bevy_ecs_macros::Bundle;
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    archetype::ComponentStatus,
 | 
			
		||||
    component::{Component, ComponentId, ComponentTicks, Components, StorageType, TypeInfo},
 | 
			
		||||
    component::{Component, ComponentId, ComponentTicks, Components, StorageType},
 | 
			
		||||
    entity::Entity,
 | 
			
		||||
    storage::{SparseSetIndex, SparseSets, Table},
 | 
			
		||||
};
 | 
			
		||||
@ -38,13 +38,13 @@ use std::{any::TypeId, collections::HashMap};
 | 
			
		||||
/// ```
 | 
			
		||||
///
 | 
			
		||||
/// # Safety
 | 
			
		||||
/// [Bundle::type_info] must return the TypeInfo for each component type in the bundle, in the
 | 
			
		||||
/// [Bundle::component_id] must return the ComponentId for each component type in the bundle, in the
 | 
			
		||||
/// _exact_ order that [Bundle::get_components] is called.
 | 
			
		||||
/// [Bundle::from_components] must call `func` exactly once for each [TypeInfo] returned by
 | 
			
		||||
/// [Bundle::type_info]
 | 
			
		||||
/// [Bundle::from_components] must call `func` exactly once for each [ComponentId] returned by
 | 
			
		||||
/// [Bundle::component_id]
 | 
			
		||||
pub unsafe trait Bundle: Send + Sync + 'static {
 | 
			
		||||
    /// Gets this [Bundle]'s components type info, in the order of this bundle's Components
 | 
			
		||||
    fn type_info() -> Vec<TypeInfo>;
 | 
			
		||||
    /// Gets this [Bundle]'s component ids, in the order of this bundle's Components
 | 
			
		||||
    fn component_ids(components: &mut Components) -> Vec<ComponentId>;
 | 
			
		||||
 | 
			
		||||
    /// Calls `func`, which should return data for each component in the bundle, in the order of
 | 
			
		||||
    /// this bundle's Components
 | 
			
		||||
@ -66,8 +66,9 @@ macro_rules! tuple_impl {
 | 
			
		||||
    ($($name: ident),*) => {
 | 
			
		||||
        /// SAFE: TypeInfo is returned in tuple-order. [Bundle::from_components] and [Bundle::get_components] use tuple-order
 | 
			
		||||
        unsafe impl<$($name: Component),*> Bundle for ($($name,)*) {
 | 
			
		||||
            fn type_info() -> Vec<TypeInfo> {
 | 
			
		||||
                vec![$(TypeInfo::of::<$name>()),*]
 | 
			
		||||
            #[allow(unused_variables)]
 | 
			
		||||
            fn component_ids(components: &mut Components) -> Vec<ComponentId> {
 | 
			
		||||
                vec![$(components.get_or_insert_id::<$name>()),*]
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            #[allow(unused_variables, unused_mut)]
 | 
			
		||||
@ -205,10 +206,12 @@ impl Bundles {
 | 
			
		||||
    ) -> &'a BundleInfo {
 | 
			
		||||
        let bundle_infos = &mut self.bundle_infos;
 | 
			
		||||
        let id = self.bundle_ids.entry(TypeId::of::<T>()).or_insert_with(|| {
 | 
			
		||||
            let type_info = T::type_info();
 | 
			
		||||
            let component_ids = T::component_ids(components);
 | 
			
		||||
            let id = BundleId(bundle_infos.len());
 | 
			
		||||
            let bundle_info =
 | 
			
		||||
                initialize_bundle(std::any::type_name::<T>(), &type_info, id, components);
 | 
			
		||||
            // SAFE: T::component_id ensures info was created
 | 
			
		||||
            let bundle_info = unsafe {
 | 
			
		||||
                initialize_bundle(std::any::type_name::<T>(), component_ids, id, components)
 | 
			
		||||
            };
 | 
			
		||||
            bundle_infos.push(bundle_info);
 | 
			
		||||
            id
 | 
			
		||||
        });
 | 
			
		||||
@ -217,21 +220,21 @@ impl Bundles {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn initialize_bundle(
 | 
			
		||||
/// # Safety
 | 
			
		||||
///
 | 
			
		||||
/// `component_id` must be valid [ComponentId]'s
 | 
			
		||||
unsafe fn initialize_bundle(
 | 
			
		||||
    bundle_type_name: &'static str,
 | 
			
		||||
    type_info: &[TypeInfo],
 | 
			
		||||
    component_ids: Vec<ComponentId>,
 | 
			
		||||
    id: BundleId,
 | 
			
		||||
    components: &mut Components,
 | 
			
		||||
) -> BundleInfo {
 | 
			
		||||
    let mut component_ids = Vec::new();
 | 
			
		||||
    let mut storage_types = Vec::new();
 | 
			
		||||
 | 
			
		||||
    for type_info in type_info {
 | 
			
		||||
        let component_id = components.get_or_insert_with(type_info.type_id(), || type_info.clone());
 | 
			
		||||
        // SAFE: get_with_type_info ensures info was created
 | 
			
		||||
        let info = unsafe { components.get_info_unchecked(component_id) };
 | 
			
		||||
        component_ids.push(component_id);
 | 
			
		||||
        storage_types.push(info.storage_type());
 | 
			
		||||
    for &component_id in &component_ids {
 | 
			
		||||
        // SAFE: component_id exists and is therefore valid
 | 
			
		||||
        let component_info = components.get_info_unchecked(component_id);
 | 
			
		||||
        storage_types.push(component_info.storage_type());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let mut deduped = component_ids.clone();
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,3 @@
 | 
			
		||||
mod type_info;
 | 
			
		||||
 | 
			
		||||
pub use type_info::*;
 | 
			
		||||
 | 
			
		||||
use crate::storage::SparseSetIndex;
 | 
			
		||||
use std::{
 | 
			
		||||
    alloc::Layout,
 | 
			
		||||
@ -56,15 +52,8 @@ impl Default for StorageType {
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub struct ComponentInfo {
 | 
			
		||||
    name: String,
 | 
			
		||||
    id: ComponentId,
 | 
			
		||||
    type_id: Option<TypeId>,
 | 
			
		||||
    // SAFETY: This must remain private. It must only be set to "true" if this component is
 | 
			
		||||
    // actually Send + Sync
 | 
			
		||||
    is_send_and_sync: bool,
 | 
			
		||||
    layout: Layout,
 | 
			
		||||
    drop: unsafe fn(*mut u8),
 | 
			
		||||
    storage_type: StorageType,
 | 
			
		||||
    descriptor: ComponentDescriptor,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ComponentInfo {
 | 
			
		||||
@ -75,44 +64,36 @@ impl ComponentInfo {
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    pub fn name(&self) -> &str {
 | 
			
		||||
        &self.name
 | 
			
		||||
        &self.descriptor.name
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    pub fn type_id(&self) -> Option<TypeId> {
 | 
			
		||||
        self.type_id
 | 
			
		||||
        self.descriptor.type_id
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    pub fn layout(&self) -> Layout {
 | 
			
		||||
        self.layout
 | 
			
		||||
        self.descriptor.layout
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    pub fn drop(&self) -> unsafe fn(*mut u8) {
 | 
			
		||||
        self.drop
 | 
			
		||||
        self.descriptor.drop
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    pub fn storage_type(&self) -> StorageType {
 | 
			
		||||
        self.storage_type
 | 
			
		||||
        self.descriptor.storage_type
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    pub fn is_send_and_sync(&self) -> bool {
 | 
			
		||||
        self.is_send_and_sync
 | 
			
		||||
        self.descriptor.is_send_and_sync
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn new(id: ComponentId, descriptor: ComponentDescriptor) -> Self {
 | 
			
		||||
        ComponentInfo {
 | 
			
		||||
            id,
 | 
			
		||||
            name: descriptor.name,
 | 
			
		||||
            storage_type: descriptor.storage_type,
 | 
			
		||||
            type_id: descriptor.type_id,
 | 
			
		||||
            is_send_and_sync: descriptor.is_send_and_sync,
 | 
			
		||||
            drop: descriptor.drop,
 | 
			
		||||
            layout: descriptor.layout,
 | 
			
		||||
        }
 | 
			
		||||
        ComponentInfo { id, descriptor }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -142,6 +123,7 @@ impl SparseSetIndex for ComponentId {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub struct ComponentDescriptor {
 | 
			
		||||
    name: String,
 | 
			
		||||
    storage_type: StorageType,
 | 
			
		||||
@ -154,6 +136,11 @@ pub struct ComponentDescriptor {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ComponentDescriptor {
 | 
			
		||||
    // SAFETY: The pointer points to a valid value of type `T` and it is safe to drop this value.
 | 
			
		||||
    unsafe fn drop_ptr<T>(x: *mut u8) {
 | 
			
		||||
        x.cast::<T>().drop_in_place()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn new<T: Component>(storage_type: StorageType) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            name: std::any::type_name::<T>().to_string(),
 | 
			
		||||
@ -161,7 +148,18 @@ impl ComponentDescriptor {
 | 
			
		||||
            is_send_and_sync: true,
 | 
			
		||||
            type_id: Some(TypeId::of::<T>()),
 | 
			
		||||
            layout: Layout::new::<T>(),
 | 
			
		||||
            drop: TypeInfo::drop_ptr::<T>,
 | 
			
		||||
            drop: Self::drop_ptr::<T>,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn new_non_send<T: Any>(storage_type: StorageType) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            name: std::any::type_name::<T>().to_string(),
 | 
			
		||||
            storage_type,
 | 
			
		||||
            is_send_and_sync: false,
 | 
			
		||||
            type_id: Some(TypeId::of::<T>()),
 | 
			
		||||
            layout: Layout::new::<T>(),
 | 
			
		||||
            drop: Self::drop_ptr::<T>,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -181,19 +179,6 @@ impl ComponentDescriptor {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<TypeInfo> for ComponentDescriptor {
 | 
			
		||||
    fn from(type_info: TypeInfo) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            name: type_info.type_name().to_string(),
 | 
			
		||||
            storage_type: StorageType::default(),
 | 
			
		||||
            is_send_and_sync: type_info.is_send_and_sync(),
 | 
			
		||||
            type_id: Some(type_info.type_id()),
 | 
			
		||||
            drop: type_info.drop(),
 | 
			
		||||
            layout: type_info.layout(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Default)]
 | 
			
		||||
pub struct Components {
 | 
			
		||||
    components: Vec<ComponentInfo>,
 | 
			
		||||
@ -231,7 +216,12 @@ impl Components {
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    pub fn get_or_insert_id<T: Component>(&mut self) -> ComponentId {
 | 
			
		||||
        self.get_or_insert_with(TypeId::of::<T>(), TypeInfo::of::<T>)
 | 
			
		||||
        // SAFE: The [`ComponentDescriptor`] matches the [`TypeId`]
 | 
			
		||||
        unsafe {
 | 
			
		||||
            self.get_or_insert_with(TypeId::of::<T>(), || {
 | 
			
		||||
                ComponentDescriptor::new::<T>(StorageType::default())
 | 
			
		||||
            })
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
@ -279,42 +269,58 @@ impl Components {
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    pub fn get_or_insert_resource_id<T: Component>(&mut self) -> ComponentId {
 | 
			
		||||
        self.get_or_insert_resource_with(TypeId::of::<T>(), TypeInfo::of::<T>)
 | 
			
		||||
        // SAFE: The [`ComponentDescriptor`] matches the [`TypeId`]
 | 
			
		||||
        unsafe {
 | 
			
		||||
            self.get_or_insert_resource_with(TypeId::of::<T>(), || {
 | 
			
		||||
                ComponentDescriptor::new::<T>(StorageType::default())
 | 
			
		||||
            })
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    pub fn get_or_insert_non_send_resource_id<T: Any>(&mut self) -> ComponentId {
 | 
			
		||||
        self.get_or_insert_resource_with(TypeId::of::<T>(), TypeInfo::of_non_send_and_sync::<T>)
 | 
			
		||||
        // SAFE: The [`ComponentDescriptor`] matches the [`TypeId`]
 | 
			
		||||
        unsafe {
 | 
			
		||||
            self.get_or_insert_resource_with(TypeId::of::<T>(), || {
 | 
			
		||||
                ComponentDescriptor::new_non_send::<T>(StorageType::default())
 | 
			
		||||
            })
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// # Safety
 | 
			
		||||
    ///
 | 
			
		||||
    /// The [`ComponentDescriptor`] must match the [`TypeId`]
 | 
			
		||||
    #[inline]
 | 
			
		||||
    fn get_or_insert_resource_with(
 | 
			
		||||
    unsafe fn get_or_insert_resource_with(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        type_id: TypeId,
 | 
			
		||||
        func: impl FnOnce() -> TypeInfo,
 | 
			
		||||
        func: impl FnOnce() -> ComponentDescriptor,
 | 
			
		||||
    ) -> ComponentId {
 | 
			
		||||
        let components = &mut self.components;
 | 
			
		||||
        let index = self.resource_indices.entry(type_id).or_insert_with(|| {
 | 
			
		||||
            let type_info = func();
 | 
			
		||||
            let descriptor = func();
 | 
			
		||||
            let index = components.len();
 | 
			
		||||
            components.push(ComponentInfo::new(ComponentId(index), type_info.into()));
 | 
			
		||||
            components.push(ComponentInfo::new(ComponentId(index), descriptor));
 | 
			
		||||
            index
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        ComponentId(*index)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// # Safety
 | 
			
		||||
    ///
 | 
			
		||||
    /// The [`ComponentDescriptor`] must match the [`TypeId`]
 | 
			
		||||
    #[inline]
 | 
			
		||||
    pub(crate) fn get_or_insert_with(
 | 
			
		||||
    pub(crate) unsafe fn get_or_insert_with(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        type_id: TypeId,
 | 
			
		||||
        func: impl FnOnce() -> TypeInfo,
 | 
			
		||||
        func: impl FnOnce() -> ComponentDescriptor,
 | 
			
		||||
    ) -> ComponentId {
 | 
			
		||||
        let components = &mut self.components;
 | 
			
		||||
        let index = self.indices.entry(type_id).or_insert_with(|| {
 | 
			
		||||
            let type_info = func();
 | 
			
		||||
            let descriptor = func();
 | 
			
		||||
            let index = components.len();
 | 
			
		||||
            components.push(ComponentInfo::new(ComponentId(index), type_info.into()));
 | 
			
		||||
            components.push(ComponentInfo::new(ComponentId(index), descriptor));
 | 
			
		||||
            index
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
@ -1,63 +0,0 @@
 | 
			
		||||
use std::{alloc::Layout, any::TypeId};
 | 
			
		||||
 | 
			
		||||
/// Metadata required to store a component.
 | 
			
		||||
#[derive(Debug, Clone, PartialEq, Eq)]
 | 
			
		||||
pub struct TypeInfo {
 | 
			
		||||
    type_id: TypeId,
 | 
			
		||||
    layout: Layout,
 | 
			
		||||
    drop: unsafe fn(*mut u8),
 | 
			
		||||
    type_name: &'static str,
 | 
			
		||||
    is_send_and_sync: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl TypeInfo {
 | 
			
		||||
    /// Metadata for `T`.
 | 
			
		||||
    pub fn of<T: Send + Sync + 'static>() -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            type_id: TypeId::of::<T>(),
 | 
			
		||||
            layout: Layout::new::<T>(),
 | 
			
		||||
            is_send_and_sync: true,
 | 
			
		||||
            drop: Self::drop_ptr::<T>,
 | 
			
		||||
            type_name: core::any::type_name::<T>(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn of_non_send_and_sync<T: 'static>() -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            type_id: TypeId::of::<T>(),
 | 
			
		||||
            layout: Layout::new::<T>(),
 | 
			
		||||
            is_send_and_sync: false,
 | 
			
		||||
            drop: Self::drop_ptr::<T>,
 | 
			
		||||
            type_name: core::any::type_name::<T>(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    pub fn type_id(&self) -> TypeId {
 | 
			
		||||
        self.type_id
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    pub fn layout(&self) -> Layout {
 | 
			
		||||
        self.layout
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    pub fn drop(&self) -> unsafe fn(*mut u8) {
 | 
			
		||||
        self.drop
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    pub fn is_send_and_sync(&self) -> bool {
 | 
			
		||||
        self.is_send_and_sync
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    pub fn type_name(&self) -> &'static str {
 | 
			
		||||
        self.type_name
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) unsafe fn drop_ptr<T>(x: *mut u8) {
 | 
			
		||||
        x.cast::<T>().drop_in_place()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -41,7 +41,7 @@ mod tests {
 | 
			
		||||
    use crate as bevy_ecs;
 | 
			
		||||
    use crate::{
 | 
			
		||||
        bundle::Bundle,
 | 
			
		||||
        component::{Component, ComponentDescriptor, ComponentId, StorageType, TypeInfo},
 | 
			
		||||
        component::{Component, ComponentDescriptor, ComponentId, StorageType},
 | 
			
		||||
        entity::Entity,
 | 
			
		||||
        query::{
 | 
			
		||||
            Added, ChangeTrackers, Changed, FilterFetch, FilteredAccess, With, Without, WorldQuery,
 | 
			
		||||
@ -102,21 +102,26 @@ mod tests {
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn bundle_derive() {
 | 
			
		||||
        let mut world = World::new();
 | 
			
		||||
 | 
			
		||||
        #[derive(Bundle, PartialEq, Debug)]
 | 
			
		||||
        struct Foo {
 | 
			
		||||
            x: &'static str,
 | 
			
		||||
            y: i32,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            <Foo as Bundle>::type_info(),
 | 
			
		||||
            vec![TypeInfo::of::<&'static str>(), TypeInfo::of::<i32>(),]
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        let mut world = World::new();
 | 
			
		||||
        world
 | 
			
		||||
            .register_component(ComponentDescriptor::new::<i32>(StorageType::SparseSet))
 | 
			
		||||
            .unwrap();
 | 
			
		||||
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            <Foo as Bundle>::component_ids(world.components_mut()),
 | 
			
		||||
            vec![
 | 
			
		||||
                world.components_mut().get_or_insert_id::<&'static str>(),
 | 
			
		||||
                world.components_mut().get_or_insert_id::<i32>(),
 | 
			
		||||
            ]
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        let e1 = world.spawn().insert_bundle(Foo { x: "abc", y: 123 }).id();
 | 
			
		||||
        let e2 = world.spawn().insert_bundle(("def", 456, true)).id();
 | 
			
		||||
        assert_eq!(*world.get::<&str>(e1).unwrap(), "abc");
 | 
			
		||||
@ -146,12 +151,12 @@ mod tests {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            <Nested as Bundle>::type_info(),
 | 
			
		||||
            <Nested as Bundle>::component_ids(world.components_mut()),
 | 
			
		||||
            vec![
 | 
			
		||||
                TypeInfo::of::<usize>(),
 | 
			
		||||
                TypeInfo::of::<&'static str>(),
 | 
			
		||||
                TypeInfo::of::<i32>(),
 | 
			
		||||
                TypeInfo::of::<u8>(),
 | 
			
		||||
                world.components_mut().get_or_insert_id::<usize>(),
 | 
			
		||||
                world.components_mut().get_or_insert_id::<&'static str>(),
 | 
			
		||||
                world.components_mut().get_or_insert_id::<i32>(),
 | 
			
		||||
                world.components_mut().get_or_insert_id::<u8>(),
 | 
			
		||||
            ]
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -267,9 +267,13 @@ const fn padding_needed_for(layout: &Layout, align: usize) -> usize {
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use super::BlobVec;
 | 
			
		||||
    use crate::component::TypeInfo;
 | 
			
		||||
    use std::{alloc::Layout, cell::RefCell, rc::Rc};
 | 
			
		||||
 | 
			
		||||
    // SAFETY: The pointer points to a valid value of type `T` and it is safe to drop this value.
 | 
			
		||||
    unsafe fn drop_ptr<T>(x: *mut u8) {
 | 
			
		||||
        x.cast::<T>().drop_in_place()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// # Safety
 | 
			
		||||
    ///
 | 
			
		||||
    /// `blob_vec` must have a layout that matches Layout::new::<T>()
 | 
			
		||||
@ -300,7 +304,7 @@ mod tests {
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn resize_test() {
 | 
			
		||||
        let item_layout = Layout::new::<usize>();
 | 
			
		||||
        let drop = TypeInfo::drop_ptr::<usize>;
 | 
			
		||||
        let drop = drop_ptr::<usize>;
 | 
			
		||||
        let mut blob_vec = BlobVec::new(item_layout, drop, 64);
 | 
			
		||||
        unsafe {
 | 
			
		||||
            for i in 0..1_000 {
 | 
			
		||||
@ -330,7 +334,7 @@ mod tests {
 | 
			
		||||
        let drop_counter = Rc::new(RefCell::new(0));
 | 
			
		||||
        {
 | 
			
		||||
            let item_layout = Layout::new::<Foo>();
 | 
			
		||||
            let drop = TypeInfo::drop_ptr::<Foo>;
 | 
			
		||||
            let drop = drop_ptr::<Foo>;
 | 
			
		||||
            let mut blob_vec = BlobVec::new(item_layout, drop, 2);
 | 
			
		||||
            assert_eq!(blob_vec.capacity(), 2);
 | 
			
		||||
            unsafe {
 | 
			
		||||
@ -390,7 +394,7 @@ mod tests {
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn blob_vec_drop_empty_capacity() {
 | 
			
		||||
        let item_layout = Layout::new::<Foo>();
 | 
			
		||||
        let drop = TypeInfo::drop_ptr::<Foo>;
 | 
			
		||||
        let drop = drop_ptr::<Foo>;
 | 
			
		||||
        let _ = BlobVec::new(item_layout, drop, 0);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -500,17 +500,12 @@ impl IndexMut<TableId> for Tables {
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use crate::{
 | 
			
		||||
        component::{Components, TypeInfo},
 | 
			
		||||
        entity::Entity,
 | 
			
		||||
        storage::Table,
 | 
			
		||||
    };
 | 
			
		||||
    use crate::{component::Components, entity::Entity, storage::Table};
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn table() {
 | 
			
		||||
        let mut components = Components::default();
 | 
			
		||||
        let type_info = TypeInfo::of::<usize>();
 | 
			
		||||
        let component_id = components.get_or_insert_with(type_info.type_id(), || type_info);
 | 
			
		||||
        let component_id = components.get_or_insert_id::<usize>();
 | 
			
		||||
        let columns = &[component_id];
 | 
			
		||||
        let mut table = Table::with_capacity(0, columns.len());
 | 
			
		||||
        table.add_column(components.get_info(component_id).unwrap());
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user