mirror of
https://github.com/bevyengine/bevy
synced 2024-11-26 06:30:19 +00:00
Get rid of ChangedRes (#1313)
This replaces `ChangedRes` with simple associated methods that return the same info, but don't block execution. Also, since ChangedRes was infectious and was the only reason `FetchSystemParam::get_params` and `System::run_unsafe` returned `Option`s, their implementation could be simplified after this PR is merged, or as part of it with a future commit.
This commit is contained in:
parent
e035ce1f2a
commit
87ada5b589
4 changed files with 56 additions and 129 deletions
|
@ -13,7 +13,7 @@ pub use system::{Query, *};
|
|||
pub mod prelude {
|
||||
pub use crate::{
|
||||
core::WorldBuilderSource,
|
||||
resource::{ChangedRes, FromResources, Local, NonSend, Res, ResMut, Resource, Resources},
|
||||
resource::{FromResources, Local, NonSend, Res, ResMut, Resource, Resources},
|
||||
schedule::{
|
||||
ExclusiveSystemDescriptorCoercion, ParallelSystemDescriptorCoercion,
|
||||
ReportExecutionOrderAmbiguities, RunOnce, Schedule, Stage, State, StateStage,
|
||||
|
|
|
@ -8,37 +8,12 @@ use std::{
|
|||
|
||||
// TODO: align TypeAccess api with Query::Fetch
|
||||
|
||||
/// A shared borrow of a Resource
|
||||
/// that will only return in a query if the Resource has been changed
|
||||
#[derive(Debug)]
|
||||
pub struct ChangedRes<'a, T: Resource> {
|
||||
value: &'a T,
|
||||
}
|
||||
|
||||
impl<'a, T: Resource> ChangedRes<'a, T> {
|
||||
/// Creates a reference cell to a Resource from a pointer
|
||||
///
|
||||
/// # Safety
|
||||
/// The pointer must have correct lifetime / storage
|
||||
pub unsafe fn new(value: NonNull<T>) -> Self {
|
||||
Self {
|
||||
value: &*value.as_ptr(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Resource> Deref for ChangedRes<'a, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
/// Shared borrow of a Resource
|
||||
#[derive(Debug)]
|
||||
pub struct Res<'a, T: Resource> {
|
||||
value: &'a T,
|
||||
added: bool,
|
||||
mutated: bool,
|
||||
}
|
||||
|
||||
impl<'a, T: Resource> Res<'a, T> {
|
||||
|
@ -46,9 +21,11 @@ impl<'a, T: Resource> Res<'a, T> {
|
|||
///
|
||||
/// # Safety
|
||||
/// The pointer must have correct lifetime / storage
|
||||
pub unsafe fn new(value: NonNull<T>) -> Self {
|
||||
pub unsafe fn new(value: NonNull<T>, added: bool, changed: bool) -> Self {
|
||||
Self {
|
||||
value: &*value.as_ptr(),
|
||||
added,
|
||||
mutated: changed,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -61,11 +38,29 @@ impl<'a, T: Resource> Deref for Res<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Resource> Res<'a, T> {
|
||||
#[inline(always)]
|
||||
pub fn added(this: &Self) -> bool {
|
||||
this.added
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn mutated(this: &Self) -> bool {
|
||||
this.mutated
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn changed(this: &Self) -> bool {
|
||||
this.added || this.mutated
|
||||
}
|
||||
}
|
||||
|
||||
/// Unique borrow of a Resource
|
||||
#[derive(Debug)]
|
||||
pub struct ResMut<'a, T: Resource> {
|
||||
_marker: PhantomData<&'a T>,
|
||||
value: *mut T,
|
||||
added: bool,
|
||||
mutated: *mut bool,
|
||||
}
|
||||
|
||||
|
@ -74,10 +69,11 @@ impl<'a, T: Resource> ResMut<'a, T> {
|
|||
///
|
||||
/// # Safety
|
||||
/// The pointer must have correct lifetime / storage / ownership
|
||||
pub unsafe fn new(value: NonNull<T>, mutated: NonNull<bool>) -> Self {
|
||||
pub unsafe fn new(value: NonNull<T>, added: bool, mutated: NonNull<bool>) -> Self {
|
||||
Self {
|
||||
value: value.as_ptr(),
|
||||
mutated: mutated.as_ptr(),
|
||||
added,
|
||||
_marker: Default::default(),
|
||||
}
|
||||
}
|
||||
|
@ -100,6 +96,23 @@ impl<'a, T: Resource> DerefMut for ResMut<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Resource> ResMut<'a, T> {
|
||||
#[inline(always)]
|
||||
pub fn added(this: Self) -> bool {
|
||||
this.added
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn mutated(this: Self) -> bool {
|
||||
unsafe { *this.mutated }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn changed(this: Self) -> bool {
|
||||
this.added || Self::mutated(this)
|
||||
}
|
||||
}
|
||||
|
||||
/// Local<T> resources are unique per-system. Two instances of the same system will each have their own resource.
|
||||
/// Local resources are automatically initialized using the FromResources trait.
|
||||
#[derive(Debug)]
|
||||
|
|
|
@ -340,8 +340,8 @@ mod tests {
|
|||
clear_trackers_system,
|
||||
resource::{Res, ResMut, Resources},
|
||||
schedule::Schedule,
|
||||
ChangedRes, Entity, IntoExclusiveSystem, Local, Or, Query, QuerySet, Stage, System,
|
||||
SystemStage, With, World,
|
||||
Entity, IntoExclusiveSystem, Local, Query, QuerySet, Stage, System, SystemStage, With,
|
||||
World,
|
||||
};
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Default)]
|
||||
|
@ -444,7 +444,11 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn changed_resource_system() {
|
||||
fn incr_e_on_flip(_run_on_flip: ChangedRes<bool>, mut query: Query<&mut i32>) {
|
||||
fn incr_e_on_flip(run_on_flip: Res<bool>, mut query: Query<&mut i32>) {
|
||||
if !Res::changed(&run_on_flip) {
|
||||
return;
|
||||
}
|
||||
|
||||
for mut i in query.iter_mut() {
|
||||
*i += 1;
|
||||
}
|
||||
|
@ -475,50 +479,6 @@ mod tests {
|
|||
assert_eq!(*(world.get::<i32>(ent).unwrap()), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn changed_resource_or_system() {
|
||||
fn incr_e_on_flip(
|
||||
_or: Or<(Option<ChangedRes<bool>>, Option<ChangedRes<i32>>)>,
|
||||
mut query: Query<&mut i32>,
|
||||
) {
|
||||
for mut i in query.iter_mut() {
|
||||
*i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let mut world = World::default();
|
||||
let mut resources = Resources::default();
|
||||
resources.insert(false);
|
||||
resources.insert::<i32>(10);
|
||||
let ent = world.spawn((0,));
|
||||
|
||||
let mut schedule = Schedule::default();
|
||||
let mut update = SystemStage::parallel();
|
||||
update.add_system(incr_e_on_flip.system());
|
||||
schedule.add_stage("update", update);
|
||||
schedule.add_stage(
|
||||
"clear_trackers",
|
||||
SystemStage::single(clear_trackers_system.exclusive_system()),
|
||||
);
|
||||
|
||||
schedule.run(&mut world, &mut resources);
|
||||
assert_eq!(*(world.get::<i32>(ent).unwrap()), 1);
|
||||
|
||||
schedule.run(&mut world, &mut resources);
|
||||
assert_eq!(*(world.get::<i32>(ent).unwrap()), 1);
|
||||
|
||||
*resources.get_mut::<bool>().unwrap() = true;
|
||||
schedule.run(&mut world, &mut resources);
|
||||
assert_eq!(*(world.get::<i32>(ent).unwrap()), 2);
|
||||
|
||||
schedule.run(&mut world, &mut resources);
|
||||
assert_eq!(*(world.get::<i32>(ent).unwrap()), 2);
|
||||
|
||||
*resources.get_mut::<i32>().unwrap() = 20;
|
||||
schedule.run(&mut world, &mut resources);
|
||||
assert_eq!(*(world.get::<i32>(ent).unwrap()), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn conflicting_query_mut_system() {
|
||||
|
@ -624,14 +584,6 @@ mod tests {
|
|||
test_for_conflicting_resources(sys.system())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn conflicting_changed_and_mutable_resource() {
|
||||
// A tempting pattern, but unsound if allowed.
|
||||
fn sys(_: ResMut<BufferRes>, _: ChangedRes<BufferRes>) {}
|
||||
test_for_conflicting_resources(sys.system())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn conflicting_system_local_resources() {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{
|
||||
ArchetypeComponent, ChangedRes, Commands, Fetch, FromResources, Local, NonSend, Or, Query,
|
||||
QueryAccess, QueryFilter, QuerySet, QueryTuple, Res, ResMut, Resource, ResourceIndex,
|
||||
Resources, SystemState, TypeAccess, World, WorldQuery,
|
||||
ArchetypeComponent, Commands, Fetch, FromResources, Local, NonSend, Or, Query, QueryAccess,
|
||||
QueryFilter, QuerySet, QueryTuple, Res, ResMut, Resource, ResourceIndex, Resources,
|
||||
SystemState, TypeAccess, World, WorldQuery,
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use std::{any::TypeId, marker::PhantomData, sync::Arc};
|
||||
|
@ -173,9 +173,8 @@ impl<'a, T: Resource> FetchSystemParam<'a> for FetchRes<T> {
|
|||
_world: &'a World,
|
||||
resources: &'a Resources,
|
||||
) -> Option<Self::Item> {
|
||||
Some(Res::new(
|
||||
resources.get_unsafe_ref::<T>(ResourceIndex::Global),
|
||||
))
|
||||
let result = resources.get_unsafe_ref_with_added_and_mutated::<T>(ResourceIndex::Global);
|
||||
Some(Res::new(result.0, *result.1.as_ptr(), *result.2.as_ptr()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,39 +203,6 @@ impl<'a, T: Resource> FetchSystemParam<'a> for FetchResMut<T> {
|
|||
system_state.resource_access.add_write(TypeId::of::<T>());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn get_param(
|
||||
_system_state: &'a SystemState,
|
||||
_world: &'a World,
|
||||
resources: &'a Resources,
|
||||
) -> Option<Self::Item> {
|
||||
let (value, _added, mutated) =
|
||||
resources.get_unsafe_ref_with_added_and_mutated::<T>(ResourceIndex::Global);
|
||||
Some(ResMut::new(value, mutated))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FetchChangedRes<T>(PhantomData<T>);
|
||||
|
||||
impl<'a, T: Resource> SystemParam for ChangedRes<'a, T> {
|
||||
type Fetch = FetchChangedRes<T>;
|
||||
}
|
||||
|
||||
impl<'a, T: Resource> FetchSystemParam<'a> for FetchChangedRes<T> {
|
||||
type Item = ChangedRes<'a, T>;
|
||||
|
||||
fn init(system_state: &mut SystemState, _world: &World, _resources: &mut Resources) {
|
||||
if system_state.resource_access.is_write(&TypeId::of::<T>()) {
|
||||
panic!(
|
||||
"System `{}` has a `ChangedRes<{res}>` parameter that conflicts with \
|
||||
another parameter with mutable access to the same `{res}` resource.",
|
||||
system_state.name,
|
||||
res = std::any::type_name::<T>()
|
||||
);
|
||||
}
|
||||
system_state.resource_access.add_read(TypeId::of::<T>());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn get_param(
|
||||
_system_state: &'a SystemState,
|
||||
|
@ -245,11 +211,7 @@ impl<'a, T: Resource> FetchSystemParam<'a> for FetchChangedRes<T> {
|
|||
) -> Option<Self::Item> {
|
||||
let (value, added, mutated) =
|
||||
resources.get_unsafe_ref_with_added_and_mutated::<T>(ResourceIndex::Global);
|
||||
if *added.as_ptr() || *mutated.as_ptr() {
|
||||
Some(ChangedRes::new(value))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
Some(ResMut::new(value, *added.as_ptr(), mutated))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue