126 lines
3.4 KiB
Rust
126 lines
3.4 KiB
Rust
|
use std::{marker::PhantomData, any::TypeId, ptr::NonNull, cell::Ref};
|
||
|
|
||
|
use crate::{world::World, resource::ResourceObject};
|
||
|
|
||
|
use super::{Query, Fetch, AsQuery, DefaultQuery};
|
||
|
|
||
|
pub struct FetchResource<'a, T> {
|
||
|
world: Option<&'a World>,
|
||
|
_phantom: PhantomData<T>,
|
||
|
}
|
||
|
|
||
|
impl<'a, T: 'a + 'static> Fetch<'a> for FetchResource<'a, T> {
|
||
|
type Item = Ref<'a, T>;
|
||
|
|
||
|
fn dangling() -> Self {
|
||
|
Self {
|
||
|
world: None,
|
||
|
_phantom: PhantomData,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn can_visit_item(&mut self, _entity: crate::world::ArchetypeEntityId) -> bool {
|
||
|
true
|
||
|
}
|
||
|
|
||
|
unsafe fn get_item(&mut self, _entity: crate::world::ArchetypeEntityId) -> Self::Item {
|
||
|
let w = self.world.unwrap();
|
||
|
w.get_resource::<T>()
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
/// A query type for getting Resources
|
||
|
///
|
||
|
/// Resources are stored in an archetype with the id of [`world::RESOURCE_ARCHETYPE_ID`]. There is only one instance of a type of resource.
|
||
|
/// The resources are stored in that archetype in the first entity in the column.
|
||
|
pub struct QueryResource<T> {
|
||
|
_phantom: PhantomData<T>
|
||
|
}
|
||
|
|
||
|
pub type Resource<T> = QueryResource<T>;
|
||
|
|
||
|
impl<T: 'static> Query for QueryResource<T> {
|
||
|
type Item<'a> = Ref<'a, T>;
|
||
|
|
||
|
type Fetch<'a> = FetchResource<'a, T>;
|
||
|
|
||
|
const ALWAYS_FETCHES: bool = true;
|
||
|
|
||
|
fn can_visit_archetype(&self, _archetype: &crate::archetype::Archetype) -> bool {
|
||
|
true
|
||
|
}
|
||
|
|
||
|
unsafe fn fetch<'a>(&self, world: &'a World, _arch_id: crate::archetype::ArchetypeId, _archetype: &'a crate::archetype::Archetype) -> Self::Fetch<'a> {
|
||
|
self.fetch_world(world).unwrap()
|
||
|
}
|
||
|
|
||
|
unsafe fn fetch_world<'a>(&self, world: &'a World) -> Option<Self::Fetch<'a>> {
|
||
|
Some(FetchResource {
|
||
|
world: Some(world),
|
||
|
_phantom: PhantomData,
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<R: ResourceObject> AsQuery for QueryResource<R> {
|
||
|
type Query = QueryResource<R>;
|
||
|
}
|
||
|
|
||
|
impl<R: ResourceObject> DefaultQuery for QueryResource<R> {
|
||
|
fn default_query() -> Self::Query {
|
||
|
QueryResource::<R> {
|
||
|
_phantom: PhantomData
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#[cfg(test)]
|
||
|
mod tests {
|
||
|
use crate::{world::World, tests::{Vec2, Vec3}};
|
||
|
|
||
|
use super::QueryResource;
|
||
|
|
||
|
struct SomeCounter(u32);
|
||
|
|
||
|
#[test]
|
||
|
fn simple_query() {
|
||
|
let mut world = World::new();
|
||
|
{
|
||
|
let counter = SomeCounter(0);
|
||
|
world.add_resource(counter);
|
||
|
println!("Added resource");
|
||
|
}
|
||
|
|
||
|
let mut res_iter = world.view::<QueryResource<SomeCounter>>();
|
||
|
let res = res_iter.next().unwrap();
|
||
|
assert_eq!(res.0, 0);
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn complex_query() {
|
||
|
let mut world = World::new();
|
||
|
{
|
||
|
let counter = SomeCounter(0);
|
||
|
|
||
|
world.spawn((Vec2::rand(),));
|
||
|
world.spawn((Vec2::rand(),));
|
||
|
world.spawn((Vec2::rand(),));
|
||
|
world.spawn((Vec3::rand(),));
|
||
|
|
||
|
world.add_resource(counter);
|
||
|
println!("Added resource");
|
||
|
}
|
||
|
|
||
|
let i = world.view::<(QueryResource<SomeCounter>, &Vec2)>();
|
||
|
assert_eq!(i.count(), 3);
|
||
|
let i = world.view::<(&Vec2, QueryResource<SomeCounter>)>();
|
||
|
assert_eq!(i.count(), 3);
|
||
|
|
||
|
for (res, e) in world.view::<(QueryResource<SomeCounter>, &Vec2)>() {
|
||
|
println!("Got res {}! and entity at {:?}", res.0, e);
|
||
|
}
|
||
|
|
||
|
let i = world.view::<QueryResource<SomeCounter>>();
|
||
|
assert_eq!(i.count(), 1);
|
||
|
}
|
||
|
}
|