1use std::fmt;
2
3use super::value_source::ValueSource;
4
5pub type ScalarGetter<S> = fn(&S, usize, usize) -> Option<usize>;
6pub type ScalarSetter<S> = fn(&mut S, usize, usize, Option<usize>);
7pub type ScalarCandidateValues<S> = for<'a> fn(&'a S, usize, usize) -> &'a [usize];
8pub type NearbyValueDistanceMeter<S> = fn(&S, usize, usize, usize) -> Option<f64>;
9pub type NearbyEntityDistanceMeter<S> = fn(&S, usize, usize, usize) -> Option<f64>;
10pub type ConstructionEntityOrderKey<S> = fn(&S, usize, usize) -> Option<i64>;
11pub type ConstructionValueOrderKey<S> = fn(&S, usize, usize, usize) -> Option<i64>;
12
13pub struct ScalarVariableSlot<S> {
14 pub descriptor_index: usize,
15 pub variable_index: usize,
16 pub entity_type_name: &'static str,
17 pub entity_count: fn(&S) -> usize,
18 pub variable_name: &'static str,
19 pub getter: ScalarGetter<S>,
20 pub setter: ScalarSetter<S>,
21 pub value_source: ValueSource<S>,
22 pub allows_unassigned: bool,
23 pub candidate_values: Option<ScalarCandidateValues<S>>,
24 pub nearby_value_candidates: Option<ScalarCandidateValues<S>>,
25 pub nearby_entity_candidates: Option<ScalarCandidateValues<S>>,
26 pub nearby_value_distance_meter: Option<NearbyValueDistanceMeter<S>>,
27 pub nearby_entity_distance_meter: Option<NearbyEntityDistanceMeter<S>>,
28 pub construction_entity_order_key: Option<ConstructionEntityOrderKey<S>>,
29 pub construction_value_order_key: Option<ConstructionValueOrderKey<S>>,
30}
31
32impl<S> Clone for ScalarVariableSlot<S> {
33 fn clone(&self) -> Self {
34 *self
35 }
36}
37
38impl<S> Copy for ScalarVariableSlot<S> {}
39
40impl<S> ScalarVariableSlot<S> {
41 #[allow(clippy::too_many_arguments)]
42 pub fn new(
43 descriptor_index: usize,
44 variable_index: usize,
45 entity_type_name: &'static str,
46 entity_count: fn(&S) -> usize,
47 variable_name: &'static str,
48 getter: ScalarGetter<S>,
49 setter: ScalarSetter<S>,
50 value_source: ValueSource<S>,
51 allows_unassigned: bool,
52 ) -> Self {
53 Self {
54 descriptor_index,
55 variable_index,
56 entity_type_name,
57 entity_count,
58 variable_name,
59 getter,
60 setter,
61 value_source,
62 allows_unassigned,
63 candidate_values: None,
64 nearby_value_candidates: None,
65 nearby_entity_candidates: None,
66 nearby_value_distance_meter: None,
67 nearby_entity_distance_meter: None,
68 construction_entity_order_key: None,
69 construction_value_order_key: None,
70 }
71 }
72
73 pub fn with_nearby_value_distance_meter(mut self, meter: NearbyValueDistanceMeter<S>) -> Self {
74 self.nearby_value_distance_meter = Some(meter);
75 self
76 }
77
78 pub fn with_candidate_values(mut self, provider: ScalarCandidateValues<S>) -> Self {
79 self.candidate_values = Some(provider);
80 self
81 }
82
83 pub fn with_nearby_value_candidates(mut self, provider: ScalarCandidateValues<S>) -> Self {
84 self.nearby_value_candidates = Some(provider);
85 self
86 }
87
88 pub fn with_nearby_entity_candidates(mut self, provider: ScalarCandidateValues<S>) -> Self {
89 self.nearby_entity_candidates = Some(provider);
90 self
91 }
92
93 pub fn with_nearby_entity_distance_meter(
94 mut self,
95 meter: NearbyEntityDistanceMeter<S>,
96 ) -> Self {
97 self.nearby_entity_distance_meter = Some(meter);
98 self
99 }
100
101 pub fn with_construction_entity_order_key(
102 mut self,
103 order_key: ConstructionEntityOrderKey<S>,
104 ) -> Self {
105 self.construction_entity_order_key = Some(order_key);
106 self
107 }
108
109 pub fn with_construction_value_order_key(
110 mut self,
111 order_key: ConstructionValueOrderKey<S>,
112 ) -> Self {
113 self.construction_value_order_key = Some(order_key);
114 self
115 }
116
117 pub fn matches_target(&self, entity_class: Option<&str>, variable_name: Option<&str>) -> bool {
118 entity_class.is_none_or(|name| name == self.entity_type_name)
119 && variable_name.is_none_or(|name| name == self.variable_name)
120 }
121
122 pub fn current_value(&self, solution: &S, entity_index: usize) -> Option<usize> {
123 (self.getter)(solution, entity_index, self.variable_index)
124 }
125
126 pub fn set_value(&self, solution: &mut S, entity_index: usize, value: Option<usize>) {
127 (self.setter)(solution, entity_index, self.variable_index, value);
128 }
129
130 pub fn values_for_entity(&self, solution: &S, entity_index: usize) -> Vec<usize> {
131 match self.value_source {
132 ValueSource::Empty => Vec::new(),
133 ValueSource::CountableRange { from, to } => (from..to).collect(),
134 ValueSource::SolutionCount {
135 count_fn,
136 provider_index,
137 } => (0..count_fn(solution, provider_index)).collect(),
138 ValueSource::EntitySlice { values_for_entity } => {
139 values_for_entity(solution, entity_index, self.variable_index).to_vec()
140 }
141 }
142 }
143
144 pub fn candidate_values_for_entity(
145 &self,
146 solution: &S,
147 entity_index: usize,
148 value_candidate_limit: Option<usize>,
149 ) -> Vec<usize> {
150 if let Some(provider) = self.candidate_values {
151 let values = provider(solution, entity_index, self.variable_index);
152 return match value_candidate_limit {
153 Some(limit) => values.iter().copied().take(limit).collect(),
154 None => values.to_vec(),
155 };
156 }
157
158 match self.value_source {
159 ValueSource::Empty => Vec::new(),
160 ValueSource::CountableRange { from, to } => {
161 let end = value_candidate_limit
162 .map(|limit| from.saturating_add(limit).min(to))
163 .unwrap_or(to);
164 (from..end).collect()
165 }
166 ValueSource::SolutionCount {
167 count_fn,
168 provider_index,
169 } => {
170 let count = count_fn(solution, provider_index);
171 let end = value_candidate_limit
172 .map(|limit| limit.min(count))
173 .unwrap_or(count);
174 (0..end).collect()
175 }
176 ValueSource::EntitySlice { values_for_entity } => {
177 let values = values_for_entity(solution, entity_index, self.variable_index);
178 match value_candidate_limit {
179 Some(limit) => values.iter().copied().take(limit).collect(),
180 None => values.to_vec(),
181 }
182 }
183 }
184 }
185
186 pub fn has_values_for_entity(&self, solution: &S, entity_index: usize) -> bool {
187 match self.value_source {
188 ValueSource::Empty => false,
189 ValueSource::CountableRange { from, to } => from < to,
190 ValueSource::SolutionCount {
191 count_fn,
192 provider_index,
193 } => count_fn(solution, provider_index) > 0,
194 ValueSource::EntitySlice { values_for_entity } => {
195 !values_for_entity(solution, entity_index, self.variable_index).is_empty()
196 }
197 }
198 }
199
200 pub fn value_is_legal(
201 &self,
202 solution: &S,
203 entity_index: usize,
204 candidate: Option<usize>,
205 ) -> bool {
206 let Some(value) = candidate else {
207 return self.allows_unassigned;
208 };
209 match self.value_source {
210 ValueSource::Empty => false,
211 ValueSource::CountableRange { from, to } => from <= value && value < to,
212 ValueSource::SolutionCount {
213 count_fn,
214 provider_index,
215 } => value < count_fn(solution, provider_index),
216 ValueSource::EntitySlice { values_for_entity } => {
217 values_for_entity(solution, entity_index, self.variable_index).contains(&value)
218 }
219 }
220 }
221
222 pub fn nearby_value_distance(
223 &self,
224 solution: &S,
225 entity_index: usize,
226 value: usize,
227 ) -> Option<f64> {
228 self.nearby_value_distance_meter
229 .and_then(|meter| meter(solution, entity_index, self.variable_index, value))
230 }
231
232 pub fn nearby_entity_distance(
233 &self,
234 solution: &S,
235 left_entity_index: usize,
236 right_entity_index: usize,
237 ) -> Option<f64> {
238 self.nearby_entity_distance_meter.and_then(|meter| {
239 meter(
240 solution,
241 left_entity_index,
242 right_entity_index,
243 self.variable_index,
244 )
245 })
246 }
247
248 pub fn construction_entity_order_key(&self, solution: &S, entity_index: usize) -> Option<i64> {
249 self.construction_entity_order_key
250 .and_then(|order_key| order_key(solution, entity_index, self.variable_index))
251 }
252
253 pub fn construction_value_order_key(
254 &self,
255 solution: &S,
256 entity_index: usize,
257 value: usize,
258 ) -> Option<i64> {
259 self.construction_value_order_key
260 .and_then(|order_key| order_key(solution, entity_index, self.variable_index, value))
261 }
262}
263
264impl<S> fmt::Debug for ScalarVariableSlot<S> {
265 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
266 f.debug_struct("ScalarVariableSlot")
267 .field("descriptor_index", &self.descriptor_index)
268 .field("variable_index", &self.variable_index)
269 .field("entity_type_name", &self.entity_type_name)
270 .field("variable_name", &self.variable_name)
271 .field("value_source", &self.value_source)
272 .field("allows_unassigned", &self.allows_unassigned)
273 .field("has_candidate_values", &self.candidate_values.is_some())
274 .field(
275 "has_nearby_value_candidates",
276 &self.nearby_value_candidates.is_some(),
277 )
278 .field(
279 "has_nearby_entity_candidates",
280 &self.nearby_entity_candidates.is_some(),
281 )
282 .field(
283 "has_nearby_value_distance_meter",
284 &self.nearby_value_distance_meter.is_some(),
285 )
286 .field(
287 "has_nearby_entity_distance_meter",
288 &self.nearby_entity_distance_meter.is_some(),
289 )
290 .field(
291 "has_construction_entity_order_key",
292 &self.construction_entity_order_key.is_some(),
293 )
294 .field(
295 "has_construction_value_order_key",
296 &self.construction_value_order_key.is_some(),
297 )
298 .finish()
299 }
300}