use std::any::Any;
use std::fmt::Debug;
#[derive(Debug, Clone)]
pub struct EntityRef {
pub index: usize,
pub type_name: &'static str,
pub collection_field: &'static str,
}
impl EntityRef {
pub fn new(index: usize, type_name: &'static str, collection_field: &'static str) -> Self {
Self {
index,
type_name,
collection_field,
}
}
}
pub trait EntityExtractor: Send + Sync {
fn count(&self, solution: &dyn Any) -> Option<usize>;
fn get<'a>(&self, solution: &'a dyn Any, index: usize) -> Option<&'a dyn Any>;
fn get_mut<'a>(&self, solution: &'a mut dyn Any, index: usize) -> Option<&'a mut dyn Any>;
fn entity_refs(&self, solution: &dyn Any) -> Vec<EntityRef>;
fn clone_box(&self) -> Box<dyn EntityExtractor>;
fn clone_entity_boxed(
&self,
solution: &dyn Any,
index: usize,
) -> Option<Box<dyn Any + Send + Sync>>;
fn entity_type_id(&self) -> std::any::TypeId;
}
impl Clone for Box<dyn EntityExtractor> {
fn clone(&self) -> Self {
self.clone_box()
}
}
pub struct EntityCollectionExtractor<S, E> {
type_name: &'static str,
collection_field: &'static str,
get_collection: fn(&S) -> &Vec<E>,
get_collection_mut: fn(&mut S) -> &mut Vec<E>,
}
impl<S, E> EntityCollectionExtractor<S, E>
where
S: 'static,
E: 'static,
{
pub fn new(
type_name: &'static str,
collection_field: &'static str,
get_collection: fn(&S) -> &Vec<E>,
get_collection_mut: fn(&mut S) -> &mut Vec<E>,
) -> Self {
Self {
type_name,
collection_field,
get_collection,
get_collection_mut,
}
}
}
impl<S, E> EntityExtractor for EntityCollectionExtractor<S, E>
where
S: Send + Sync + 'static,
E: Clone + Send + Sync + 'static,
{
fn count(&self, solution: &dyn Any) -> Option<usize> {
let solution = solution.downcast_ref::<S>()?;
Some((self.get_collection)(solution).len())
}
fn get<'a>(&self, solution: &'a dyn Any, index: usize) -> Option<&'a dyn Any> {
let solution = solution.downcast_ref::<S>()?;
let collection = (self.get_collection)(solution);
collection.get(index).map(|e| e as &dyn Any)
}
fn get_mut<'a>(&self, solution: &'a mut dyn Any, index: usize) -> Option<&'a mut dyn Any> {
let solution = solution.downcast_mut::<S>()?;
let collection = (self.get_collection_mut)(solution);
collection.get_mut(index).map(|e| e as &mut dyn Any)
}
fn entity_refs(&self, solution: &dyn Any) -> Vec<EntityRef> {
let Some(solution) = solution.downcast_ref::<S>() else {
return Vec::new();
};
let collection = (self.get_collection)(solution);
(0..collection.len())
.map(|i| EntityRef::new(i, self.type_name, self.collection_field))
.collect()
}
fn clone_box(&self) -> Box<dyn EntityExtractor> {
Box::new(Self {
type_name: self.type_name,
collection_field: self.collection_field,
get_collection: self.get_collection,
get_collection_mut: self.get_collection_mut,
})
}
fn clone_entity_boxed(
&self,
solution: &dyn Any,
index: usize,
) -> Option<Box<dyn Any + Send + Sync>> {
let solution = solution.downcast_ref::<S>()?;
let collection = (self.get_collection)(solution);
let entity = collection.get(index)?;
Some(Box::new(entity.clone()) as Box<dyn Any + Send + Sync>)
}
fn entity_type_id(&self) -> std::any::TypeId {
std::any::TypeId::of::<E>()
}
}
impl<S, E> Debug for EntityCollectionExtractor<S, E> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("EntityCollectionExtractor")
.field("type_name", &self.type_name)
.field("collection_field", &self.collection_field)
.finish()
}
}