1use std::fmt;
2
3use crate::planning::{
4 ScalarAssignmentDeclaration, ScalarCandidateProvider, ScalarEdit, ScalarGroup, ScalarGroupKind,
5 ScalarGroupLimits,
6};
7
8use super::value_source::ValueSource;
9use super::variable::{ScalarGetter, ScalarSetter, ScalarVariableSlot};
10
11pub struct ScalarGroupMemberBinding<S> {
12 pub descriptor_index: usize,
13 pub variable_index: usize,
14 pub entity_type_name: &'static str,
15 pub variable_name: &'static str,
16 pub getter: ScalarGetter<S>,
17 pub setter: ScalarSetter<S>,
18 pub value_source: ValueSource<S>,
19 pub entity_count: fn(&S) -> usize,
20 pub candidate_values: Option<super::variable::ScalarCandidateValues<S>>,
21 pub allows_unassigned: bool,
22}
23
24impl<S> Clone for ScalarGroupMemberBinding<S> {
25 fn clone(&self) -> Self {
26 *self
27 }
28}
29
30impl<S> Copy for ScalarGroupMemberBinding<S> {}
31
32impl<S> ScalarGroupMemberBinding<S> {
33 pub fn from_scalar_slot(slot: ScalarVariableSlot<S>) -> Self {
34 Self {
35 descriptor_index: slot.descriptor_index,
36 variable_index: slot.variable_index,
37 entity_type_name: slot.entity_type_name,
38 variable_name: slot.variable_name,
39 getter: slot.getter,
40 setter: slot.setter,
41 value_source: slot.value_source,
42 entity_count: slot.entity_count,
43 candidate_values: slot.candidate_values,
44 allows_unassigned: slot.allows_unassigned,
45 }
46 }
47
48 pub fn current_value(&self, solution: &S, entity_index: usize) -> Option<usize> {
49 (self.getter)(solution, entity_index, self.variable_index)
50 }
51
52 pub fn value_is_legal(
53 &self,
54 solution: &S,
55 entity_index: usize,
56 candidate: Option<usize>,
57 ) -> bool {
58 let Some(value) = candidate else {
59 return self.allows_unassigned;
60 };
61 match self.value_source {
62 ValueSource::Empty => false,
63 ValueSource::CountableRange { from, to } => from <= value && value < to,
64 ValueSource::SolutionCount {
65 count_fn,
66 provider_index,
67 } => value < count_fn(solution, provider_index),
68 ValueSource::EntitySlice { values_for_entity } => {
69 values_for_entity(solution, entity_index, self.variable_index).contains(&value)
70 }
71 }
72 }
73
74 pub fn entity_count(&self, solution: &S) -> usize {
75 (self.entity_count)(solution)
76 }
77
78 pub fn candidate_values(
79 &self,
80 solution: &S,
81 entity_index: usize,
82 value_candidate_limit: Option<usize>,
83 ) -> Vec<usize> {
84 if let Some(candidate_values) = self.candidate_values {
85 let values = candidate_values(solution, entity_index, self.variable_index);
86 return match value_candidate_limit {
87 Some(limit) => values.iter().copied().take(limit).collect(),
88 None => values.to_vec(),
89 };
90 }
91 match self.value_source {
92 ValueSource::Empty => Vec::new(),
93 ValueSource::CountableRange { from, to } => {
94 let end = value_candidate_limit
95 .map(|limit| from.saturating_add(limit).min(to))
96 .unwrap_or(to);
97 (from..end).collect()
98 }
99 ValueSource::SolutionCount {
100 count_fn,
101 provider_index,
102 } => {
103 let count = count_fn(solution, provider_index);
104 let end = value_candidate_limit
105 .map(|limit| limit.min(count))
106 .unwrap_or(count);
107 (0..end).collect()
108 }
109 ValueSource::EntitySlice { values_for_entity } => {
110 let values = values_for_entity(solution, entity_index, self.variable_index);
111 match value_candidate_limit {
112 Some(limit) => values.iter().copied().take(limit).collect(),
113 None => values.to_vec(),
114 }
115 }
116 }
117 }
118}
119
120impl<S> fmt::Debug for ScalarGroupMemberBinding<S> {
121 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122 f.debug_struct("ScalarGroupMemberBinding")
123 .field("descriptor_index", &self.descriptor_index)
124 .field("variable_index", &self.variable_index)
125 .field("entity_type_name", &self.entity_type_name)
126 .field("variable_name", &self.variable_name)
127 .field("value_source", &self.value_source)
128 .field("allows_unassigned", &self.allows_unassigned)
129 .finish()
130 }
131}
132
133pub struct ScalarGroupBinding<S> {
134 pub group_name: &'static str,
135 pub members: Vec<ScalarGroupMemberBinding<S>>,
136 pub kind: ScalarGroupBindingKind<S>,
137 pub limits: ScalarGroupLimits,
138}
139
140pub enum ScalarGroupBindingKind<S> {
141 Candidates {
142 candidate_provider: ScalarCandidateProvider<S>,
143 },
144 Assignment(ScalarAssignmentBinding<S>),
145}
146
147impl<S> Clone for ScalarGroupBindingKind<S> {
148 fn clone(&self) -> Self {
149 *self
150 }
151}
152
153impl<S> Copy for ScalarGroupBindingKind<S> {}
154
155pub struct ScalarAssignmentBinding<S> {
156 pub target: ScalarGroupMemberBinding<S>,
157 pub required_entity: Option<fn(&S, usize) -> bool>,
158 pub capacity_key: Option<fn(&S, usize, usize) -> Option<usize>>,
159 pub position_key: Option<fn(&S, usize) -> i64>,
160 pub sequence_key: Option<fn(&S, usize, usize) -> Option<usize>>,
161 pub entity_order: Option<fn(&S, usize) -> i64>,
162 pub value_order: Option<fn(&S, usize, usize) -> i64>,
163}
164
165impl<S> Clone for ScalarAssignmentBinding<S> {
166 fn clone(&self) -> Self {
167 *self
168 }
169}
170
171impl<S> Copy for ScalarAssignmentBinding<S> {}
172
173impl<S> ScalarAssignmentBinding<S> {
174 fn bind(
175 group_name: &'static str,
176 members: &[ScalarGroupMemberBinding<S>],
177 declaration: ScalarAssignmentDeclaration<S>,
178 ) -> Self {
179 assert_eq!(
180 members.len(),
181 1,
182 "assignment scalar group `{group_name}` must target exactly one scalar planning variable",
183 );
184 let target = members[0];
185 assert!(
186 target.allows_unassigned,
187 "assignment scalar group `{group_name}` target {}.{} must allow unassigned values",
188 target.entity_type_name, target.variable_name,
189 );
190 Self {
191 target,
192 required_entity: declaration.required_entity,
193 capacity_key: declaration.capacity_key,
194 position_key: declaration.position_key,
195 sequence_key: declaration.sequence_key,
196 entity_order: declaration.entity_order,
197 value_order: declaration.value_order,
198 }
199 }
200
201 pub fn entity_count(&self, solution: &S) -> usize {
202 self.target.entity_count(solution)
203 }
204
205 pub fn current_value(&self, solution: &S, entity_index: usize) -> Option<usize> {
206 self.target.current_value(solution, entity_index)
207 }
208
209 pub fn is_required(&self, solution: &S, entity_index: usize) -> bool {
210 self.required_entity
211 .map(|required_entity| required_entity(solution, entity_index))
212 .unwrap_or(false)
213 }
214
215 pub fn capacity_key(&self, solution: &S, entity_index: usize, value: usize) -> Option<usize> {
216 self.capacity_key
217 .and_then(|capacity_key| capacity_key(solution, entity_index, value))
218 }
219
220 pub fn position_key(&self, solution: &S, entity_index: usize) -> Option<i64> {
221 self.position_key
222 .map(|position_key| position_key(solution, entity_index))
223 }
224
225 pub fn sequence_key(&self, solution: &S, entity_index: usize, value: usize) -> Option<usize> {
226 self.sequence_key
227 .and_then(|sequence_key| sequence_key(solution, entity_index, value))
228 }
229
230 pub fn entity_order_key(&self, solution: &S, entity_index: usize) -> Option<i64> {
231 self.entity_order
232 .map(|entity_order| entity_order(solution, entity_index))
233 }
234
235 pub fn value_order_key(&self, solution: &S, entity_index: usize, value: usize) -> Option<i64> {
236 self.value_order
237 .map(|value_order| value_order(solution, entity_index, value))
238 }
239
240 pub fn candidate_values(
241 &self,
242 solution: &S,
243 entity_index: usize,
244 value_candidate_limit: Option<usize>,
245 ) -> Vec<usize> {
246 let mut values =
247 self.target
248 .candidate_values(solution, entity_index, value_candidate_limit);
249 values.sort_by_key(|value| (self.value_order_key(solution, entity_index, *value), *value));
250 values
251 }
252
253 pub fn value_is_legal(&self, solution: &S, entity_index: usize, value: Option<usize>) -> bool {
254 self.target.value_is_legal(solution, entity_index, value)
255 }
256
257 pub fn edit(&self, entity_index: usize, value: Option<usize>) -> ScalarEdit<S> {
258 ScalarEdit::from_descriptor_index(
259 self.target.descriptor_index,
260 entity_index,
261 self.target.variable_name,
262 value,
263 )
264 }
265}
266
267impl<S> ScalarGroupBinding<S> {
268 pub fn bind(group: ScalarGroup<S>, scalar_slots: &[ScalarVariableSlot<S>]) -> Self {
269 let members = group
270 .targets()
271 .iter()
272 .map(|target| {
273 let descriptor_index = target.descriptor_index();
274 let variable_name = target.variable_name();
275 let slot = scalar_slots
276 .iter()
277 .copied()
278 .find(|slot| {
279 slot.descriptor_index == descriptor_index
280 && slot.variable_name == variable_name
281 })
282 .unwrap_or_else(|| {
283 panic!(
284 "scalar group `{}` targets unknown scalar variable `{}` on descriptor {}",
285 group.group_name(),
286 variable_name,
287 descriptor_index
288 )
289 });
290 ScalarGroupMemberBinding::from_scalar_slot(slot)
291 })
292 .collect::<Vec<_>>();
293
294 let kind = match group.kind() {
295 ScalarGroupKind::Assignment(declaration) => ScalarGroupBindingKind::Assignment(
296 ScalarAssignmentBinding::bind(group.group_name(), &members, declaration),
297 ),
298 ScalarGroupKind::Candidates { candidate_provider } => {
299 ScalarGroupBindingKind::Candidates { candidate_provider }
300 }
301 };
302
303 Self {
304 group_name: group.group_name(),
305 members,
306 kind,
307 limits: group.limits(),
308 }
309 }
310
311 pub fn member_for_edit(&self, edit: &ScalarEdit<S>) -> Option<ScalarGroupMemberBinding<S>> {
312 self.members.iter().copied().find(|member| {
313 member.descriptor_index == edit.descriptor_index()
314 && member.variable_name == edit.variable_name()
315 })
316 }
317}
318
319impl<S> Clone for ScalarGroupBinding<S> {
320 fn clone(&self) -> Self {
321 Self {
322 group_name: self.group_name,
323 members: self.members.clone(),
324 kind: self.kind,
325 limits: self.limits,
326 }
327 }
328}
329
330impl<S> fmt::Debug for ScalarGroupBinding<S> {
331 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
332 f.debug_struct("ScalarGroupBinding")
333 .field("group_name", &self.group_name)
334 .field("members", &self.members)
335 .finish_non_exhaustive()
336 }
337}
338
339pub fn bind_scalar_groups<S>(
340 groups: Vec<ScalarGroup<S>>,
341 scalar_slots: &[ScalarVariableSlot<S>],
342) -> Vec<ScalarGroupBinding<S>> {
343 groups
344 .into_iter()
345 .map(|group| ScalarGroupBinding::bind(group, scalar_slots))
346 .collect()
347}