Skip to main content

solverforge_solver/planning/
scalar.rs

1use 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}