use bevy_ecs::prelude::{Commands, Component, Entity, World};
use std::{
any::TypeId,
borrow::Cow,
collections::{HashMap, hash_map::Entry},
};
use crate::{DuplicateStream, NamedTarget, NamedValue, UnhandledErrors};
#[derive(Component, Default, Clone, Debug)]
pub struct StreamTargetMap {
pub(crate) anonymous: HashMap<TypeId, Entity>,
pub(crate) named: HashMap<Cow<'static, str>, (TypeId, Entity)>,
}
impl StreamTargetMap {
pub fn add_anonymous<T: 'static + Send + Sync>(
&mut self,
target: Entity,
commands: &mut Commands,
) {
match self.anonymous.entry(TypeId::of::<T>()) {
Entry::Vacant(vacant) => {
vacant.insert(target);
}
Entry::Occupied(_) => {
commands.queue(move |world: &mut World| {
world
.get_resource_or_insert_with(|| UnhandledErrors::default())
.duplicate_streams
.push(DuplicateStream {
target,
type_name: std::any::type_name::<T>(),
stream_name: None,
})
});
}
}
}
pub fn add_named<T: 'static + Send + Sync>(
&mut self,
name: Cow<'static, str>,
target: Entity,
commands: &mut Commands,
) {
match self.named.entry(name.clone()) {
Entry::Vacant(vacant) => {
vacant.insert((TypeId::of::<T>(), target));
}
Entry::Occupied(_) => {
commands.queue(move |world: &mut World| {
world
.get_resource_or_insert_with(|| UnhandledErrors::default())
.duplicate_streams
.push(DuplicateStream {
target,
type_name: std::any::type_name::<T>(),
stream_name: Some(name.clone()),
});
});
}
}
}
pub fn anonymous(&self) -> &HashMap<TypeId, Entity> {
&self.anonymous
}
pub fn get_anonymous<T: 'static + Send + Sync>(&self) -> Option<Entity> {
self.anonymous.get(&TypeId::of::<T>()).copied()
}
pub fn get_named<T: 'static + Send + Sync>(&self, name: &str) -> Option<Entity> {
let target_type = TypeId::of::<T>();
self.named
.get(name)
.filter(|(ty, _)| *ty == target_type)
.map(|(_, target)| *target)
}
pub fn get_named_or_anonymous<T: 'static + Send + Sync>(
&self,
name: &str,
) -> Option<NamedTarget> {
self.get_named::<T>(name)
.map(NamedTarget::Value)
.or_else(|| {
self.get_anonymous::<NamedValue<T>>()
.map(NamedTarget::NamedValue)
})
.or_else(|| self.get_anonymous::<T>().map(NamedTarget::Value))
}
}