use std::fmt::Debug;
use std::marker::PhantomData;
use solverforge_core::domain::PlanningSolution;
use solverforge_scoring::Director;
pub trait ValueSelector<S: PlanningSolution, V>: Send + Debug {
fn iter_typed<'a, D: Director<S>>(
&'a self,
score_director: &'a D,
descriptor_index: usize,
entity_index: usize,
) -> impl Iterator<Item = V> + 'a;
fn size<D: Director<S>>(
&self,
score_director: &D,
descriptor_index: usize,
entity_index: usize,
) -> usize;
fn is_never_ending(&self) -> bool {
false
}
}
pub struct StaticValueSelector<S, V> {
values: Vec<V>,
_phantom: PhantomData<fn() -> S>,
}
impl<S, V: Clone> Clone for StaticValueSelector<S, V> {
fn clone(&self) -> Self {
Self {
values: self.values.clone(),
_phantom: PhantomData,
}
}
}
impl<S, V: Debug> Debug for StaticValueSelector<S, V> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("StaticValueSelector")
.field("values", &self.values)
.finish()
}
}
impl<S, V: Clone> StaticValueSelector<S, V> {
pub fn new(values: Vec<V>) -> Self {
Self {
values,
_phantom: PhantomData,
}
}
pub fn values(&self) -> &[V] {
&self.values
}
}
impl<S, V> ValueSelector<S, V> for StaticValueSelector<S, V>
where
S: PlanningSolution,
V: Clone + Send + Debug + 'static,
{
fn iter_typed<'a, D: Director<S>>(
&'a self,
_score_director: &'a D,
_descriptor_index: usize,
_entity_index: usize,
) -> impl Iterator<Item = V> + 'a {
self.values.iter().cloned()
}
fn size<D: Director<S>>(
&self,
_score_director: &D,
_descriptor_index: usize,
_entity_index: usize,
) -> usize {
self.values.len()
}
}
pub struct FromSolutionValueSelector<S, V> {
extractor: fn(&S) -> Vec<V>,
_phantom: PhantomData<(fn() -> S, fn() -> V)>,
}
impl<S, V> Debug for FromSolutionValueSelector<S, V> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("FromSolutionValueSelector").finish()
}
}
impl<S, V> FromSolutionValueSelector<S, V> {
pub fn new(extractor: fn(&S) -> Vec<V>) -> Self {
Self {
extractor,
_phantom: PhantomData,
}
}
}
pub struct PerEntityValueSelector<S, V> {
extractor: fn(&S, usize) -> Vec<V>,
_phantom: PhantomData<(fn() -> S, fn() -> V)>,
}
impl<S, V> Debug for PerEntityValueSelector<S, V> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PerEntityValueSelector").finish()
}
}
impl<S, V> PerEntityValueSelector<S, V> {
pub fn new(extractor: fn(&S, usize) -> Vec<V>) -> Self {
Self {
extractor,
_phantom: PhantomData,
}
}
}
impl<S, V> ValueSelector<S, V> for PerEntityValueSelector<S, V>
where
S: PlanningSolution,
V: Clone + Send + Debug + 'static,
{
fn iter_typed<'a, D: Director<S>>(
&'a self,
score_director: &'a D,
_descriptor_index: usize,
entity_index: usize,
) -> impl Iterator<Item = V> + 'a {
(self.extractor)(score_director.working_solution(), entity_index).into_iter()
}
fn size<D: Director<S>>(
&self,
score_director: &D,
_descriptor_index: usize,
entity_index: usize,
) -> usize {
(self.extractor)(score_director.working_solution(), entity_index).len()
}
}
impl<S, V> ValueSelector<S, V> for FromSolutionValueSelector<S, V>
where
S: PlanningSolution,
V: Clone + Send + Debug + 'static,
{
fn iter_typed<'a, D: Director<S>>(
&'a self,
score_director: &'a D,
_descriptor_index: usize,
_entity_index: usize,
) -> impl Iterator<Item = V> + 'a {
let values = (self.extractor)(score_director.working_solution());
values.into_iter()
}
fn size<D: Director<S>>(
&self,
score_director: &D,
_descriptor_index: usize,
_entity_index: usize,
) -> usize {
(self.extractor)(score_director.working_solution()).len()
}
}
pub struct RangeValueSelector<S> {
count_fn: fn(&S) -> usize,
_phantom: PhantomData<fn() -> S>,
}
impl<S> Debug for RangeValueSelector<S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("RangeValueSelector").finish()
}
}
impl<S> RangeValueSelector<S> {
pub fn new(count_fn: fn(&S) -> usize) -> Self {
Self {
count_fn,
_phantom: PhantomData,
}
}
}
impl<S> ValueSelector<S, usize> for RangeValueSelector<S>
where
S: PlanningSolution,
{
fn iter_typed<'a, D: Director<S>>(
&'a self,
score_director: &'a D,
_descriptor_index: usize,
_entity_index: usize,
) -> impl Iterator<Item = usize> + 'a {
let count = (self.count_fn)(score_director.working_solution());
0..count
}
fn size<D: Director<S>>(
&self,
score_director: &D,
_descriptor_index: usize,
_entity_index: usize,
) -> usize {
(self.count_fn)(score_director.working_solution())
}
}
#[cfg(test)]
#[path = "value_selector_tests.rs"]
mod tests;