use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::fmt;
use super::{EntityDescriptor, ProblemFactDescriptor, VariableDescriptor};
use crate::domain::entity_ref::EntityRef;
pub struct SolutionDescriptor {
pub type_name: &'static str,
pub type_id: TypeId,
pub entity_descriptors: Vec<EntityDescriptor>,
pub problem_fact_descriptors: Vec<ProblemFactDescriptor>,
pub score_field: &'static str,
pub score_is_optional: bool,
entity_type_index: HashMap<TypeId, usize>,
}
impl SolutionDescriptor {
pub fn new(type_name: &'static str, type_id: TypeId) -> Self {
SolutionDescriptor {
type_name,
type_id,
entity_descriptors: Vec::new(),
problem_fact_descriptors: Vec::new(),
score_field: "score",
score_is_optional: true,
entity_type_index: HashMap::new(),
}
}
pub fn with_entity(mut self, descriptor: EntityDescriptor) -> Self {
let index = self.entity_descriptors.len();
let type_id = descriptor.type_id;
self.entity_descriptors.push(descriptor);
self.entity_type_index.insert(type_id, index);
self
}
pub fn with_problem_fact(mut self, descriptor: ProblemFactDescriptor) -> Self {
self.problem_fact_descriptors.push(descriptor);
self
}
pub fn with_score_field(mut self, field: &'static str) -> Self {
self.score_field = field;
self
}
pub fn find_entity_descriptor(&self, type_name: &str) -> Option<&EntityDescriptor> {
self.entity_descriptors
.iter()
.find(|d| d.type_name == type_name)
}
pub fn find_entity_descriptor_by_type(&self, type_id: TypeId) -> Option<&EntityDescriptor> {
self.entity_type_index
.get(&type_id)
.and_then(|&idx| self.entity_descriptors.get(idx))
}
pub fn genuine_variable_descriptors(&self) -> Vec<&VariableDescriptor> {
self.entity_descriptors
.iter()
.flat_map(|e| e.genuine_variable_descriptors())
.collect()
}
pub fn shadow_variable_descriptors(&self) -> Vec<&VariableDescriptor> {
self.entity_descriptors
.iter()
.flat_map(|e| e.shadow_variable_descriptors())
.collect()
}
pub fn total_entity_count(&self, solution: &dyn Any) -> Option<usize> {
let mut total = 0;
for desc in &self.entity_descriptors {
total += desc.entity_count(solution)?;
}
Some(total)
}
pub fn all_entity_refs(&self, solution: &dyn Any) -> Vec<(usize, EntityRef)> {
let mut refs = Vec::new();
for (desc_idx, desc) in self.entity_descriptors.iter().enumerate() {
for entity_ref in desc.entity_refs(solution) {
refs.push((desc_idx, entity_ref));
}
}
refs
}
pub fn for_each_entity<F>(&self, solution: &dyn Any, mut f: F)
where
F: FnMut(usize, usize, &dyn Any),
{
for (desc_idx, desc) in self.entity_descriptors.iter().enumerate() {
desc.for_each_entity(solution, |entity_idx, entity| {
f(desc_idx, entity_idx, entity);
});
}
}
pub fn get_entity<'a>(
&self,
solution: &'a dyn Any,
descriptor_index: usize,
entity_index: usize,
) -> Option<&'a dyn Any> {
self.entity_descriptors
.get(descriptor_index)?
.get_entity(solution, entity_index)
}
pub fn get_entity_mut<'a>(
&self,
solution: &'a mut dyn Any,
descriptor_index: usize,
entity_index: usize,
) -> Option<&'a mut dyn Any> {
self.entity_descriptors
.get(descriptor_index)?
.get_entity_mut(solution, entity_index)
}
pub fn entity_descriptor_count(&self) -> usize {
self.entity_descriptors.len()
}
pub fn problem_fact_descriptor_count(&self) -> usize {
self.problem_fact_descriptors.len()
}
pub fn all_extractors_configured(&self) -> bool {
self.entity_descriptors.iter().all(|d| d.has_extractor())
}
}
impl Clone for SolutionDescriptor {
fn clone(&self) -> Self {
Self {
type_name: self.type_name,
type_id: self.type_id,
entity_descriptors: self.entity_descriptors.clone(),
problem_fact_descriptors: self.problem_fact_descriptors.clone(),
score_field: self.score_field,
score_is_optional: self.score_is_optional,
entity_type_index: self.entity_type_index.clone(),
}
}
}
impl fmt::Debug for SolutionDescriptor {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SolutionDescriptor")
.field("type_name", &self.type_name)
.field("entities", &self.entity_descriptors.len())
.field("problem_facts", &self.problem_fact_descriptors.len())
.finish()
}
}