solverforge_solver/planning/
scalar.rs1use std::marker::PhantomData;
2
3#[derive(Debug)]
4pub struct ScalarTarget<S> {
5 descriptor_index: usize,
6 variable_name: &'static str,
7 _phantom: PhantomData<fn() -> S>,
8}
9
10impl<S> Clone for ScalarTarget<S> {
11 fn clone(&self) -> Self {
12 *self
13 }
14}
15
16impl<S> Copy for ScalarTarget<S> {}
17
18impl<S> PartialEq for ScalarTarget<S> {
19 fn eq(&self, other: &Self) -> bool {
20 self.descriptor_index == other.descriptor_index && self.variable_name == other.variable_name
21 }
22}
23
24impl<S> Eq for ScalarTarget<S> {}
25
26impl<S> std::hash::Hash for ScalarTarget<S> {
27 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
28 self.descriptor_index.hash(state);
29 self.variable_name.hash(state);
30 }
31}
32
33impl<S> ScalarTarget<S> {
34 #[doc(hidden)]
35 pub const fn from_descriptor_index(
36 descriptor_index: usize,
37 variable_name: &'static str,
38 ) -> Self {
39 Self {
40 descriptor_index,
41 variable_name,
42 _phantom: PhantomData,
43 }
44 }
45
46 #[inline]
47 pub fn set(self, entity_index: usize, to_value: Option<usize>) -> ScalarEdit<S> {
48 ScalarEdit {
49 descriptor_index: self.descriptor_index,
50 entity_index,
51 variable_name: self.variable_name,
52 to_value,
53 _phantom: PhantomData,
54 }
55 }
56
57 #[doc(hidden)]
58 #[inline]
59 pub fn descriptor_index(self) -> usize {
60 self.descriptor_index
61 }
62
63 #[doc(hidden)]
64 #[inline]
65 pub fn variable_name(self) -> &'static str {
66 self.variable_name
67 }
68}
69
70#[derive(Debug)]
71pub struct ScalarEdit<S> {
72 descriptor_index: usize,
73 entity_index: usize,
74 variable_name: &'static str,
75 to_value: Option<usize>,
76 _phantom: PhantomData<fn() -> S>,
77}
78
79impl<S> Clone for ScalarEdit<S> {
80 fn clone(&self) -> Self {
81 *self
82 }
83}
84
85impl<S> Copy for ScalarEdit<S> {}
86
87impl<S> PartialEq for ScalarEdit<S> {
88 fn eq(&self, other: &Self) -> bool {
89 self.descriptor_index == other.descriptor_index
90 && self.entity_index == other.entity_index
91 && self.variable_name == other.variable_name
92 && self.to_value == other.to_value
93 }
94}
95
96impl<S> Eq for ScalarEdit<S> {}
97
98impl<S> std::hash::Hash for ScalarEdit<S> {
99 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
100 self.descriptor_index.hash(state);
101 self.entity_index.hash(state);
102 self.variable_name.hash(state);
103 self.to_value.hash(state);
104 }
105}
106
107impl<S> ScalarEdit<S> {
108 #[doc(hidden)]
109 pub const fn from_descriptor_index(
110 descriptor_index: usize,
111 entity_index: usize,
112 variable_name: &'static str,
113 to_value: Option<usize>,
114 ) -> Self {
115 Self {
116 descriptor_index,
117 entity_index,
118 variable_name,
119 to_value,
120 _phantom: PhantomData,
121 }
122 }
123
124 #[doc(hidden)]
125 #[inline]
126 pub fn descriptor_index(&self) -> usize {
127 self.descriptor_index
128 }
129
130 #[doc(hidden)]
131 #[inline]
132 pub fn entity_index(&self) -> usize {
133 self.entity_index
134 }
135
136 #[doc(hidden)]
137 #[inline]
138 pub fn variable_name(&self) -> &'static str {
139 self.variable_name
140 }
141
142 #[doc(hidden)]
143 #[inline]
144 pub fn to_value(&self) -> Option<usize> {
145 self.to_value
146 }
147}
148
149#[derive(Debug)]
150pub struct ScalarCandidate<S> {
151 reason: &'static str,
152 edits: Vec<ScalarEdit<S>>,
153 construction_slot_key: Option<usize>,
154 construction_entity_order_key: Option<i64>,
155 construction_value_order_key: Option<i64>,
156}
157
158impl<S> Clone for ScalarCandidate<S> {
159 fn clone(&self) -> Self {
160 Self {
161 reason: self.reason,
162 edits: self.edits.clone(),
163 construction_slot_key: self.construction_slot_key,
164 construction_entity_order_key: self.construction_entity_order_key,
165 construction_value_order_key: self.construction_value_order_key,
166 }
167 }
168}
169
170impl<S> PartialEq for ScalarCandidate<S> {
171 fn eq(&self, other: &Self) -> bool {
172 self.reason == other.reason
173 && self.edits == other.edits
174 && self.construction_slot_key == other.construction_slot_key
175 && self.construction_entity_order_key == other.construction_entity_order_key
176 && self.construction_value_order_key == other.construction_value_order_key
177 }
178}
179
180impl<S> Eq for ScalarCandidate<S> {}
181
182impl<S> std::hash::Hash for ScalarCandidate<S> {
183 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
184 self.reason.hash(state);
185 self.edits.hash(state);
186 self.construction_slot_key.hash(state);
187 self.construction_entity_order_key.hash(state);
188 self.construction_value_order_key.hash(state);
189 }
190}
191
192impl<S> ScalarCandidate<S> {
193 pub fn new(reason: &'static str, edits: Vec<ScalarEdit<S>>) -> Self {
194 Self {
195 reason,
196 edits,
197 construction_slot_key: None,
198 construction_entity_order_key: None,
199 construction_value_order_key: None,
200 }
201 }
202
203 pub fn with_construction_slot_key(mut self, key: usize) -> Self {
204 self.construction_slot_key = Some(key);
205 self
206 }
207
208 pub fn with_construction_entity_order_key(mut self, key: i64) -> Self {
209 self.construction_entity_order_key = Some(key);
210 self
211 }
212
213 pub fn with_construction_value_order_key(mut self, key: i64) -> Self {
214 self.construction_value_order_key = Some(key);
215 self
216 }
217
218 #[doc(hidden)]
219 #[inline]
220 pub fn reason(&self) -> &'static str {
221 self.reason
222 }
223
224 #[doc(hidden)]
225 #[inline]
226 pub fn edits(&self) -> &[ScalarEdit<S>] {
227 &self.edits
228 }
229
230 #[doc(hidden)]
231 #[inline]
232 pub fn into_edits(self) -> Vec<ScalarEdit<S>> {
233 self.edits
234 }
235
236 #[doc(hidden)]
237 #[inline]
238 pub fn construction_slot_key(&self) -> Option<usize> {
239 self.construction_slot_key
240 }
241
242 #[doc(hidden)]
243 #[inline]
244 pub fn construction_entity_order_key(&self) -> Option<i64> {
245 self.construction_entity_order_key
246 }
247
248 #[doc(hidden)]
249 #[inline]
250 pub fn construction_value_order_key(&self) -> Option<i64> {
251 self.construction_value_order_key
252 }
253}
254
255#[derive(Debug, Clone, Copy, PartialEq, Eq)]
256pub struct ScalarGroupLimits {
257 pub value_candidate_limit: Option<usize>,
258 pub group_candidate_limit: Option<usize>,
259 pub max_moves_per_step: Option<usize>,
260 pub max_augmenting_depth: Option<usize>,
261 pub max_rematch_size: Option<usize>,
262}
263
264impl ScalarGroupLimits {
265 pub const fn new() -> Self {
266 Self {
267 value_candidate_limit: None,
268 group_candidate_limit: None,
269 max_moves_per_step: None,
270 max_augmenting_depth: None,
271 max_rematch_size: None,
272 }
273 }
274}
275
276impl Default for ScalarGroupLimits {
277 fn default() -> Self {
278 Self::new()
279 }
280}
281
282pub type ScalarCandidateProvider<S> = fn(&S, ScalarGroupLimits) -> Vec<ScalarCandidate<S>>;
283
284pub(crate) struct ScalarAssignmentDeclaration<S> {
285 pub(crate) required_entity: Option<fn(&S, usize) -> bool>,
286 pub(crate) capacity_key: Option<fn(&S, usize, usize) -> Option<usize>>,
287 pub(crate) position_key: Option<fn(&S, usize) -> i64>,
288 pub(crate) sequence_key: Option<fn(&S, usize, usize) -> Option<usize>>,
289 pub(crate) entity_order: Option<fn(&S, usize) -> i64>,
290 pub(crate) value_order: Option<fn(&S, usize, usize) -> i64>,
291}
292
293impl<S> Clone for ScalarAssignmentDeclaration<S> {
294 fn clone(&self) -> Self {
295 *self
296 }
297}
298
299impl<S> Copy for ScalarAssignmentDeclaration<S> {}
300
301impl<S> Default for ScalarAssignmentDeclaration<S> {
302 fn default() -> Self {
303 Self {
304 required_entity: None,
305 capacity_key: None,
306 position_key: None,
307 sequence_key: None,
308 entity_order: None,
309 value_order: None,
310 }
311 }
312}
313
314pub struct ScalarGroup<S> {
315 group_name: &'static str,
316 targets: Vec<ScalarTarget<S>>,
317 kind: ScalarGroupKind<S>,
318 limits: ScalarGroupLimits,
319}
320
321pub(crate) enum ScalarGroupKind<S> {
322 Candidates {
323 candidate_provider: ScalarCandidateProvider<S>,
324 },
325 Assignment(ScalarAssignmentDeclaration<S>),
326}
327
328impl<S> Clone for ScalarGroupKind<S> {
329 fn clone(&self) -> Self {
330 *self
331 }
332}
333
334impl<S> Copy for ScalarGroupKind<S> {}
335
336impl<S> Clone for ScalarGroup<S> {
337 fn clone(&self) -> Self {
338 Self {
339 group_name: self.group_name,
340 targets: self.targets.clone(),
341 kind: self.kind,
342 limits: self.limits,
343 }
344 }
345}
346
347impl<S> ScalarGroup<S> {
348 pub fn candidates(
349 group_name: &'static str,
350 targets: Vec<ScalarTarget<S>>,
351 candidate_provider: ScalarCandidateProvider<S>,
352 ) -> Self {
353 Self {
354 group_name,
355 targets,
356 kind: ScalarGroupKind::Candidates { candidate_provider },
357 limits: ScalarGroupLimits::new(),
358 }
359 }
360
361 pub fn assignment(group_name: &'static str, target: ScalarTarget<S>) -> Self {
362 Self {
363 group_name,
364 targets: vec![target],
365 kind: ScalarGroupKind::Assignment(ScalarAssignmentDeclaration::default()),
366 limits: ScalarGroupLimits::new(),
367 }
368 }
369
370 pub fn with_required_entity(mut self, required_entity: fn(&S, usize) -> bool) -> Self {
371 self.assignment_mut().required_entity = Some(required_entity);
372 self
373 }
374
375 pub fn with_capacity_key(
376 mut self,
377 capacity_key: fn(&S, usize, usize) -> Option<usize>,
378 ) -> Self {
379 self.assignment_mut().capacity_key = Some(capacity_key);
380 self
381 }
382
383 pub fn with_position_key(mut self, position_key: fn(&S, usize) -> i64) -> Self {
384 self.assignment_mut().position_key = Some(position_key);
385 self
386 }
387
388 pub fn with_sequence_key(
389 mut self,
390 sequence_key: fn(&S, usize, usize) -> Option<usize>,
391 ) -> Self {
392 self.assignment_mut().sequence_key = Some(sequence_key);
393 self
394 }
395
396 pub fn with_entity_order(mut self, entity_order: fn(&S, usize) -> i64) -> Self {
397 self.assignment_mut().entity_order = Some(entity_order);
398 self
399 }
400
401 pub fn with_value_order(mut self, value_order: fn(&S, usize, usize) -> i64) -> Self {
402 self.assignment_mut().value_order = Some(value_order);
403 self
404 }
405
406 pub fn with_limits(mut self, limits: ScalarGroupLimits) -> Self {
407 self.limits = limits;
408 self
409 }
410
411 fn assignment_mut(&mut self) -> &mut ScalarAssignmentDeclaration<S> {
412 let ScalarGroupKind::Assignment(declaration) = &mut self.kind else {
413 panic!(
414 "scalar group `{}` is candidate-backed; assignment hooks require ScalarGroup::assignment",
415 self.group_name
416 );
417 };
418 declaration
419 }
420
421 #[doc(hidden)]
422 #[inline]
423 pub fn group_name(&self) -> &'static str {
424 self.group_name
425 }
426
427 #[doc(hidden)]
428 #[inline]
429 pub fn targets(&self) -> &[ScalarTarget<S>] {
430 &self.targets
431 }
432
433 #[doc(hidden)]
434 #[inline]
435 pub(crate) fn kind(&self) -> ScalarGroupKind<S> {
436 self.kind
437 }
438
439 #[doc(hidden)]
440 #[inline]
441 pub fn limits(&self) -> ScalarGroupLimits {
442 self.limits
443 }
444}
445
446impl<S> std::fmt::Debug for ScalarGroup<S> {
447 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
448 f.debug_struct("ScalarGroup")
449 .field("group_name", &self.group_name)
450 .field("target_count", &self.targets.len())
451 .field(
452 "kind",
453 match self.kind {
454 ScalarGroupKind::Assignment(_) => &"assignment",
455 ScalarGroupKind::Candidates { .. } => &"candidates",
456 },
457 )
458 .field("limits", &self.limits)
459 .finish_non_exhaustive()
460 }
461}