Skip to content
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
2 changes: 1 addition & 1 deletion benches/bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ fn iterate_100k(b: &mut Bencher) {
world.spawn((Position(-(i as f32)), Velocity(i as f32)));
}
b.iter(|| {
for (_, (pos, vel)) in &mut world.query::<(&mut Position, &Velocity)>() {
for (_, (mut pos, vel)) in &mut world.query::<(&mut Position, &Velocity)>() {
pos.0 += vel.0;
}
})
Expand Down
4 changes: 2 additions & 2 deletions examples/ffa_simulation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ fn batch_spawn_entities(world: &mut World, n: usize) {
fn system_integrate_motion(world: &mut World) {
let mut rng = thread_rng();

for (id, (pos, s)) in &mut world.query::<(&mut Position, &Speed)>() {
for (id, (mut pos, s)) in &mut world.query::<(&mut Position, &Speed)>() {
let change = (rng.gen_range(-s.0, s.0), rng.gen_range(-s.0, s.0));
pos.x += change.0;
pos.y += change.1;
Expand All @@ -72,7 +72,7 @@ fn system_integrate_motion(world: &mut World) {

// In this system entities find the closest entity and fire at them
fn system_fire_at_closest(world: &mut World) {
for (id0, (pos0, dmg0, kc0)) in
for (id0, (pos0, dmg0, mut kc0)) in
&mut world.query::<With<Health, (&Position, &Damage, &mut KillCount)>>()
{
// Find closest:
Expand Down
2 changes: 1 addition & 1 deletion src/archetype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ impl Archetype {
}

/// How, if at all, `Q` will access entities in this archetype
pub fn access<Q: Query>(&self) -> Option<Access> {
pub fn access<'w, Q: Query<'w, C>, C: Copy + 'w>(&self) -> Option<Access> {
Q::Fetch::access(self)
}
}
Expand Down
109 changes: 80 additions & 29 deletions src/borrow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use core::ptr::NonNull;
use core::sync::atomic::{AtomicUsize, Ordering};

use crate::archetype::Archetype;
use crate::{Component, MissingComponent};
use crate::{Entity, MissingComponent, SmartComponent};

pub struct AtomicBorrow(AtomicUsize);

Expand Down Expand Up @@ -63,15 +63,19 @@ const UNIQUE_BIT: usize = !(usize::max_value() >> 1);

/// Shared borrow of an entity's component
#[derive(Clone)]
pub struct Ref<'a, T: Component> {
pub struct Ref<'a, T: SmartComponent<C>, C: Clone + 'a = ()> {
archetype: &'a Archetype,
target: NonNull<T>,
entity: Entity,
context: C,
}

impl<'a, T: Component> Ref<'a, T> {
impl<'a, T: SmartComponent<C>, C: Clone + 'a> Ref<'a, T, C> {
pub(crate) unsafe fn new(
archetype: &'a Archetype,
index: u32,
entity: Entity,
context: C,
) -> Result<Self, MissingComponent> {
let target = NonNull::new_unchecked(
archetype
Expand All @@ -81,36 +85,47 @@ impl<'a, T: Component> Ref<'a, T> {
.add(index as usize),
);
archetype.borrow::<T>();
Ok(Self { archetype, target })
Ok(Self {
archetype,
target,
entity,
context,
})
}
}

unsafe impl<T: Component> Send for Ref<'_, T> {}
unsafe impl<T: Component> Sync for Ref<'_, T> {}
unsafe impl<T: SmartComponent<C>, C: Clone + Sync> Send for Ref<'_, T, C> {}
unsafe impl<T: SmartComponent<C>, C: Clone + Sync> Sync for Ref<'_, T, C> {}

impl<'a, T: Component> Drop for Ref<'a, T> {
impl<'a, T: SmartComponent<C>, C: Clone> Drop for Ref<'a, T, C> {
fn drop(&mut self) {
self.archetype.release::<T>();
}
}

impl<'a, T: Component> Deref for Ref<'a, T> {
impl<'a, T: SmartComponent<C>, C: Clone> Deref for Ref<'a, T, C> {
type Target = T;
fn deref(&self) -> &T {
unsafe { self.target.as_ref() }
let value = unsafe { self.target.as_ref() };
value.on_borrow(self.entity, self.context.clone());
value
}
}

/// Unique borrow of an entity's component
pub struct RefMut<'a, T: Component> {
pub struct RefMut<'a, T: SmartComponent<C>, C: Clone = ()> {
archetype: &'a Archetype,
target: NonNull<T>,
entity: Entity,
context: C,
}

impl<'a, T: Component> RefMut<'a, T> {
impl<'a, T: SmartComponent<C>, C: Clone> RefMut<'a, T, C> {
pub(crate) unsafe fn new(
archetype: &'a Archetype,
index: u32,
entity: Entity,
context: C,
) -> Result<Self, MissingComponent> {
let target = NonNull::new_unchecked(
archetype
Expand All @@ -120,68 +135,104 @@ impl<'a, T: Component> RefMut<'a, T> {
.add(index as usize),
);
archetype.borrow_mut::<T>();
Ok(Self { archetype, target })
Ok(Self {
archetype,
target,
entity,
context,
})
}
}

unsafe impl<T: Component> Send for RefMut<'_, T> {}
unsafe impl<T: Component> Sync for RefMut<'_, T> {}
unsafe impl<T: SmartComponent<C>, C: Clone + Sync> Send for RefMut<'_, T, C> {}
unsafe impl<T: SmartComponent<C>, C: Clone + Sync> Sync for RefMut<'_, T, C> {}

impl<'a, T: Component> Drop for RefMut<'a, T> {
impl<'a, T: SmartComponent<C>, C: Clone> Drop for RefMut<'a, T, C> {
fn drop(&mut self) {
self.archetype.release_mut::<T>();
}
}

impl<'a, T: Component> Deref for RefMut<'a, T> {
impl<'a, T: SmartComponent<C>, C: Clone> Deref for RefMut<'a, T, C> {
type Target = T;
fn deref(&self) -> &T {
unsafe { self.target.as_ref() }
let value = unsafe { self.target.as_ref() };
value.on_borrow(self.entity, self.context.clone());
value
}
}

impl<'a, T: Component> DerefMut for RefMut<'a, T> {
impl<'a, T: SmartComponent<C>, C: Clone> DerefMut for RefMut<'a, T, C> {
fn deref_mut(&mut self) -> &mut T {
unsafe { self.target.as_mut() }
let value = unsafe { self.target.as_mut() };
value.on_borrow_mut(self.entity, self.context.clone());
value
}
}

/// Handle to an entity with any component types
#[derive(Copy, Clone)]
pub struct EntityRef<'a> {
pub struct EntityRef<'a, C: Clone = ()> {
archetype: Option<&'a Archetype>,
index: u32,
entity: Entity,
context: C,
}

impl<'a> EntityRef<'a> {
impl<'a, C: Clone> EntityRef<'a, C> {
/// Construct a `Ref` for an entity with no components
pub(crate) fn empty() -> Self {
pub(crate) fn empty(entity: Entity, context: C) -> Self {
Self {
archetype: None,
index: 0,
entity,
context,
}
}

pub(crate) unsafe fn new(archetype: &'a Archetype, index: u32) -> Self {
pub(crate) unsafe fn new(
archetype: &'a Archetype,
index: u32,
entity: Entity,
context: C,
) -> Self {
Self {
archetype: Some(archetype),
index,
entity,
context,
}
}

/// Borrow the component of type `T`, if it exists
///
/// Panics if the component is already uniquely borrowed from another entity with the same
/// components.
pub fn get<T: Component>(&self) -> Option<Ref<'a, T>> {
Some(unsafe { Ref::new(self.archetype?, self.index).ok()? })
pub fn get<T: SmartComponent<C>>(&self) -> Option<Ref<'a, T, C>> {
Some(unsafe {
Ref::new(
self.archetype?,
self.index,
self.entity,
self.context.clone(),
)
.ok()?
})
}

/// Uniquely borrow the component of type `T`, if it exists
///
/// Panics if the component is already borrowed from another entity with the same components.
pub fn get_mut<T: Component>(&self) -> Option<RefMut<'a, T>> {
Some(unsafe { RefMut::new(self.archetype?, self.index).ok()? })
pub fn get_mut<T: SmartComponent<C>>(&self) -> Option<RefMut<'a, T, C>> {
Some(unsafe {
RefMut::new(
self.archetype?,
self.index,
self.entity,
self.context.clone(),
)
.ok()?
})
}

/// Enumerate the types of the entity's components
Expand All @@ -197,5 +248,5 @@ impl<'a> EntityRef<'a> {
}
}

unsafe impl<'a> Send for EntityRef<'a> {}
unsafe impl<'a> Sync for EntityRef<'a> {}
unsafe impl<'a, C: Clone + Sync> Send for EntityRef<'a, C> {}
unsafe impl<'a, C: Clone + Sync> Sync for EntityRef<'a, C> {}
8 changes: 5 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
//! let a = world.spawn((123, true, "abc"));
//! let b = world.spawn((42, false));
//! // Systems can be simple for loops
//! for (id, (number, &flag)) in world.query::<(&mut i32, &bool)>().iter() {
//! if flag { *number *= 2; }
//! for (id, (mut number, flag)) in world.query::<(&mut i32, &bool)>().iter() {
//! if *flag { *number *= 2; }
//! }
//! // Random access is simple and safe
//! assert_eq!(*world.get::<i32>(a).unwrap(), 246);
Expand Down Expand Up @@ -78,7 +78,9 @@ pub use entities::{Entity, NoSuchEntity};
pub use entity_builder::{BuiltEntity, EntityBuilder};
pub use query::{Access, BatchedIter, Query, QueryBorrow, QueryIter, With, Without};
pub use query_one::QueryOne;
pub use world::{ArchetypesGeneration, Component, ComponentError, Iter, SpawnBatchIter, World};
pub use world::{
ArchetypesGeneration, Component, ComponentError, Iter, SmartComponent, SpawnBatchIter, World,
};

// Unstable implementation details needed by the macros
#[doc(hidden)]
Expand Down
Loading