Implement simple resources
This commit is contained in:
parent
7d94cf052f
commit
08a458eb9c
|
@ -12,12 +12,14 @@ I couldn't find anything that fulfilled my needs, specifically an ECS that can s
|
||||||
- [x] Find some way to fill in the gaps in component columns after entities are deleted
|
- [x] Find some way to fill in the gaps in component columns after entities are deleted
|
||||||
* This was done by moving the last entity in the column to the gap that was just removed.
|
* This was done by moving the last entity in the column to the gap that was just removed.
|
||||||
- [x] Grow archetype as it fills up
|
- [x] Grow archetype as it fills up
|
||||||
- [x] Borrow safety of components inside Archetypes
|
- [ ] Borrow safety of components inside Archetypes
|
||||||
|
* Return `Ref` and `RefMut` from borrow queries
|
||||||
- [ ] Querying components from archetypes
|
- [ ] Querying components from archetypes
|
||||||
- [x] Views
|
- [x] Views
|
||||||
- [ ] Mutable views
|
- [ ] Mutable views
|
||||||
- [ ] Make it possible so that ONLY `ViewMut` can borrow mutably
|
- [ ] Make it possible so that ONLY `ViewMut` can borrow mutably
|
||||||
- [ ] Resources
|
- [x] Resources
|
||||||
|
- [ ] Get resources in views somehow
|
||||||
- [ ] Relationships (maybe this can be done through queries, idk)
|
- [ ] Relationships (maybe this can be done through queries, idk)
|
||||||
- [ ] Dynamic queries
|
- [ ] Dynamic queries
|
||||||
* Needed for scripting engines that can create their own components that Rust does not know the types of.
|
* Needed for scripting engines that can create their own components that Rust does not know the types of.
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
use std::{marker::PhantomData, any::TypeId, ptr::NonNull, cell::{Ref, RefCell, RefMut}};
|
use std::{marker::PhantomData, any::TypeId, ptr::NonNull, cell::{Ref, RefCell, RefMut}};
|
||||||
|
|
||||||
|
use crate::world::World;
|
||||||
|
|
||||||
use super::{Fetch, Query, AsQuery, DefaultQuery};
|
use super::{Fetch, Query, AsQuery, DefaultQuery};
|
||||||
|
|
||||||
/// Fetcher for borrowing components from archetypes.
|
/// Fetcher for borrowing components from archetypes.
|
||||||
|
@ -66,7 +68,7 @@ where
|
||||||
archetype.columns.iter().any(|c| c.info.type_id == self.type_id)
|
archetype.columns.iter().any(|c| c.info.type_id == self.type_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn fetch<'a>(&self, _arch_id: crate::archetype::ArchetypeId, archetype: &'a crate::archetype::Archetype) -> Self::Fetch<'a> {
|
unsafe fn fetch<'a>(&self, _world: &'a World, _arch_id: crate::archetype::ArchetypeId, archetype: &'a crate::archetype::Archetype) -> Self::Fetch<'a> {
|
||||||
let col = archetype.columns.iter().find(|c| c.info.type_id == self.type_id)
|
let col = archetype.columns.iter().find(|c| c.info.type_id == self.type_id)
|
||||||
.expect("You ignored 'can_visit_archetype'!");
|
.expect("You ignored 'can_visit_archetype'!");
|
||||||
let col_data = col.borrow_ptr();
|
let col_data = col.borrow_ptr();
|
||||||
|
@ -163,7 +165,7 @@ where
|
||||||
archetype.columns.iter().any(|c| c.info.type_id == self.type_id)
|
archetype.columns.iter().any(|c| c.info.type_id == self.type_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn fetch<'a>(&self, _arch_id: crate::archetype::ArchetypeId, archetype: &'a crate::archetype::Archetype) -> Self::Fetch<'a> {
|
unsafe fn fetch<'a>(&self, _world: &'a World, _arch_id: crate::archetype::ArchetypeId, archetype: &'a crate::archetype::Archetype) -> Self::Fetch<'a> {
|
||||||
let col = archetype.columns.iter().find(|c| c.info.type_id == self.type_id)
|
let col = archetype.columns.iter().find(|c| c.info.type_id == self.type_id)
|
||||||
.expect("You ignored 'can_visit_archetype'!");
|
.expect("You ignored 'can_visit_archetype'!");
|
||||||
let col_data = col.borrow_mut_ptr();
|
let col_data = col.borrow_mut_ptr();
|
||||||
|
@ -223,7 +225,7 @@ mod tests {
|
||||||
_phantom: std::marker::PhantomData,
|
_phantom: std::marker::PhantomData,
|
||||||
};
|
};
|
||||||
let archetypes: Vec<&Archetype> = world.archetypes.values().collect();
|
let archetypes: Vec<&Archetype> = world.archetypes.values().collect();
|
||||||
let v = View::new(borrow, archetypes);
|
let v = View::new(&world, borrow, archetypes);
|
||||||
|
|
||||||
for e in v.into_iter() {
|
for e in v.into_iter() {
|
||||||
println!("Found entity at {:?}", e);
|
println!("Found entity at {:?}", e);
|
||||||
|
@ -239,7 +241,7 @@ mod tests {
|
||||||
_phantom: std::marker::PhantomData,
|
_phantom: std::marker::PhantomData,
|
||||||
};
|
};
|
||||||
let archetypes: Vec<&Archetype> = world.archetypes.values().collect();
|
let archetypes: Vec<&Archetype> = world.archetypes.values().collect();
|
||||||
let v = View::new(borrow, archetypes);
|
let v = View::new(&world, borrow, archetypes);
|
||||||
|
|
||||||
let mut orig = vec![];
|
let mut orig = vec![];
|
||||||
|
|
||||||
|
@ -256,7 +258,7 @@ mod tests {
|
||||||
_phantom: std::marker::PhantomData,
|
_phantom: std::marker::PhantomData,
|
||||||
};
|
};
|
||||||
let archetypes: Vec<&Archetype> = world.archetypes.values().collect();
|
let archetypes: Vec<&Archetype> = world.archetypes.values().collect();
|
||||||
let v = View::new(borrow, archetypes);
|
let v = View::new(&world, borrow, archetypes);
|
||||||
|
|
||||||
for (new, orig) in v.into_iter().zip(orig.iter()) {
|
for (new, orig) in v.into_iter().zip(orig.iter()) {
|
||||||
assert!(new.x - orig.x == 10.0);
|
assert!(new.x - orig.x == 10.0);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{world::Entity, archetype::{Archetype, ArchetypeId}};
|
use crate::{world::{Entity, World}, archetype::{Archetype, ArchetypeId}};
|
||||||
|
|
||||||
use super::{Fetch, Query};
|
use super::{Fetch, Query};
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ impl Query for Entities {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn fetch<'a>(&self, arch_id: ArchetypeId, archetype: &'a Archetype) -> Self::Fetch<'a> {
|
unsafe fn fetch<'a>(&self, _world: &'a World, arch_id: ArchetypeId, archetype: &'a Archetype) -> Self::Fetch<'a> {
|
||||||
let _ = arch_id; // ignore unused warnings
|
let _ = arch_id; // ignore unused warnings
|
||||||
EntitiesFetch {
|
EntitiesFetch {
|
||||||
entities: archetype.entities.keys().cloned().collect::<Vec<Entity>>(),
|
entities: archetype.entities.keys().cloned().collect::<Vec<Entity>>(),
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{archetype::{Archetype, ArchetypeId}, world::ArchetypeEntityId};
|
use crate::{archetype::{Archetype, ArchetypeId}, world::{ArchetypeEntityId, World}};
|
||||||
|
|
||||||
pub mod view;
|
pub mod view;
|
||||||
pub use view::*;
|
pub use view::*;
|
||||||
|
@ -42,7 +42,13 @@ pub trait Query {
|
||||||
/// Returns true if the archetype should be visited or skipped.
|
/// Returns true if the archetype should be visited or skipped.
|
||||||
fn can_visit_archetype(&self, archetype: &Archetype) -> bool;
|
fn can_visit_archetype(&self, archetype: &Archetype) -> bool;
|
||||||
|
|
||||||
unsafe fn fetch<'a>(&self, arch_id: ArchetypeId, archetype: &'a Archetype) -> Self::Fetch<'a>;
|
/// Returns true if the Query can visit the world
|
||||||
|
/* fn can_visit_world(&self, world: &'a World) -> bool {
|
||||||
|
let _ = world; // compiler warnings
|
||||||
|
false
|
||||||
|
} */
|
||||||
|
|
||||||
|
unsafe fn fetch<'a>(&self, world: &'a World, arch_id: ArchetypeId, archetype: &'a Archetype) -> Self::Fetch<'a>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A trait for getting the query of a type.
|
/// A trait for getting the query of a type.
|
||||||
|
@ -76,7 +82,7 @@ mod tests {
|
||||||
|
|
||||||
let archetypes: Vec<&Archetype> = world.archetypes.values().collect();
|
let archetypes: Vec<&Archetype> = world.archetypes.values().collect();
|
||||||
|
|
||||||
let v = View::new(entities, archetypes);
|
let v = View::new(&world, entities, archetypes);
|
||||||
|
|
||||||
for e in v.into_iter() {
|
for e in v.into_iter() {
|
||||||
println!("Got entity! {:?}", e);
|
println!("Got entity! {:?}", e);
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use crate::world::World;
|
||||||
|
|
||||||
use super::{Query, Fetch, AsQuery, DefaultQuery};
|
use super::{Query, Fetch, AsQuery, DefaultQuery};
|
||||||
|
|
||||||
// Technically all of these implementations for a 2-sized tuple
|
// Technically all of these implementations for a 2-sized tuple
|
||||||
|
@ -40,9 +42,9 @@ where
|
||||||
q1.can_visit_archetype(archetype) && q2.can_visit_archetype(archetype)
|
q1.can_visit_archetype(archetype) && q2.can_visit_archetype(archetype)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn fetch<'a>(&self, arch_id: crate::archetype::ArchetypeId, archetype: &'a crate::archetype::Archetype) -> Self::Fetch<'a> {
|
unsafe fn fetch<'a>(&self, world: &'a World, arch_id: crate::archetype::ArchetypeId, archetype: &'a crate::archetype::Archetype) -> Self::Fetch<'a> {
|
||||||
let (q1, q2) = self;
|
let (q1, q2) = self;
|
||||||
( q1.fetch(arch_id, archetype), q2.fetch(arch_id, archetype) )
|
( q1.fetch(world, arch_id, archetype), q2.fetch(world, arch_id, archetype) )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,9 +103,9 @@ macro_rules! impl_bundle_tuple {
|
||||||
bools.iter().all(|b| *b)
|
bools.iter().all(|b| *b)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn fetch<'a>(&self, arch_id: crate::archetype::ArchetypeId, archetype: &'a crate::archetype::Archetype) -> Self::Fetch<'a> {
|
unsafe fn fetch<'a>(&self, world: &'a World, arch_id: crate::archetype::ArchetypeId, archetype: &'a crate::archetype::Archetype) -> Self::Fetch<'a> {
|
||||||
let ( $($name,)+ ) = self;
|
let ( $($name,)+ ) = self;
|
||||||
( $($name.fetch(arch_id, archetype),)+ )
|
( $($name.fetch(world, arch_id, archetype),)+ )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
use crate::{archetype::{Archetype, ArchetypeId}, world::ArchetypeEntityId};
|
use crate::{archetype::{Archetype, ArchetypeId}, world::{ArchetypeEntityId, World}};
|
||||||
|
|
||||||
use super::{Query, Fetch};
|
use super::{Query, Fetch};
|
||||||
|
|
||||||
pub struct View<'a, Q: Query> {
|
pub struct View<'a, Q: Query> {
|
||||||
|
world: &'a World,
|
||||||
query: Q,
|
query: Q,
|
||||||
archetypes: Vec<&'a Archetype>,
|
archetypes: Vec<&'a Archetype>,
|
||||||
}
|
}
|
||||||
|
@ -13,8 +14,9 @@ impl<'a, Q> View<'a, Q>
|
||||||
where
|
where
|
||||||
Q: Query,
|
Q: Query,
|
||||||
{
|
{
|
||||||
pub fn new(query: Q, archetypes: Vec<&'a Archetype>) -> Self {
|
pub fn new(world: &'a World, query: Q, archetypes: Vec<&'a Archetype>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
world,
|
||||||
query,
|
query,
|
||||||
archetypes,
|
archetypes,
|
||||||
}
|
}
|
||||||
|
@ -31,6 +33,7 @@ where
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
ViewIter {
|
ViewIter {
|
||||||
|
world: self.world,
|
||||||
query: self.query,
|
query: self.query,
|
||||||
fetcher: Q::Fetch::dangling(),
|
fetcher: Q::Fetch::dangling(),
|
||||||
archetypes: self.archetypes,
|
archetypes: self.archetypes,
|
||||||
|
@ -41,6 +44,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ViewIter<'a, Q: Query> {
|
pub struct ViewIter<'a, Q: Query> {
|
||||||
|
world: &'a World,
|
||||||
query: Q,
|
query: Q,
|
||||||
fetcher: Q::Fetch<'a>,
|
fetcher: Q::Fetch<'a>,
|
||||||
archetypes: Vec<&'a Archetype>,
|
archetypes: Vec<&'a Archetype>,
|
||||||
|
@ -81,7 +85,7 @@ where
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.fetcher = unsafe { self.query.fetch(ArchetypeId(arch_id as u64), arch) };
|
self.fetcher = unsafe { self.query.fetch(self.world, ArchetypeId(arch_id as u64), arch) };
|
||||||
self.component_indices = 0..arch.entities.len() as u64;
|
self.component_indices = 0..arch.entities.len() as u64;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,13 +14,13 @@ pub struct ResourceData {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ResourceData {
|
impl ResourceData {
|
||||||
pub fn new<T: 'static>(mut data: T) -> Self {
|
pub fn new<T: 'static>(data: T) -> Self {
|
||||||
let layout = Layout::new::<T>();
|
let layout = Layout::new::<T>();
|
||||||
|
let data = NonNull::from(&data).cast();
|
||||||
|
|
||||||
let ptr = unsafe {
|
let ptr = unsafe {
|
||||||
if let Some(ptr) = NonNull::new(alloc::alloc(layout)) {
|
if let Some(ptr) = NonNull::new(alloc::alloc(layout)) {
|
||||||
let data = (&mut data as *mut T) as *mut u8; // thx i hate it
|
std::ptr::copy_nonoverlapping(data.as_ptr(), ptr.as_ptr(), layout.size());
|
||||||
std::ptr::copy_nonoverlapping(data, ptr.as_ptr(), 1);
|
|
||||||
ptr
|
ptr
|
||||||
} else {
|
} else {
|
||||||
alloc::handle_alloc_error(layout)
|
alloc::handle_alloc_error(layout)
|
||||||
|
@ -53,13 +53,41 @@ impl ResourceData {
|
||||||
|
|
||||||
/// Mutably borrow the data inside of the resource.
|
/// Mutably borrow the data inside of the resource.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// If the type of T is not the same as the expected type, it will panic.
|
/// * If the type of T is not the same as the expected type, it will panic.
|
||||||
|
/// * If the data is already borrowed mutably, this will panic.
|
||||||
pub fn get_mut<'a, T: 'static>(&'a self) -> RefMut<'a, T> {
|
pub fn get_mut<'a, T: 'static>(&'a self) -> RefMut<'a, T> {
|
||||||
assert!(TypeId::of::<T>() == self.type_id);
|
assert!(TypeId::of::<T>() == self.type_id);
|
||||||
|
|
||||||
let data = self.data.borrow_mut();
|
let data = self.data.borrow_mut();
|
||||||
RefMut::map(data, |ptr| unsafe { &mut *ptr.cast().as_ptr() })
|
RefMut::map(data, |ptr| unsafe { &mut *ptr.cast().as_ptr() })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Borrow the data inside of the resource.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// If the type of T is not the same as the expected type, it will panic.
|
||||||
|
pub fn try_get<'a, T: 'static>(&'a self) -> Option<Ref<'a, T>> {
|
||||||
|
assert!(TypeId::of::<T>() == self.type_id);
|
||||||
|
|
||||||
|
self.data.try_borrow()
|
||||||
|
.map(|r| Ref::map(r, |ptr| unsafe { &*ptr.cast().as_ptr() }))
|
||||||
|
.ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mutably borrow the data inside of the resource.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// * If the type of T is not the same as the expected type, it will panic.
|
||||||
|
/// * If the data is already borrowed mutably, this will panic.
|
||||||
|
pub fn try_get_mut<'a, T: 'static>(&'a self) -> Option<RefMut<'a, T>> {
|
||||||
|
assert!(TypeId::of::<T>() == self.type_id);
|
||||||
|
|
||||||
|
self.data.try_borrow_mut()
|
||||||
|
.map(|r| RefMut::map(r, |ptr| unsafe { &mut *ptr.cast().as_ptr() }))
|
||||||
|
.ok()
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -117,7 +117,7 @@ impl World {
|
||||||
|
|
||||||
pub fn view<'a, T: 'static + Component + DefaultQuery>(&'a self) -> ViewIter<'a, T::Query> {
|
pub fn view<'a, T: 'static + Component + DefaultQuery>(&'a self) -> ViewIter<'a, T::Query> {
|
||||||
let archetypes = self.archetypes.values().collect();
|
let archetypes = self.archetypes.values().collect();
|
||||||
let v = View::new(T::default_query(), archetypes);
|
let v = View::new(self, T::default_query(), archetypes);
|
||||||
v.into_iter()
|
v.into_iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +139,8 @@ impl World {
|
||||||
/// Returns `None` if the resource was not found.
|
/// Returns `None` if the resource was not found.
|
||||||
pub fn try_get_resource<'a, T: 'static>(&'a self) -> Option<Ref<'a, T>> {
|
pub fn try_get_resource<'a, T: 'static>(&'a self) -> Option<Ref<'a, T>> {
|
||||||
self.resources.get(&TypeId::of::<T>())
|
self.resources.get(&TypeId::of::<T>())
|
||||||
.map(|r| r.get())
|
.map(|r| r.try_get())
|
||||||
|
.flatten()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a mutable borrow of a resource from the World.
|
/// Gets a mutable borrow of a resource from the World.
|
||||||
|
@ -156,7 +157,8 @@ impl World {
|
||||||
/// Returns `None` if the resource was not found.
|
/// Returns `None` if the resource was not found.
|
||||||
pub fn try_get_resource_mut<'a, T: 'static>(&'a self) -> Option<RefMut<'a, T>> {
|
pub fn try_get_resource_mut<'a, T: 'static>(&'a self) -> Option<RefMut<'a, T>> {
|
||||||
self.resources.get(&TypeId::of::<T>())
|
self.resources.get(&TypeId::of::<T>())
|
||||||
.map(|r| r.get_mut())
|
.map(|r| r.try_get_mut())
|
||||||
|
.flatten()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,6 +168,8 @@ mod tests {
|
||||||
|
|
||||||
use super::World;
|
use super::World;
|
||||||
|
|
||||||
|
struct SimpleCounter(i32);
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn spawning_entity() {
|
fn spawning_entity() {
|
||||||
let mut world = World::new();
|
let mut world = World::new();
|
||||||
|
@ -214,8 +218,6 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn simple_resource() {
|
fn simple_resource() {
|
||||||
struct SimpleCounter(i32);
|
|
||||||
|
|
||||||
let mut world = World::new();
|
let mut world = World::new();
|
||||||
{
|
{
|
||||||
let counter = SimpleCounter(0);
|
let counter = SimpleCounter(0);
|
||||||
|
@ -223,16 +225,44 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
let counter = world.get_resource::<SimpleCounter>();
|
let counter = world.get_resource::<SimpleCounter>();
|
||||||
assert!(counter.0 == 0);
|
assert_eq!(counter.0, 0);
|
||||||
drop(counter);
|
drop(counter);
|
||||||
|
|
||||||
let mut counter = world.get_resource_mut::<SimpleCounter>();
|
let mut counter = world.get_resource_mut::<SimpleCounter>();
|
||||||
counter.0 += 4582;
|
counter.0 += 4582;
|
||||||
drop(counter);
|
drop(counter);
|
||||||
|
|
||||||
let counter = world.get_resource::<SimpleCounter>();
|
|
||||||
assert!(counter.0 == 4582);
|
|
||||||
|
|
||||||
assert!(world.try_get_resource::<u32>().is_none());
|
assert!(world.try_get_resource::<u32>().is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn resource_multi_borrow() {
|
||||||
|
let mut world = World::new();
|
||||||
|
{
|
||||||
|
let counter = SimpleCounter(4582);
|
||||||
|
world.add_resource(counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
// test multiple borrows at the same time
|
||||||
|
let counter = world.get_resource::<SimpleCounter>();
|
||||||
|
assert_eq!(counter.0, 4582);
|
||||||
|
let counter2 = world.get_resource::<SimpleCounter>();
|
||||||
|
assert_eq!(counter2.0, 4582);
|
||||||
|
assert_eq!(counter2.0, 4582);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn resource_one_mutable_borrow() {
|
||||||
|
let mut world = World::new();
|
||||||
|
{
|
||||||
|
let counter = SimpleCounter(4582);
|
||||||
|
world.add_resource(counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
// test multiple borrows at the same time
|
||||||
|
let counter = world.get_resource_mut::<SimpleCounter>();
|
||||||
|
assert_eq!(counter.0, 4582);
|
||||||
|
assert!(world.try_get_resource_mut::<SimpleCounter>().is_none());
|
||||||
|
assert_eq!(counter.0, 4582);
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue