use std::{marker::PhantomData, cell::{Ref, RefMut}}; use crate::{world::World, resource::ResourceObject}; use super::{Query, Fetch, AsQuery}; pub struct FetchResource<'a, T> { world: Option<&'a World>, _phantom: PhantomData, } 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::() } } /// A query type for borrowing Resources. pub struct QueryResource { _phantom: PhantomData } pub type Resource = QueryResource; impl Copy for QueryResource {} impl Clone for QueryResource { fn clone(&self) -> Self { *self } } impl Query for QueryResource { type Item<'a> = Ref<'a, T>; type Fetch<'a> = FetchResource<'a, T>; const ALWAYS_FETCHES: bool = true; fn new() -> Self { QueryResource:: { _phantom: PhantomData } } fn can_visit_archetype(&self, _archetype: &crate::archetype::Archetype) -> bool { true } unsafe fn fetch<'a>(&self, world: &'a World, _archetype: &'a crate::archetype::Archetype, tick: crate::Tick) -> Self::Fetch<'a> { let _ = tick; self.fetch_world(world).unwrap() } unsafe fn fetch_world<'a>(&self, world: &'a World) -> Option> { Some(FetchResource { world: Some(world), _phantom: PhantomData, }) } } impl AsQuery for QueryResource { type Query = QueryResource; } pub struct FetchResourceMut<'a, T> { world: Option<&'a World>, _phantom: PhantomData, } impl<'a, T: 'a + 'static> Fetch<'a> for FetchResourceMut<'a, T> { type Item = RefMut<'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_mut::() } } /// A query type for borrowing Resources mutably. pub struct QueryResourceMut { _phantom: PhantomData } pub type ResourceMut = QueryResourceMut; impl Copy for QueryResourceMut {} impl Clone for QueryResourceMut { fn clone(&self) -> Self { *self } } impl Query for QueryResourceMut { type Item<'a> = RefMut<'a, T>; type Fetch<'a> = FetchResourceMut<'a, T>; const ALWAYS_FETCHES: bool = true; fn new() -> Self { QueryResourceMut:: { _phantom: PhantomData } } fn can_visit_archetype(&self, _archetype: &crate::archetype::Archetype) -> bool { true } unsafe fn fetch<'a>(&self, world: &'a World, _archetype: &'a crate::archetype::Archetype, tick: crate::Tick) -> Self::Fetch<'a> { let _ = tick; self.fetch_world(world).unwrap() } unsafe fn fetch_world<'a>(&self, world: &'a World) -> Option> { Some(FetchResourceMut { world: Some(world), _phantom: PhantomData, }) } } impl AsQuery for QueryResourceMut { type Query = QueryResourceMut; } #[cfg(test)] mod tests { use crate::{world::World, tests::{Vec2, Vec3}, query::QueryResourceMut}; 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_iter::>(); 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_iter::<(QueryResource, &Vec2)>(); assert_eq!(i.count(), 3); let i = world.view_iter::<(&Vec2, QueryResource)>(); assert_eq!(i.count(), 3); for (res, e) in world.view_iter::<(QueryResource, &Vec2)>() { println!("Got res {}! and entity at {:?}", res.0, e); } let i = world.view_iter::>(); assert_eq!(i.count(), 1); } #[test] fn mutate_query() { let mut world = World::new(); { let counter = SomeCounter(0); world.add_resource(counter); println!("Added resource"); } { let mut resmut_iter = world.view_iter::>(); let mut resmut = resmut_iter.next().unwrap(); assert_eq!(resmut.0, 0); resmut.0 += 20; } let mut res_iter = world.view_iter::>(); let res = res_iter.next().unwrap(); assert_eq!(res.0, 20); } }