Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add reflection for resources #1260

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions crates/bevy_ecs/src/resource/resources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pub enum ResourceIndex {
// TODO: consider using this for normal resources (would require change tracking)
trait ResourceStorage: Downcast {
fn clear_trackers(&mut self);
fn get_flag_mutated(&mut self, index: usize) -> &mut bool;
}
impl_downcast!(ResourceStorage);

Expand Down Expand Up @@ -77,6 +78,22 @@ impl<T: 'static> VecResourceStorage<T> {
fn is_empty(&self) -> bool {
self.stored.is_empty()
}

fn borrow(&self, index:usize) -> bool {
self.stored[index].atomic_borrow.borrow()
}

fn borrow_mut(&self, index:usize) -> bool {
self.stored[index].atomic_borrow.borrow_mut()
}

unsafe fn release(&self, index:usize) {
self.stored[index].atomic_borrow.release()
}

unsafe fn release_mut(&self, index:usize) {
self.stored[index].atomic_borrow.release_mut()
}
}

impl<T: 'static> Default for VecResourceStorage<T> {
Expand All @@ -94,6 +111,12 @@ impl<T: 'static> ResourceStorage for VecResourceStorage<T> {
stored.mutated = UnsafeCell::new(false);
}
}

fn get_flag_mutated(&mut self, index: usize) -> &mut bool {
// # Safety
// Safe as we take &mut self
unsafe { self.stored[index].mutated.get().as_mut().unwrap() }
}
}

/// A collection of resource instances identified by their type.
Expand Down Expand Up @@ -327,6 +350,63 @@ impl Resources {
resource_data.storage.clear_trackers();
}
}

pub fn iter_types(&self) -> impl Iterator<Item = &TypeId> {
self.resource_data.keys()
}

pub fn set_mutated_dynamic(&mut self, type_id: &TypeId) {
let data = self.resource_data.get_mut(type_id).unwrap();
*data.storage.get_flag_mutated(data.default_index.unwrap()) = true;
}

pub fn borrow<T: Resource>(&self) {
self.get_resource_data_index::<T>(ResourceIndex::Global)
.map(|(data, index)| {
let resources = data
.storage
.downcast_ref::<VecResourceStorage<T>>()
.unwrap();
if !resources.borrow(index) {
panic!("{} already borrowed uniquely.", std::any::type_name::<T>());
}
});
}

pub fn borrow_mut<T: Resource>(&self) {
self.get_resource_data_index::<T>(ResourceIndex::Global)
.map(|(data, index)| {
let resources = data
.storage
.downcast_ref::<VecResourceStorage<T>>()
.unwrap();
if !resources.borrow_mut(index) {
panic!("{} already borrowed uniquely.", std::any::type_name::<T>());
}
});
}

pub unsafe fn release<T: Resource>(&self) {
self.get_resource_data_index::<T>(ResourceIndex::Global)
.map(|(data, index)| {
let resources = data
.storage
.downcast_ref::<VecResourceStorage<T>>()
.unwrap();
resources.release(index);
});
}

pub unsafe fn release_mut<T: Resource>(&self) {
self.get_resource_data_index::<T>(ResourceIndex::Global)
.map(|(data, index)| {
let resources = data
.storage
.downcast_ref::<VecResourceStorage<T>>()
.unwrap();
resources.release_mut(index);
});
}
}

unsafe impl Send for Resources {}
Expand Down
129 changes: 128 additions & 1 deletion crates/bevy_reflect/src/impls/bevy_ecs.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{FromType, Reflect};
use bevy_ecs::{
Archetype, Component, Entity, EntityMap, FromResources, MapEntities, MapEntitiesError,
Resources, World,
Resource, ResourceIndex, Resources, World,
};
use std::marker::PhantomData;

Expand All @@ -10,6 +10,7 @@ pub struct ReflectComponent {
add_component: fn(&mut World, resources: &Resources, Entity, &dyn Reflect),
apply_component: fn(&mut World, Entity, &dyn Reflect),
reflect_component: unsafe fn(&Archetype, usize) -> &dyn Reflect,
reflect_component_mut: unsafe fn(&mut Archetype, usize) -> &mut dyn Reflect,
copy_component: fn(&World, &mut World, &Resources, Entity, Entity),
}

Expand Down Expand Up @@ -38,6 +39,17 @@ impl ReflectComponent {
(self.reflect_component)(archetype, entity_index)
}

