use crate::{DataAccesses, MaskType, sync::{ReadGuardRef, WriteGuardRef, Lock}};
use hashbrown::HashMap;
use std::any::{TypeId, Any};
#[cfg(feature="dynamic_systems")]
use crate::dynamic_system_loader::DynamicSystemsLoader;
#[cfg(feature="dynamic_systems")]
use crate::DynamicSymbol;
#[cfg(all(feature="parallel_systems", feature="lockfree"))]
#[cfg(not(components_bigint))]
use num_traits::Zero;
pub struct Res<'a, T> (pub &'a T);
impl<'a,T> std::ops::Deref for Res<'a, T> {
type Target = T;
fn deref(&self) -> &T{
&self.0
}
}
impl<'a, T: 'static> DataAccesses for Res<'a, T> {
fn reads() -> Vec<TypeId> {
vec![TypeId::of::<T>()]
}
fn writes() -> Vec<TypeId> {
vec![]
}
}
pub struct ResMut<'a, T> (pub &'a mut T);
impl<'a,T> std::ops::Deref for ResMut<'a, T> {
type Target = T;
fn deref(&self) -> &T{
&self.0
}
}
impl<'a,T> std::ops::DerefMut for ResMut<'a, T> {
fn deref_mut(&mut self) -> &mut T{
&mut self.0
}
}
impl<'a, T: 'static> DataAccesses for ResMut<'a, T> {
fn reads() -> Vec<TypeId> {
vec![TypeId::of::<T>()]
}
fn writes() -> Vec<TypeId> {
vec![TypeId::of::<T>()]
}
}
#[derive(Clone, Copy)]
pub struct Resources<'a>{
pub(crate) resources: &'a ResourcesContainer,
pub(crate) resource_mask_r: Option<&'a MaskType>,
pub(crate) resource_mask_w: Option<&'a MaskType>,
pub(crate) system_info: &'a str,
#[cfg(feature="dynamic_systems")]
pub(crate) dynamic_systems: &'a DynamicSystemsLoader,
}
unsafe impl<'a> Send for Resources<'a>{}
unsafe impl<'a> Sync for Resources<'a>{}
impl<'a> Resources<'a>{
pub fn get<T: 'static + Send>(&self) -> Option<ReadGuardRef<'a, T>>{
self.resources.get(self.resource_mask_r, self.system_info)
}
pub fn get_mut<T: 'static + Send>(&self) -> Option<WriteGuardRef<'a, T>>{
self.resources.get_mut(self.resource_mask_w, self.system_info)
}
pub fn as_trait<T: 'static + Send + ?Sized>(&self) -> Option<ReadGuardRef<'a, T>>{
self.resources.as_trait(self.resource_mask_r, self.system_info)
}
pub fn as_trait_mut<T: 'static + Send + ?Sized>(&self) -> Option<WriteGuardRef<'a, T>>{
self.resources.as_trait_mut(self.resource_mask_w, self.system_info)
}
#[cfg(feature="dynamic_systems")]
pub unsafe fn get_dynamic_symbol<S>(&self, symbol_path: &str) -> Result<DynamicSymbol<S>, String>{
self.dynamic_systems.get_dynamic_symbol(symbol_path)
}
pub(crate) fn check_resource(&self, id: &TypeId, func: &Box<dyn Any>) -> bool {
self.resources.check_resource(id, func)
}
pub(crate) fn has_resource(&self, id: &TypeId) -> bool {
self.resources.has_resource(id)
}
}
#[derive(Clone, Copy)]
pub struct ResourcesThreadLocal<'a>{
pub(crate) resources: &'a ResourcesContainer,
pub(crate) resource_mask_r: Option<&'a MaskType>,
pub(crate) resource_mask_w: Option<&'a MaskType>,
pub(crate) system_info: &'a str,
#[cfg(feature="dynamic_systems")]
pub(crate) dynamic_systems: &'a DynamicSystemsLoader,
}
impl<'a> ResourcesThreadLocal<'a>{
pub fn get<T: 'static>(&self) -> Option<ReadGuardRef<'a, T>>{
self.resources.get(self.resource_mask_r, self.system_info)
}
pub fn get_mut<T: 'static>(&self) -> Option<WriteGuardRef<'a, T>>{
self.resources.get_mut(self.resource_mask_w, self.system_info)
}
pub fn as_trait<T: 'static + ?Sized>(&self) -> Option<ReadGuardRef<'a, T>>{
self.resources.as_trait(self.resource_mask_r, self.system_info)
}
pub fn as_trait_mut<T: 'static + ?Sized>(&self) -> Option<WriteGuardRef<'a, T>>{
self.resources.as_trait_mut(self.resource_mask_w, self.system_info)
}
pub fn to_send(&self) -> Resources<'a>{
Resources{
resources: self.resources,
resource_mask_r: self.resource_mask_r,
resource_mask_w: self.resource_mask_w,
system_info: self.system_info,
#[cfg(feature="dynamic_systems")]
dynamic_systems: self.dynamic_systems,
}
}
#[cfg(feature="dynamic_systems")]
pub unsafe fn get_dynamic_symbol<S>(&self, symbol_path: &str) -> Result<DynamicSymbol<S>, String>{
self.dynamic_systems.get_dynamic_symbol(symbol_path)
}
pub(crate) fn check_resource(&self, id: &TypeId, func: &Box<dyn Any>) -> bool {
self.resources.check_resource(id, func)
}
pub(crate) fn has_resource(&self, id: &TypeId) -> bool {
self.resources.has_resource(id)
}
pub fn clone(&mut self) -> Resources {
Resources {
resources: self.resources,
resource_mask_r: self.resource_mask_r,
resource_mask_w: self.resource_mask_w,
system_info: self.system_info,
#[cfg(feature="dynamic_systems")]
dynamic_systems: self.dynamic_systems
}
}
}
pub struct ResourcesCreation<'a>{
pub(crate) resources: &'a mut ResourcesContainer,
pub(crate) system_info: &'a str,
#[cfg(feature="dynamic_systems")]
pub(crate) dynamic_systems: &'a DynamicSystemsLoader,
}
impl<'a> ResourcesCreation<'a>{
pub fn get<T: 'static>(&self) -> Option<ReadGuardRef<T>>{
self.resources.get(None, self.system_info)
}
pub fn get_mut<T: 'static>(&self) -> Option<WriteGuardRef<T>>{
self.resources.get_mut(None, self.system_info)
}
pub fn as_trait<T: 'static + ?Sized>(&self) -> Option<ReadGuardRef<T>>{
self.resources.as_trait(None, self.system_info)
}
pub fn as_trait_mut<T: 'static + ?Sized>(&self) -> Option<WriteGuardRef<T>>{
self.resources.as_trait_mut(None, self.system_info)
}
pub fn to_send(&mut self) -> Resources {
Resources{
resources: self.resources,
resource_mask_r: None,
resource_mask_w: None,
system_info: self.system_info,
#[cfg(feature="dynamic_systems")]
dynamic_systems: self.dynamic_systems,
}
}
pub fn to_thread_local(&mut self) -> ResourcesThreadLocal {
ResourcesThreadLocal{
resources: self.resources,
resource_mask_r: None,
resource_mask_w: None,
system_info: self.system_info,
#[cfg(feature="dynamic_systems")]
dynamic_systems: self.dynamic_systems,
}
}
#[cfg(feature="dynamic_systems")]
pub unsafe fn get_dynamic_symbol<S>(&self, symbol_path: &str) -> Result<DynamicSymbol<S>, String>{
self.dynamic_systems.get_dynamic_symbol(symbol_path)
}
pub(crate) fn check_resource(&self, id: &TypeId, func: &Box<dyn Any>) -> bool {
self.resources.check_resource(id, func)
}
pub(crate) fn has_resource(&self, id: &TypeId) -> bool {
self.resources.has_resource(id)
}
pub fn add<T: 'static + Send>(&mut self, resource: T){
self.resources.add(resource);
}
pub fn add_thread_local<T: 'static>(&mut self, resource: T){
self.resources.add_thread_local(resource);
}
pub fn add_as_trait<T, U, F, FMut>(&mut self, resource: (T, F, FMut))
where T: 'static + Send,
U: 'static + Send + ?Sized,
F: Fn(&T) -> &U + 'static,
FMut: Fn(&mut T) -> &mut U + 'static,
{
let (resource, f, fmut) = resource;
self.add(resource);
self.resources.add_as_trait::<T,U,F,FMut>(f, fmut)
}
pub fn add_as_trait_thread_local<T, U, F, FMut>(&mut self, resource: (T, F, FMut))
where T: 'static,
U: 'static + ?Sized,
F: Fn(&T) -> &U + 'static,
FMut: Fn(&mut T) -> &mut U + 'static,
{
let (resource, f, fmut) = resource;
self.add_thread_local(resource);
self.resources.add_as_trait_thread_local::<T,U,F,FMut>(f, fmut)
}
pub fn remove<T: 'static>(&mut self) -> Option<T>{
self.resources.remove()
}
pub fn clone(&mut self) -> ResourcesCreation {
ResourcesCreation {
resources: self.resources,
system_info: self.system_info,
#[cfg(feature="dynamic_systems")]
dynamic_systems: self.dynamic_systems
}
}
}
pub trait ResourcesExt {
fn resource<T: 'static + Send>(&self) -> Option<ReadGuardRef<T>>;
fn resource_mut<T: 'static + Send>(&self) -> Option<WriteGuardRef<T>>;
fn resource_as_trait<T: 'static + Send + ?Sized>(&self) -> Option<ReadGuardRef<T>>;
fn resource_as_trait_mut<T: 'static + Send + ?Sized>(&self) -> Option<WriteGuardRef<T>>;
}
pub trait ResourcesThreadLocalExt {
fn resource_thread_local<T: 'static>(&self) -> Option<ReadGuardRef<T>>;
fn resource_thread_local_mut<T: 'static>(&self) -> Option<WriteGuardRef<T>>;
fn resource_as_trait_thread_local<T: 'static + ?Sized>(&self) -> Option<ReadGuardRef<T>>;
fn resource_as_trait_thread_local_mut<T: 'static + ?Sized>(&self) -> Option<WriteGuardRef<T>>;
}
impl<'a> ResourcesExt for Resources<'a> {
fn resource<T: 'static + Send>(&self) -> Option<ReadGuardRef<T>> {
self.get()
}
fn resource_mut<T: 'static + Send>(&self) -> Option<WriteGuardRef<T>> {
self.get_mut()
}
fn resource_as_trait<T: 'static + Send + ?Sized>(&self) -> Option<ReadGuardRef<T>> {
self.as_trait()
}
fn resource_as_trait_mut<T: 'static + Send + ?Sized>(&self) -> Option<WriteGuardRef<T>> {
self.as_trait_mut()
}
}
impl<'a> ResourcesExt for ResourcesThreadLocal<'a> {
fn resource<T: 'static + Send>(&self) -> Option<ReadGuardRef<T>> {
self.get()
}
fn resource_mut<T: 'static + Send>(&self) -> Option<WriteGuardRef<T>> {
self.get_mut()
}
fn resource_as_trait<T: 'static + Send + ?Sized>(&self) -> Option<ReadGuardRef<T>> {
self.as_trait()
}
fn resource_as_trait_mut<T: 'static + Send + ?Sized>(&self) -> Option<WriteGuardRef<T>> {
self.as_trait_mut()
}
}
impl<'a> ResourcesThreadLocalExt for ResourcesThreadLocal<'a> {
fn resource_thread_local<T: 'static>(&self) -> Option<ReadGuardRef<T>> {
self.get()
}
fn resource_thread_local_mut<T: 'static>(&self) -> Option<WriteGuardRef<T>> {
self.get_mut()
}
fn resource_as_trait_thread_local<T: 'static + ?Sized>(&self) -> Option<ReadGuardRef<T>> {
self.as_trait()
}
fn resource_as_trait_thread_local_mut<T: 'static + ?Sized>(&self) -> Option<WriteGuardRef<T>> {
self.as_trait_mut()
}
}
impl<'a> ResourcesExt for ResourcesCreation<'a> {
fn resource<T: 'static + Send>(&self) -> Option<ReadGuardRef<T>> {
self.get()
}
fn resource_mut<T: 'static + Send>(&self) -> Option<WriteGuardRef<T>> {
self.get_mut()
}
fn resource_as_trait<T: 'static + Send + ?Sized>(&self) -> Option<ReadGuardRef<T>> {
self.as_trait()
}
fn resource_as_trait_mut<T: 'static + Send + ?Sized>(&self) -> Option<WriteGuardRef<T>> {
self.as_trait_mut()
}
}
impl<'a> ResourcesThreadLocalExt for ResourcesCreation<'a> {
fn resource_thread_local<T: 'static>(&self) -> Option<ReadGuardRef<T>> {
self.get()
}
fn resource_thread_local_mut<T: 'static>(&self) -> Option<WriteGuardRef<T>> {
self.get_mut()
}
fn resource_as_trait_thread_local<T: 'static + ?Sized>(&self) -> Option<ReadGuardRef<T>> {
self.as_trait()
}
fn resource_as_trait_thread_local_mut<T: 'static + ?Sized>(&self) -> Option<WriteGuardRef<T>> {
self.as_trait_mut()
}
}
pub struct MaskedResource {
dependency_mask: MaskType,
resource: Box<dyn Any>,
}
pub struct MaskedTraitResource {
resource_dependency_mask: MaskType,
trait_dependency_mask: MaskType,
resource_typeid: TypeId,
trait_to_resource: Box<dyn Any>,
}
#[derive(Default)]
pub struct ResourcesContainer{
resources: HashMap<TypeId, MaskedResource>,
resources_traits: HashMap<TypeId, MaskedTraitResource>,
resources_traits_mut: HashMap<TypeId, MaskedTraitResource>,
resource_checks: HashMap<TypeId, Box<dyn Fn(&Box<dyn Any>, &Box<dyn Any>) -> bool>>,
resources_index: HashMap<TypeId, MaskType>,
reverse_trait_index: HashMap<TypeId, TypeId>,
traits_changed: bool,
}
impl ResourcesContainer{
pub fn set_resources_index(&mut self, resources_index: HashMap<TypeId, MaskType>){
self.resources_index = resources_index.clone();
for (typeid, resource) in self.resources.iter_mut(){
resource.dependency_mask = resources_index.get(&typeid).cloned().unwrap_or(MaskType::zero());
}
for (typeid, resource_trait) in self.resources_traits.iter_mut(){
resource_trait.resource_dependency_mask = resources_index
.get(&resource_trait.resource_typeid)
.cloned()
.unwrap_or(MaskType::zero());
resource_trait.trait_dependency_mask = resources_index.get(&typeid).cloned().unwrap_or(MaskType::zero());
}
for (typeid, resource_trait) in self.resources_traits_mut.iter_mut(){
resource_trait.resource_dependency_mask = resources_index
.get(&resource_trait.resource_typeid)
.cloned()
.unwrap_or(MaskType::zero());
resource_trait.trait_dependency_mask = resources_index.get(&typeid).cloned().unwrap_or(MaskType::zero());
}
}
pub fn reverse_trait_index(&self) -> &HashMap<TypeId, TypeId> {
&self.reverse_trait_index
}
pub fn take_traits_changed(&mut self) -> bool {
std::mem::replace(&mut self.traits_changed, false)
}
pub fn add<T: 'static + Send>(&mut self, resource: T){
self.resources.insert(TypeId::of::<T>(), MaskedResource{
dependency_mask: self.resources_index.get(&TypeId::of::<T>()).cloned().unwrap_or(MaskType::zero()),
resource: Box::new(Lock::new(resource)) as Box<dyn Any>
});
let resource_check = |resource: &Box<dyn Any>, check: &Box<dyn Any>|{
let check: &Box<dyn Fn(&T) -> bool> = check.downcast_ref().unwrap();
let resource: &Lock<T> = resource.downcast_ref().unwrap();
check(&resource.read())
};
self.resource_checks.insert(TypeId::of::<T>(), Box::new(resource_check));
}
pub fn add_thread_local<T: 'static>(&mut self, resource: T){
self.resources.insert(TypeId::of::<T>(), MaskedResource{
dependency_mask: self.resources_index.get(&TypeId::of::<T>()).cloned().unwrap_or(MaskType::zero()),
resource: Box::new(Lock::new(resource)) as Box<dyn Any>
});
let resource_check = |resource: &Box<dyn Any>, check: &Box<dyn Any>|{
let check: &Box<dyn Fn(&T) -> bool> = check.downcast_ref().unwrap();
let resource: &Lock<T> = resource.downcast_ref().unwrap();
check(&resource.read())
};
self.resource_checks.insert(TypeId::of::<T>(), Box::new(resource_check));
}
pub fn add_as_trait<T, U, F, FMut>(&mut self, f: F, fmut: FMut)
where T: 'static + Send,
U: 'static + Send + ?Sized,
F: Fn(&T) -> &U + 'static,
FMut: Fn(&mut T) -> &mut U + 'static,
{
let f: Box<dyn for<'a> Fn(&'a ResourcesContainer, Option<&MaskType>, &str) -> ReadGuardRef<'a, U>>
= Box::new(move |resources: &ResourcesContainer, mask: Option<&MaskType>, system_info: &str|{
ReadGuardRef::map(resources.get::<T>(mask, system_info).unwrap(), |t| f(t))
});
let fmut: Box<dyn for<'a> Fn(&'a ResourcesContainer, Option<&MaskType>, &str) -> WriteGuardRef<'a, U>>
= Box::new(move |resources: &ResourcesContainer, mask: Option<&MaskType>, system_info: &str|{
WriteGuardRef::map(resources.get_mut::<T>(mask, system_info).unwrap(), |t| fmut(t))
});
self.resources_traits.insert(TypeId::of::<U>(), MaskedTraitResource{
trait_dependency_mask: self.resources_index.get(&TypeId::of::<U>()).cloned().unwrap_or(MaskType::zero()),
resource_dependency_mask: self.resources_index.get(&TypeId::of::<T>()).cloned().unwrap_or(MaskType::zero()),
resource_typeid: TypeId::of::<T>(),
trait_to_resource: Box::new(f),
});
self.resources_traits_mut.insert(TypeId::of::<U>(), MaskedTraitResource{
trait_dependency_mask: self.resources_index.get(&TypeId::of::<U>()).cloned().unwrap_or(MaskType::zero()),
resource_dependency_mask: self.resources_index.get(&TypeId::of::<T>()).cloned().unwrap_or(MaskType::zero()),
resource_typeid: TypeId::of::<T>(),
trait_to_resource: Box::new(fmut),
});
self.reverse_trait_index.insert(TypeId::of::<T>(), TypeId::of::<U>());
self.traits_changed = true;
}
pub fn add_as_trait_thread_local<T, U, F, FMut>(&mut self, f: F, fmut: FMut)
where T: 'static,
U: 'static + ?Sized,
F: Fn(&T) -> &U + 'static,
FMut: Fn(&mut T) -> &mut U + 'static,
{
let f: Box<dyn for<'a> Fn(&'a ResourcesContainer, Option<&MaskType>, &str) -> ReadGuardRef<'a, U>>
= Box::new(move |resources: &ResourcesContainer, mask: Option<&MaskType>, system_info: &str|{
ReadGuardRef::map(resources.get::<T>(mask, system_info).unwrap(), |t| f(t))
});
let fmut: Box<dyn for<'a> Fn(&'a ResourcesContainer, Option<&MaskType>, &str) -> WriteGuardRef<'a, U>>
= Box::new(move |resources: &ResourcesContainer, mask: Option<&MaskType>, system_info: &str|{
WriteGuardRef::map(resources.get_mut::<T>(mask, system_info).unwrap(), |t| fmut(t))
});
self.resources_traits.insert(TypeId::of::<U>(), MaskedTraitResource{
trait_dependency_mask: self.resources_index.get(&TypeId::of::<U>()).cloned().unwrap_or(MaskType::zero()),
resource_dependency_mask: self.resources_index.get(&TypeId::of::<T>()).cloned().unwrap_or(MaskType::zero()),
resource_typeid: TypeId::of::<T>(),
trait_to_resource: Box::new(f),
});
self.resources_traits_mut.insert(TypeId::of::<U>(), MaskedTraitResource{
trait_dependency_mask: self.resources_index.get(&TypeId::of::<U>()).cloned().unwrap_or(MaskType::zero()),
resource_dependency_mask: self.resources_index.get(&TypeId::of::<T>()).cloned().unwrap_or(MaskType::zero()),
resource_typeid: TypeId::of::<T>(),
trait_to_resource: Box::new(fmut),
});
self.reverse_trait_index.insert(TypeId::of::<T>(), TypeId::of::<U>());
self.traits_changed = true;
}
#[inline]
pub fn check_resource(&self, id: &TypeId, func: &Box<dyn Any>) -> bool {
let resource = &self.resources[id].resource;
self.resource_checks[id](resource, func)
}
#[inline]
pub fn resources_mut(&mut self) -> &mut HashMap<TypeId, MaskedResource>{
&mut self.resources
}
pub fn remove<T: 'static>(&mut self) -> Option<T> {
self.resources.remove(&TypeId::of::<T>()).map(|t| {
let t: Box<Lock<T>> = t.resource.downcast().unwrap();
t.into_inner()
})
}
#[inline]
pub fn get<T: 'static>(&self, _mask: Option<&MaskType>, _system_info: &str) -> Option<ReadGuardRef<T>>{
self.resources.get(&TypeId::of::<T>()).map(|t| {
#[cfg(all(feature="parallel_systems", feature="lockfree"))]
if let Some(mask) = _mask {
if mask & &t.dependency_mask == MaskType::zero() {
println!("Doesn't have mask {:?}", mask);
panic!("Trying to retrieve resource {} that this system doesn't have read access to. {}",
std::any::type_name::<T>(),
_system_info
);
}
}
let t: &Lock<T> = t.resource.downcast_ref().unwrap();
ReadGuardRef::new(t.read())
})
}
#[inline]
pub fn get_mut<T: 'static>(&self, _mask: Option<&MaskType>, _system_info: &str) -> Option<WriteGuardRef<T>>{
self.resources.get(&TypeId::of::<T>()).map(|t| {
#[cfg(all(feature="parallel_systems", feature="lockfree"))]
if let Some(mask) = _mask {
if mask & &t.dependency_mask == MaskType::zero() {
panic!("Trying to retrieve resource {} that this system doesn't have write access to. {}",
std::any::type_name::<T>(),
_system_info
);
}
}
let t: &Lock<T> = t.resource.downcast_ref().unwrap();
WriteGuardRef::new(t.write())
})
}
pub fn as_trait<T: 'static + ?Sized>(&self, mask: Option<&MaskType>, system_info: &str) -> Option<ReadGuardRef<T>>{
self.resources_traits.get(&TypeId::of::<T>()).map(|f| {
#[cfg(all(feature="parallel_systems", feature="lockfree"))]
let mask = mask.map(|mask| if mask & &f.trait_dependency_mask != MaskType::zero(){
mask & !&f.trait_dependency_mask | &f.resource_dependency_mask
}else{
mask.clone()
});
#[cfg(all(feature="parallel_systems", feature="lockfree"))]
let mask = mask.as_ref();
let f: &Box<dyn for<'a> Fn(&'a ResourcesContainer, Option<&MaskType>, &str) -> ReadGuardRef<'a, T>>
= f.trait_to_resource.downcast_ref().unwrap();
f(self, mask, system_info)
})
}
pub fn as_trait_mut<T: 'static + ?Sized>(&self, mask: Option<&MaskType>, system_info: &str) -> Option<WriteGuardRef<T>>{
self.resources_traits_mut.get(&TypeId::of::<T>()).map(|f| {
#[cfg(all(feature="parallel_systems", feature="lockfree"))]
let mask = mask.map(|mask| if mask & &f.trait_dependency_mask != MaskType::zero(){
mask & !&f.trait_dependency_mask | &f.resource_dependency_mask
}else{
mask.clone()
});
#[cfg(all(feature="parallel_systems", feature="lockfree"))]
let mask = mask.as_ref();
let f: &Box<dyn for<'a> Fn(&'a ResourcesContainer, Option<&MaskType>, &str) -> WriteGuardRef<'a, T>>
= f.trait_to_resource.downcast_ref().unwrap();
f(self, mask, system_info)
})
}
pub(crate) fn has_resource(&self, id: &TypeId) -> bool {
self.resources.contains_key(id)
}
}