use super::list_access::ListAccess;
use std::collections::HashMap;
pub(crate) trait ListSourceAccess<S> {
type Element: Clone + Send + Sync + 'static;
fn element_count(&self, solution: &S) -> usize;
fn index_to_element(&self, solution: &S, source_index: usize) -> Option<Self::Element>;
fn element_source_key(&self, solution: &S, element: &Self::Element) -> usize;
fn assigned_elements(&self, solution: &S) -> Vec<Self::Element>;
}
pub(crate) trait AssignedListSourceAccess<S> {
type Element: Clone + Send + Sync + 'static;
fn element_source_key(&self, solution: &S, element: &Self::Element) -> usize;
fn assigned_elements(&self, solution: &S) -> Vec<Self::Element>;
}
impl<S, A> AssignedListSourceAccess<S> for A
where
A: ListSourceAccess<S>,
{
type Element = A::Element;
fn element_source_key(&self, solution: &S, element: &Self::Element) -> usize {
ListSourceAccess::element_source_key(self, solution, element)
}
fn assigned_elements(&self, solution: &S) -> Vec<Self::Element> {
ListSourceAccess::assigned_elements(self, solution)
}
}
impl<S, A> ListSourceAccess<S> for A
where
A: ListAccess<S>,
{
type Element = A::Element;
fn element_count(&self, solution: &S) -> usize {
ListAccess::element_count(self, solution)
}
fn index_to_element(&self, solution: &S, source_index: usize) -> Option<Self::Element> {
ListAccess::index_to_element(self, solution, source_index)
}
fn element_source_key(&self, solution: &S, element: &Self::Element) -> usize {
ListAccess::element_source_key(self, solution, element)
}
fn assigned_elements(&self, solution: &S) -> Vec<Self::Element> {
ListAccess::assigned_elements(self, solution)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) enum ListConstructionKernelError {
MissingDeclaredElement {
source_index: usize,
},
DuplicateDeclaredElement {
first_source_index: usize,
duplicate_source_index: usize,
},
AssignedElementNotDeclared {
assigned_occurrence: usize,
},
DuplicateAssignedElement {
source_index: usize,
first_assigned_occurrence: usize,
duplicate_assigned_occurrence: usize,
},
}
#[derive(Debug)]
pub(crate) struct RuntimeListSourceIndex<E> {
source_index_by_key: HashMap<usize, usize>,
elements: Vec<E>,
}
pub(crate) struct RuntimeListSourceBinding<E> {
source_index: RuntimeListSourceIndex<E>,
initial_unassigned: Vec<SourceElement<E>>,
}
impl<E> RuntimeListSourceBinding<E> {
pub(crate) fn into_source_index(self) -> RuntimeListSourceIndex<E> {
self.source_index
}
pub(crate) fn into_parts(self) -> (RuntimeListSourceIndex<E>, Vec<SourceElement<E>>) {
(self.source_index, self.initial_unassigned)
}
}
impl<E> RuntimeListSourceIndex<E> {
pub(crate) fn bind<S, A>(access: &A, solution: &S) -> Result<Self, ListConstructionKernelError>
where
A: ListSourceAccess<S, Element = E>,
E: Clone + Send + Sync + 'static,
{
let source_count = access.element_count(solution);
let mut source_index_by_key = HashMap::with_capacity(source_count);
let mut elements = Vec::with_capacity(source_count);
for source_index in 0..source_count {
let element = access
.index_to_element(solution, source_index)
.ok_or(ListConstructionKernelError::MissingDeclaredElement { source_index })?;
let key = access.element_source_key(solution, &element);
if let Some(first_source_index) = source_index_by_key.insert(key, source_index) {
return Err(ListConstructionKernelError::DuplicateDeclaredElement {
first_source_index,
duplicate_source_index: source_index,
});
}
elements.push(element);
}
Ok(Self {
source_index_by_key,
elements,
})
}
pub(crate) fn source_index_for_key(&self, key: usize) -> Option<usize> {
self.source_index_by_key.get(&key).copied()
}
pub(crate) fn source_count(&self) -> usize {
self.elements.len()
}
pub(crate) fn element(&self, source_index: usize) -> &E {
&self.elements[source_index]
}
}
#[derive(Clone)]
pub(crate) struct SourceElement<E> {
pub(crate) source_index: usize,
pub(crate) element: E,
}
pub(crate) fn unassigned_from_current_assignment<S, A>(
access: &A,
source_index: &RuntimeListSourceIndex<A::Element>,
solution: &S,
) -> Result<Vec<SourceElement<A::Element>>, ListConstructionKernelError>
where
A: AssignedListSourceAccess<S>,
{
let mut assigned = vec![false; source_index.source_count()];
let mut first_assigned_occurrence = vec![None; source_index.source_count()];
for (assigned_occurrence, value) in access.assigned_elements(solution).into_iter().enumerate() {
let key = access.element_source_key(solution, &value);
let Some(resolved_source_index) = source_index.source_index_for_key(key) else {
return Err(ListConstructionKernelError::AssignedElementNotDeclared {
assigned_occurrence,
});
};
if let Some(first_assigned_occurrence) = first_assigned_occurrence[resolved_source_index] {
return Err(ListConstructionKernelError::DuplicateAssignedElement {
source_index: resolved_source_index,
first_assigned_occurrence,
duplicate_assigned_occurrence: assigned_occurrence,
});
}
first_assigned_occurrence[resolved_source_index] = Some(assigned_occurrence);
assigned[resolved_source_index] = true;
}
let mut elements = Vec::with_capacity(source_index.source_count());
for (declared_source_index, is_assigned) in assigned.into_iter().enumerate() {
if !is_assigned {
elements.push(SourceElement {
source_index: declared_source_index,
element: source_index.element(declared_source_index).clone(),
});
}
}
Ok(elements)
}
pub(crate) fn bind_runtime_list_source<S, A>(
access: &A,
solution: &S,
) -> Result<RuntimeListSourceBinding<A::Element>, ListConstructionKernelError>
where
A: ListSourceAccess<S>,
{
let source_index = RuntimeListSourceIndex::bind(access, solution)?;
let initial_unassigned = unassigned_from_current_assignment(access, &source_index, solution)?;
Ok(RuntimeListSourceBinding {
source_index,
initial_unassigned,
})
}