204 lines
5.2 KiB
Rust
204 lines
5.2 KiB
Rust
|
use std::{marker::PhantomData, any::TypeId, ptr::NonNull};
|
||
|
|
||
|
use super::{Fetch, Query};
|
||
|
|
||
|
pub struct FetchBorrow<'a, T> {
|
||
|
ptr: NonNull<u8>,
|
||
|
size: usize,
|
||
|
_phantom: PhantomData<&'a T>
|
||
|
}
|
||
|
|
||
|
impl<'a, T> Fetch<'a> for FetchBorrow<'a, T>
|
||
|
where
|
||
|
T: 'a,
|
||
|
{
|
||
|
type Item = &'a T;
|
||
|
|
||
|
fn create_empty() -> Self {
|
||
|
FetchBorrow {
|
||
|
ptr: NonNull::dangling(),
|
||
|
size: 0,
|
||
|
_phantom: PhantomData::default()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
unsafe fn get_item(&mut self, entity: crate::world::ArchetypeEntityId) -> Self::Item {
|
||
|
let ptr = NonNull::new_unchecked(self.ptr.as_ptr()
|
||
|
.add(entity.0 as usize * self.size))
|
||
|
.cast();
|
||
|
&*ptr.as_ptr()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub struct QueryBorrow<T> {
|
||
|
type_id: TypeId,
|
||
|
_phantom: PhantomData<T>
|
||
|
}
|
||
|
|
||
|
impl<T> Query for QueryBorrow<T>
|
||
|
where
|
||
|
T: 'static
|
||
|
{
|
||
|
type Item<'a> = &'a T;
|
||
|
|
||
|
type Fetch<'a> = FetchBorrow<'a, T>;
|
||
|
|
||
|
fn can_visit_archetype(&self, archetype: &crate::archetype::Archetype) -> bool {
|
||
|
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> {
|
||
|
let col = archetype.columns.iter().find(|c| c.info.type_id == self.type_id)
|
||
|
.expect("You ignored 'can_visit_archetype'!");
|
||
|
let col_data = col.data;
|
||
|
|
||
|
FetchBorrow {
|
||
|
ptr: NonNull::new_unchecked(col_data.as_ptr()),
|
||
|
size: col.info.layout.size(),
|
||
|
_phantom: PhantomData,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub struct FetchBorrowMut<'a, T> {
|
||
|
ptr: NonNull<u8>,
|
||
|
size: usize,
|
||
|
_phantom: PhantomData<&'a T>
|
||
|
}
|
||
|
|
||
|
impl<'a, T> Fetch<'a> for FetchBorrowMut<'a, T>
|
||
|
where
|
||
|
T: 'a,
|
||
|
{
|
||
|
type Item = &'a mut T;
|
||
|
|
||
|
fn create_empty() -> Self {
|
||
|
FetchBorrowMut {
|
||
|
ptr: NonNull::dangling(),
|
||
|
size: 0,
|
||
|
_phantom: PhantomData::default()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
unsafe fn get_item(&mut self, entity: crate::world::ArchetypeEntityId) -> Self::Item {
|
||
|
let ptr = NonNull::new_unchecked(self.ptr.as_ptr()
|
||
|
.add(entity.0 as usize * self.size))
|
||
|
.cast();
|
||
|
&mut *ptr.as_ptr()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub struct QueryBorrowMut<T> {
|
||
|
type_id: TypeId,
|
||
|
_phantom: PhantomData<T>
|
||
|
}
|
||
|
|
||
|
impl<T> Query for QueryBorrowMut<T>
|
||
|
where
|
||
|
T: 'static
|
||
|
{
|
||
|
type Item<'a> = &'a mut T;
|
||
|
|
||
|
type Fetch<'a> = FetchBorrowMut<'a, T>;
|
||
|
|
||
|
fn can_visit_archetype(&self, archetype: &crate::archetype::Archetype) -> bool {
|
||
|
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> {
|
||
|
let col = archetype.columns.iter().find(|c| c.info.type_id == self.type_id)
|
||
|
.expect("You ignored 'can_visit_archetype'!");
|
||
|
let col_data = col.data;
|
||
|
|
||
|
FetchBorrowMut {
|
||
|
ptr: NonNull::new_unchecked(col_data.as_ptr()),
|
||
|
size: col.info.layout.size(),
|
||
|
_phantom: PhantomData,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#[cfg(test)]
|
||
|
mod tests {
|
||
|
use std::any::TypeId;
|
||
|
|
||
|
use crate::{world::World, archetype::Archetype, query::View};
|
||
|
|
||
|
use super::{QueryBorrow, QueryBorrowMut};
|
||
|
|
||
|
#[derive(Clone, Copy, Debug, Default)]
|
||
|
struct Vec2 {
|
||
|
x: f32,
|
||
|
y: f32,
|
||
|
}
|
||
|
|
||
|
impl Vec2 {
|
||
|
pub fn new(x: f32, y: f32) -> Self {
|
||
|
Self {
|
||
|
x,
|
||
|
y,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// Creates a world with two entities, one at Vec(10, 50) and
|
||
|
/// the other at Vec2(25, 30).
|
||
|
fn prepare_world() -> World {
|
||
|
let mut world = World::new();
|
||
|
|
||
|
world.spawn((Vec2::new(10.0, 50.0),));
|
||
|
world.spawn((Vec2::new(25.0, 30.0),));
|
||
|
world
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn borrow_query() {
|
||
|
let world = prepare_world();
|
||
|
|
||
|
let borrow = QueryBorrow::<Vec2> {
|
||
|
type_id: TypeId::of::<Vec2>(),
|
||
|
_phantom: std::marker::PhantomData,
|
||
|
};
|
||
|
let archetypes: Vec<&Archetype> = world.archetypes.values().collect();
|
||
|
let v = View::new(borrow, archetypes);
|
||
|
|
||
|
for e in v.into_iter() {
|
||
|
println!("Found entity at {:?}", e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn borrow_mut_query() {
|
||
|
let world = prepare_world();
|
||
|
|
||
|
let borrow = QueryBorrowMut::<Vec2> {
|
||
|
type_id: TypeId::of::<Vec2>(),
|
||
|
_phantom: std::marker::PhantomData,
|
||
|
};
|
||
|
let archetypes: Vec<&Archetype> = world.archetypes.values().collect();
|
||
|
let v = View::new(borrow, archetypes);
|
||
|
|
||
|
let mut orig = vec![];
|
||
|
|
||
|
for v in v.into_iter() {
|
||
|
orig.push(v.clone());
|
||
|
v.x += 10.0;
|
||
|
v.y += 10.0;
|
||
|
}
|
||
|
|
||
|
// Now make sure the changes were actually made
|
||
|
|
||
|
let borrow = QueryBorrow::<Vec2> {
|
||
|
type_id: TypeId::of::<Vec2>(),
|
||
|
_phantom: std::marker::PhantomData,
|
||
|
};
|
||
|
let archetypes: Vec<&Archetype> = world.archetypes.values().collect();
|
||
|
let v = View::new(borrow, archetypes);
|
||
|
|
||
|
for (new, orig) in v.into_iter().zip(orig.iter()) {
|
||
|
assert!(new.x - orig.x == 10.0);
|
||
|
assert!(new.y - orig.y == 10.0);
|
||
|
}
|
||
|
println!("They were modified!");
|
||
|
}
|
||
|
}
|