solverforge_solver/builder/context/scalar/
group.rs1use std::fmt;
2
3use crate::planning::{ScalarCandidateProvider, ScalarEdit, ScalarGroup};
4
5use super::value_source::ValueSource;
6use super::variable::{ScalarGetter, ScalarSetter, ScalarVariableSlot};
7
8pub struct ScalarGroupMemberBinding<S> {
9 pub descriptor_index: usize,
10 pub variable_index: usize,
11 pub entity_type_name: &'static str,
12 pub variable_name: &'static str,
13 pub getter: ScalarGetter<S>,
14 pub setter: ScalarSetter<S>,
15 pub value_source: ValueSource<S>,
16 pub allows_unassigned: bool,
17}
18
19impl<S> Clone for ScalarGroupMemberBinding<S> {
20 fn clone(&self) -> Self {
21 *self
22 }
23}
24
25impl<S> Copy for ScalarGroupMemberBinding<S> {}
26
27impl<S> ScalarGroupMemberBinding<S> {
28 pub fn from_scalar_slot(slot: ScalarVariableSlot<S>) -> Self {
29 Self {
30 descriptor_index: slot.descriptor_index,
31 variable_index: slot.variable_index,
32 entity_type_name: slot.entity_type_name,
33 variable_name: slot.variable_name,
34 getter: slot.getter,
35 setter: slot.setter,
36 value_source: slot.value_source,
37 allows_unassigned: slot.allows_unassigned,
38 }
39 }
40
41 pub fn current_value(&self, solution: &S, entity_index: usize) -> Option<usize> {
42 (self.getter)(solution, entity_index, self.variable_index)
43 }
44
45 pub fn value_is_legal(
46 &self,
47 solution: &S,
48 entity_index: usize,
49 candidate: Option<usize>,
50 ) -> bool {
51 let Some(value) = candidate else {
52 return self.allows_unassigned;
53 };
54 match self.value_source {
55 ValueSource::Empty => false,
56 ValueSource::CountableRange { from, to } => from <= value && value < to,
57 ValueSource::SolutionCount {
58 count_fn,
59 provider_index,
60 } => value < count_fn(solution, provider_index),
61 ValueSource::EntitySlice { values_for_entity } => {
62 values_for_entity(solution, entity_index, self.variable_index).contains(&value)
63 }
64 }
65 }
66}
67
68impl<S> fmt::Debug for ScalarGroupMemberBinding<S> {
69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70 f.debug_struct("ScalarGroupMemberBinding")
71 .field("descriptor_index", &self.descriptor_index)
72 .field("variable_index", &self.variable_index)
73 .field("entity_type_name", &self.entity_type_name)
74 .field("variable_name", &self.variable_name)
75 .field("value_source", &self.value_source)
76 .field("allows_unassigned", &self.allows_unassigned)
77 .finish()
78 }
79}
80
81pub struct ScalarGroupBinding<S> {
82 pub group_name: &'static str,
83 pub members: Vec<ScalarGroupMemberBinding<S>>,
84 pub candidate_provider: ScalarCandidateProvider<S>,
85}
86
87impl<S> ScalarGroupBinding<S> {
88 pub fn bind(group: ScalarGroup<S>, scalar_slots: &[ScalarVariableSlot<S>]) -> Self {
89 let members = group
90 .targets()
91 .iter()
92 .map(|target| {
93 let descriptor_index = target.descriptor_index();
94 let variable_name = target.variable_name();
95 let slot = scalar_slots
96 .iter()
97 .copied()
98 .find(|slot| {
99 slot.descriptor_index == descriptor_index
100 && slot.variable_name == variable_name
101 })
102 .unwrap_or_else(|| {
103 panic!(
104 "scalar group `{}` targets unknown scalar variable `{}` on descriptor {}",
105 group.group_name(),
106 variable_name,
107 descriptor_index
108 )
109 });
110 ScalarGroupMemberBinding::from_scalar_slot(slot)
111 })
112 .collect();
113
114 Self {
115 group_name: group.group_name(),
116 members,
117 candidate_provider: group.candidate_provider(),
118 }
119 }
120
121 pub fn member_for_edit(&self, edit: &ScalarEdit<S>) -> Option<ScalarGroupMemberBinding<S>> {
122 self.members.iter().copied().find(|member| {
123 member.descriptor_index == edit.descriptor_index()
124 && member.variable_name == edit.variable_name()
125 })
126 }
127}
128
129impl<S> Clone for ScalarGroupBinding<S> {
130 fn clone(&self) -> Self {
131 Self {
132 group_name: self.group_name,
133 members: self.members.clone(),
134 candidate_provider: self.candidate_provider,
135 }
136 }
137}
138
139impl<S> fmt::Debug for ScalarGroupBinding<S> {
140 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141 f.debug_struct("ScalarGroupBinding")
142 .field("group_name", &self.group_name)
143 .field("members", &self.members)
144 .finish_non_exhaustive()
145 }
146}
147
148pub fn bind_scalar_groups<S>(
149 groups: Vec<ScalarGroup<S>>,
150 scalar_slots: &[ScalarVariableSlot<S>],
151) -> Vec<ScalarGroupBinding<S>> {
152 groups
153 .into_iter()
154 .map(|group| ScalarGroupBinding::bind(group, scalar_slots))
155 .collect()
156}