use std::cell::RefMut;
use std::ops::{Deref, DerefMut};
use crate::ecs::resources::Resources;
#[derive(Clone, Copy)]
pub struct RequiredResource {
pub name: &'static str,
pub present: fn(&hecs::World, &Resources) -> bool,
}
pub struct Res<'a, T: hecs::Component> {
pub(crate) data: hecs::Ref<'a, T>,
}
impl<'a, T: hecs::Component> Deref for Res<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.data
}
}
pub struct ResMut<'a, T: hecs::Component> {
data: hecs::RefMut<'a, T>,
}
impl<'a, T: hecs::Component> Deref for ResMut<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.data
}
}
impl<'a, T: hecs::Component> DerefMut for ResMut<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.data
}
}
pub struct Query<'a, Q: hecs::Query> {
world: &'a hecs::World,
borrow: hecs::QueryBorrow<'a, Q>,
}
impl<'a, Q: hecs::Query> Deref for Query<'a, Q> {
type Target = hecs::QueryBorrow<'a, Q>;
fn deref(&self) -> &Self::Target {
&self.borrow
}
}
impl<'a, Q: hecs::Query> DerefMut for Query<'a, Q> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.borrow
}
}
impl<'q, Q: hecs::Query> IntoIterator for &'q mut Query<'_, Q> {
type Item = Q::Item<'q>;
type IntoIter = hecs::QueryIter<'q, Q>;
fn into_iter(self) -> Self::IntoIter {
(&mut self.borrow).into_iter()
}
}
impl<'a, Q: hecs::Query> Query<'a, Q> {
pub fn get(&self, entity: hecs::Entity) -> hecs::QueryOne<'_, Q> {
self.world.query_one::<Q>(entity)
}
pub fn with<R: hecs::Query>(self) -> hecs::QueryBorrow<'a, hecs::With<Q, R>> {
self.borrow.with::<R>()
}
pub fn without<R: hecs::Query>(self) -> hecs::QueryBorrow<'a, hecs::Without<Q, R>> {
self.borrow.without::<R>()
}
pub fn single(&mut self) -> Q::Item<'_> {
self.get_single()
.expect("Query::single: expected exactly one matching entity")
}
pub fn get_single(&mut self) -> Option<Q::Item<'_>> {
let mut iter = self.borrow.iter();
let first = iter.next()?;
if iter.next().is_some() {
return None;
}
Some(first)
}
}
pub struct Commands<'a> {
buffer: RefMut<'a, hecs::CommandBuffer>,
resource_entity: hecs::Entity,
resources: &'a Resources,
}
impl<'a> Commands<'a> {
pub fn insert_resource<T: hecs::Component>(&mut self, res: T) {
self.buffer.insert_one(self.resource_entity, res);
self.resources.bump_generation();
}
pub fn remove_resource<T: hecs::Component>(&mut self) {
self.buffer.remove_one::<T>(self.resource_entity);
}
}
impl<'a> Deref for Commands<'a> {
type Target = hecs::CommandBuffer;
fn deref(&self) -> &Self::Target {
&self.buffer
}
}
impl<'a> DerefMut for Commands<'a> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.buffer
}
}
pub struct Local<'a, T: Default + Send + Sync + 'static> {
data: &'a mut T,
}
impl<'a, T: Default + Send + Sync + 'static> Deref for Local<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.data
}
}
impl<'a, T: Default + Send + Sync + 'static> DerefMut for Local<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.data
}
}
pub trait SystemParam {
type Item<'a>;
type State: Default + 'static;
fn fetch<'a>(
state: &'a mut Self::State,
world: &'a hecs::World,
resources: &'a Resources,
) -> Self::Item<'a>;
fn requires() -> Vec<RequiredResource> {
Vec::new()
}
}
impl<T> SystemParam for Res<'static, T>
where
T: 'static + Sync + Send,
{
type Item<'a> = Res<'a, T>;
type State = ();
fn fetch<'a>(
_state: &'a mut Self::State,
world: &'a hecs::World,
resource: &'a Resources,
) -> Self::Item<'a> {
Res {
data: resource.get_resource(world),
}
}
fn requires() -> Vec<RequiredResource> {
vec![RequiredResource {
name: std::any::type_name::<T>(),
present: |world, resources| resources.has_resource::<T>(world),
}]
}
}
impl<T> SystemParam for Option<Res<'static, T>>
where
T: 'static + Sync + Send,
{
type Item<'a> = Option<Res<'a, T>>;
type State = ();
fn fetch<'a>(
_state: &'a mut Self::State,
world: &'a hecs::World,
resource: &'a Resources,
) -> Self::Item<'a> {
if resource.has_resource::<T>(world) {
return Some(Res {
data: resource.get_resource(world),
});
}
None
}
}
impl<T> SystemParam for ResMut<'static, T>
where
T: 'static + Sync + Send,
{
type Item<'a> = ResMut<'a, T>;
type State = ();
fn fetch<'a>(
_state: &'a mut Self::State,
world: &'a hecs::World,
resource: &'a Resources,
) -> Self::Item<'a> {
ResMut {
data: resource.get_resource_mut(world),
}
}
fn requires() -> Vec<RequiredResource> {
vec![RequiredResource {
name: std::any::type_name::<T>(),
present: |world, resources| resources.has_resource::<T>(world),
}]
}
}
impl<T> SystemParam for Option<ResMut<'static, T>>
where
T: 'static + Sync + Send,
{
type Item<'a> = Option<ResMut<'a, T>>;
type State = ();
fn fetch<'a>(
_state: &'a mut Self::State,
world: &'a hecs::World,
resource: &'a Resources,
) -> Self::Item<'a> {
if resource.has_resource::<T>(world) {
return Some(ResMut {
data: resource.get_resource_mut(world),
});
}
None
}
}
impl<Q> SystemParam for Query<'static, Q>
where
Q: hecs::Query + 'static,
{
type Item<'a> = Query<'a, Q>;
type State = ();
fn fetch<'a>(
_state: &'a mut Self::State,
world: &'a hecs::World,
_resources: &'a Resources,
) -> Self::Item<'a> {
Query {
world: world,
borrow: world.query::<Q>(),
}
}
}
impl SystemParam for Commands<'static> {
type Item<'a> = Commands<'a>;
type State = ();
fn fetch<'a>(
_state: &'a mut Self::State,
_world: &'a hecs::World,
resources: &'a Resources,
) -> Self::Item<'a> {
Commands {
buffer: resources.get_command_buffer(),
resource_entity: resources.resource_entity,
resources,
}
}
}
impl SystemParam for &'static hecs::World {
type Item<'a> = &'a hecs::World;
type State = ();
fn fetch<'a>(
_state: &'a mut Self::State,
world: &'a hecs::World,
_resources: &'a Resources,
) -> Self::Item<'a> {
world
}
}
impl SystemParam for &'static Resources {
type Item<'a> = &'a Resources;
type State = ();
fn fetch<'a>(
_state: &'a mut Self::State,
_world: &'a hecs::World,
resources: &'a Resources,
) -> Self::Item<'a> {
resources
}
}
impl<T> SystemParam for Local<'static, T>
where
T: Default + Send + Sync + 'static,
{
type Item<'a> = Local<'a, T>;
type State = T;
fn fetch<'a>(
state: &'a mut Self::State,
_world: &'a hecs::World,
_resources: &'a Resources,
) -> Self::Item<'a> {
Local { data: state }
}
}
pub trait System: 'static {
fn run(&mut self, world: &hecs::World, resources: &Resources);
fn requires(&self) -> Vec<RequiredResource> {
Vec::new()
}
fn name(&self) -> &'static str {
std::any::type_name::<Self>()
}
}
pub struct FunctionSystem<F, Marker, State = ()> {
pub func: F,
state: State,
_marker: std::marker::PhantomData<Marker>,
}
pub trait IntoSystem<Marker> {
type System: System;
fn into_system(self) -> Self::System;
}
macro_rules! impl_system {
($($param:ident),*) => {
impl<T, $($param),*> IntoSystem<($($param,)*)> for T
where
T: for<'a> FnMut($($param::Item<'a>),*) + 'static,
for<'a> &'a mut T: FnMut($($param),*),
$($param: SystemParam + 'static),*
{
type System = FunctionSystem<T, ($($param,)*), ($($param::State,)*)>;
fn into_system(self) -> Self::System {
FunctionSystem {
func: self,
state: Default::default(),
_marker: std::marker::PhantomData,
}
}
}
impl<T, $($param),*> System for FunctionSystem<T, ($($param,)*), ($($param::State,)*)>
where
T: for<'a> FnMut($($param::Item<'a>),*) + 'static,
$($param: SystemParam + 'static),*
{
fn run(&mut self, _world: &hecs::World, _resources: &Resources) {
#[allow(non_snake_case)]
let ($($param,)*) = &mut self.state;
(self.func)($($param::fetch($param, _world, _resources)),*);
}
fn requires(&self) -> Vec<RequiredResource> {
let mut _v = Vec::new();
$(_v.extend($param::requires());)*
_v
}
fn name(&self) -> &'static str {
std::any::type_name::<T>()
}
}
};
}
impl_system!();
impl_system!(A);
impl_system!(A, B);
impl_system!(A, B, C);
impl_system!(A, B, C, D);
impl_system!(A, B, C, D, E);
impl_system!(A, B, C, D, E, F);
impl_system!(A, B, C, D, E, F, G);
impl_system!(A, B, C, D, E, F, G, H);
impl_system!(A, B, C, D, E, F, G, H, I);
impl_system!(A, B, C, D, E, F, G, H, I, J);
impl_system!(A, B, C, D, E, F, G, H, I, J, K);
impl_system!(A, B, C, D, E, F, G, H, I, J, K, L);