use crate::prelude::*;
use bevy::ecs::system::BoxedSystem;
use bevy::prelude::*;
use bevy::utils::{AHasher, HashMap};
use std::any::TypeId;
use std::hash::{Hash, Hasher};
pub fn named_syscall<H, I, O, S, Marker>(
world : &mut World,
id : H,
input : <I as SystemInput>::Inner<'_>,
system : S
) -> O
where
H: Hash,
I: Send + Sync + SystemInput + 'static,
O: Send + Sync + 'static,
S: IntoSystem<I, O, Marker> + Send + Sync + 'static,
{
let sys_name = SysName::new::<S>(id);
let mut id_mapped_systems = world.get_resource_or_insert_with::<IdMappedSystems<I, O>>(
|| IdMappedSystems::default()
);
let mut system =
match id_mapped_systems.systems.get_mut(&sys_name).map_or(None, |node| node.take())
{
Some(system) => system,
None =>
{
let mut sys = IntoSystem::into_system(system);
sys.initialize(world);
Box::new(sys)
}
};
let result = system.run(input, world);
system.apply_deferred(world);
let mut id_mapped_systems = world.get_resource_or_insert_with::<IdMappedSystems<I, O>>(
|| IdMappedSystems::default()
);
match id_mapped_systems.systems.get_mut(&sys_name)
{
Some(node) => { let _ = node.replace(system); },
None => { let _ = id_mapped_systems.systems.insert(sys_name, Some(system)); },
}
result
}
pub fn named_syscall_direct<I, O>(world: &mut World, sys_name: SysName, input: <I as SystemInput>::Inner<'_>) -> Result<O, ()>
where
I: Send + Sync + SystemInput + 'static,
O: Send + Sync + 'static,
{
let mut id_mapped_systems = world.get_resource_or_insert_with::<IdMappedSystems<I, O>>(
|| IdMappedSystems::default()
);
let mut system =
match id_mapped_systems.systems.get_mut(&sys_name).map_or(None, |node| node.take())
{
Some(system) => system,
None => return Err(()),
};
let result = system.run(input, world);
system.apply_deferred(world);
let mut id_mapped_systems = world.get_resource_or_insert_with::<IdMappedSystems<I, O>>(
|| IdMappedSystems::default()
);
match id_mapped_systems.systems.get_mut(&sys_name)
{
Some(node) => { let _ = node.replace(system); },
None => { let _ = id_mapped_systems.systems.insert(sys_name, Some(system)); },
}
Ok(result)
}
pub fn register_named_system<I, O, S, Marker>(world: &mut World, sys_name: SysName, system: S)
where
I: Send + Sync + SystemInput + 'static,
O: Send + Sync + 'static,
S: IntoSystem<I, O, Marker> + Send + Sync + 'static,
{
register_named_system_from(world, sys_name, CallbackSystem::new(system));
}
pub fn register_named_system_from<I, O>(world: &mut World, sys_name: SysName, callback: CallbackSystem<I, O>)
where
I: Send + Sync + SystemInput + 'static,
O: Send + Sync + 'static,
{
let Some(boxed_system) = callback.take_initialized(world) else { return; };
let mut id_mapped_systems = world.get_resource_or_insert_with::<IdMappedSystems<I, O>>(
|| IdMappedSystems::default()
);
match id_mapped_systems.systems.get_mut(&sys_name)
{
Some(node) => { let _ = node.replace(boxed_system); },
None => { let _ = id_mapped_systems.systems.insert(sys_name, Some(boxed_system)); },
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct SysName(u64, TypeId);
impl SysName
{
pub fn new<S: 'static>(id: impl Hash) -> Self
{
let mut hasher = AHasher::default();
id.hash(&mut hasher);
SysName(hasher.finish(), TypeId::of::<S>())
}
pub fn new_raw<S: 'static>(id: u64) -> Self
{
SysName(id, TypeId::of::<S>())
}
pub fn id(&self) -> u64
{
self.0
}
pub fn type_id(&self) -> TypeId
{
self.1
}
}
#[derive(Resource)]
pub struct IdMappedSystems<I, O>
where
I: Send + Sync + SystemInput + 'static,
O: Send + Sync + 'static,
{
systems: HashMap<SysName, Option<BoxedSystem<I, O>>>,
}
impl<I, O> IdMappedSystems<I, O>
where
I: Send + Sync + SystemInput + 'static,
O: Send + Sync + 'static,
{
pub fn revoke<S: 'static>(&mut self, id: impl Hash)
{
let id = SysName::new::<S>(id);
let _ = self.systems.remove(&id);
}
pub fn revoke_sysname(&mut self, id: SysName)
{
let _ = self.systems.remove(&id);
}
}
impl<I, O> Default for IdMappedSystems<I, O>
where
I: Send + Sync + SystemInput + 'static,
O: Send + Sync + 'static,
{
fn default() -> Self { Self{ systems: HashMap::default() } }
}