Skip to main content

solverforge_solver/planning/scalar/
group.rs

1use super::{
2    ScalarAssignmentDeclaration, ScalarAssignmentRule, ScalarCandidateProvider, ScalarTarget,
3};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub struct ScalarGroupLimits {
7    pub value_candidate_limit: Option<usize>,
8    pub group_candidate_limit: Option<usize>,
9    pub max_moves_per_step: Option<usize>,
10    pub max_augmenting_depth: Option<usize>,
11    pub max_rematch_size: Option<usize>,
12}
13
14impl ScalarGroupLimits {
15    pub const fn new() -> Self {
16        Self {
17            value_candidate_limit: None,
18            group_candidate_limit: None,
19            max_moves_per_step: None,
20            max_augmenting_depth: None,
21            max_rematch_size: None,
22        }
23    }
24}
25
26impl Default for ScalarGroupLimits {
27    fn default() -> Self {
28        Self::new()
29    }
30}
31
32pub struct ScalarGroup<S> {
33    group_name: &'static str,
34    targets: Vec<ScalarTarget<S>>,
35    kind: ScalarGroupKind<S>,
36    limits: ScalarGroupLimits,
37}
38
39pub(crate) enum ScalarGroupKind<S> {
40    Candidates {
41        candidate_provider: ScalarCandidateProvider<S>,
42    },
43    Assignment(ScalarAssignmentDeclaration<S>),
44}
45
46impl<S> Clone for ScalarGroupKind<S> {
47    fn clone(&self) -> Self {
48        *self
49    }
50}
51
52impl<S> Copy for ScalarGroupKind<S> {}
53
54impl<S> Clone for ScalarGroup<S> {
55    fn clone(&self) -> Self {
56        Self {
57            group_name: self.group_name,
58            targets: self.targets.clone(),
59            kind: self.kind,
60            limits: self.limits,
61        }
62    }
63}
64
65impl<S> ScalarGroup<S> {
66    pub fn candidates(
67        group_name: &'static str,
68        targets: Vec<ScalarTarget<S>>,
69        candidate_provider: ScalarCandidateProvider<S>,
70    ) -> Self {
71        Self {
72            group_name,
73            targets,
74            kind: ScalarGroupKind::Candidates { candidate_provider },
75            limits: ScalarGroupLimits::new(),
76        }
77    }
78
79    pub fn assignment(group_name: &'static str, target: ScalarTarget<S>) -> Self {
80        Self {
81            group_name,
82            targets: vec![target],
83            kind: ScalarGroupKind::Assignment(ScalarAssignmentDeclaration::default()),
84            limits: ScalarGroupLimits::new(),
85        }
86    }
87
88    pub fn with_required_entity(mut self, required_entity: fn(&S, usize) -> bool) -> Self {
89        self.assignment_mut().required_entity = Some(required_entity);
90        self
91    }
92
93    pub fn with_capacity_key(
94        mut self,
95        capacity_key: fn(&S, usize, usize) -> Option<usize>,
96    ) -> Self {
97        self.assignment_mut().capacity_key = Some(capacity_key);
98        self
99    }
100
101    pub fn with_assignment_rule(mut self, assignment_rule: ScalarAssignmentRule<S>) -> Self {
102        self.assignment_mut().assignment_rule = Some(assignment_rule);
103        self
104    }
105
106    pub fn with_position_key(mut self, position_key: fn(&S, usize) -> i64) -> Self {
107        self.assignment_mut().position_key = Some(position_key);
108        self
109    }
110
111    pub fn with_sequence_key(
112        mut self,
113        sequence_key: fn(&S, usize, usize) -> Option<usize>,
114    ) -> Self {
115        self.assignment_mut().sequence_key = Some(sequence_key);
116        self
117    }
118
119    pub fn with_entity_order(mut self, entity_order: fn(&S, usize) -> i64) -> Self {
120        self.assignment_mut().entity_order = Some(entity_order);
121        self
122    }
123
124    pub fn with_value_order(mut self, value_order: fn(&S, usize, usize) -> i64) -> Self {
125        self.assignment_mut().value_order = Some(value_order);
126        self
127    }
128
129    pub fn with_limits(mut self, limits: ScalarGroupLimits) -> Self {
130        self.limits = limits;
131        self
132    }
133
134    fn assignment_mut(&mut self) -> &mut ScalarAssignmentDeclaration<S> {
135        let ScalarGroupKind::Assignment(declaration) = &mut self.kind else {
136            panic!(
137                "scalar group `{}` is candidate-backed; assignment hooks require ScalarGroup::assignment",
138                self.group_name
139            );
140        };
141        declaration
142    }
143
144    #[doc(hidden)]
145    #[inline]
146    pub fn group_name(&self) -> &'static str {
147        self.group_name
148    }
149
150    #[doc(hidden)]
151    #[inline]
152    pub fn targets(&self) -> &[ScalarTarget<S>] {
153        &self.targets
154    }
155
156    #[doc(hidden)]
157    #[inline]
158    pub(crate) fn kind(&self) -> ScalarGroupKind<S> {
159        self.kind
160    }
161
162    #[doc(hidden)]
163    #[inline]
164    pub fn limits(&self) -> ScalarGroupLimits {
165        self.limits
166    }
167}
168
169impl<S> std::fmt::Debug for ScalarGroup<S> {
170    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
171        f.debug_struct("ScalarGroup")
172            .field("group_name", &self.group_name)
173            .field("target_count", &self.targets.len())
174            .field(
175                "kind",
176                match self.kind {
177                    ScalarGroupKind::Assignment(_) => &"assignment",
178                    ScalarGroupKind::Candidates { .. } => &"candidates",
179                },
180            )
181            .field("limits", &self.limits)
182            .finish_non_exhaustive()
183    }
184}