/// # Safety
/// This does not do bound checks on entity_index. You must make sure entity_index is within bounds before calling.
/// This does not mark the component as mutated, you must do it as necessary.
pub unsafe fn reflect_component_mut<'a>(
&self,
archetype: &'a mut Archetype,
entity_index: usize,
) -> &'a mut dyn Reflect {
(self.reflect_component_mut)(archetype, entity_index)
}

pub fn copy_component(
&self,
source_world: &World,
Expand Down Expand Up @@ -87,6 +99,13 @@ impl<C: Component + Reflect + FromResources> FromType<C> for ReflectComponent {
ptr.as_ref().unwrap()
}
},
reflect_component_mut: |archetype, index| {
unsafe {
// the type has been looked up by the caller, so this is safe
let ptr = archetype.get::<C>().unwrap().as_ptr().add(index);
ptr.as_mut().unwrap()
}
},
}
}
}
Expand Down Expand Up @@ -183,6 +202,114 @@ impl<Runtime: Component + IntoComponent<Scene>, Scene: Component> FromType<Runti
}
}

#[derive(Clone)]
pub struct ReflectResource {
add_resource: fn(&mut Resources, &dyn Reflect),
apply_resource: fn(&mut Resources, &dyn Reflect),
copy_resource: fn(&Resources, &mut Resources),
borrow_resource: fn(&Resources),
borrow_mut_resource: fn(&Resources),
reflect_resource: unsafe fn(&Resources) -> &dyn Reflect,
reflect_resource_mut: unsafe fn(&Resources) -> &mut dyn Reflect,
release_resource: unsafe fn(&Resources),
release_mut_resource: unsafe fn(&Resources),
}

impl<'a> ReflectResource {
pub fn add_resource(&self, resources: &mut Resources, resource: &dyn Reflect) {
(self.add_resource)(resources, resource);
}

pub fn apply_resource(&self, resources: &mut Resources, resource: &dyn Reflect) {
(self.apply_resource)(resources, resource);
}

pub fn copy_resource(
&self,
source_resources: &Resources,
destination_resources: &mut Resources,
) {
(self.copy_resource)(source_resources, destination_resources);
}

/// # Safety
/// You must call borrow_resource() and release_resource() manually
pub unsafe fn reflect_resource(&self, resources: &'a Resources) -> &'a dyn Reflect {
(self.reflect_resource)(resources)
}

/// # Safety
/// You must call borrow_mut_resource() and release_mut_resource() manually
/// This does not mark the resource as mutated, you must do it as necessary.
pub unsafe fn reflect_resource_mut(&self, resources: &'a Resources) -> &'a mut dyn Reflect {
(self.reflect_resource_mut)(resources)
}

pub fn borrow_resource(&self, resources: &Resources) {
(self.borrow_resource)(resources)
}

pub fn borrow_mut_resource(&self, resources: &Resources) {
(self.borrow_mut_resource)(resources)
}

pub unsafe fn release_resource(&self, resources: &Resources) {
(self.release_resource)(resources)
}

pub unsafe fn release_mut_resource(&self, resources: &Resources) {
(self.release_mut_resource)(resources)
}
}

impl<'a, R: Resource + Reflect + FromResources> FromType<R> for ReflectResource {
fn from_type() -> Self {
ReflectResource {
add_resource: |resources, reflected_resource| {
let mut resource = R::from_resources(resources);
resource.apply(reflected_resource);
resources.insert(resource);
},
apply_resource: |resources, reflected_resource| {
let mut resource = resources.get_mut::<R>().unwrap();
resource.apply(reflected_resource)
},
copy_resource: |source_resources, destination_resources| {
let source_resource = source_resources.get::<R>().unwrap();
let mut destination_resource = R::from_resources(destination_resources);
destination_resource.apply(&*source_resource);
destination_resources.insert(destination_resource);
},
reflect_resource: |resources| unsafe {
resources
.get_unsafe_ref::<R>(ResourceIndex::Global)
.as_ptr()
.as_ref()
.unwrap()
},
reflect_resource_mut: |resources| unsafe {
resources
.get_unsafe_ref::<R>(ResourceIndex::Global)
.as_ptr()
.as_mut()
.unwrap()
},
borrow_resource: |resources| {
resources.borrow::<R>()
},
borrow_mut_resource: |resources| {
resources.borrow_mut::<R>()
},
release_resource: |resources| unsafe {
resources.release::<R>();
},
release_mut_resource: |resources| unsafe {
resources.release_mut::<R>();
},
}
}
}

#[derive(Clone)]
pub struct ReflectMapEntities {
map_entities: fn(&mut World, &EntityMap) -> Result<(), MapEntitiesError>,
Expand Down