Skip to main content

solverforge_solver/planning/
coverage.rs

1use std::marker::PhantomData;
2
3use crate::planning::ScalarTarget;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub struct CoverageGroupLimits {
7    /// Caps candidate values considered for each entity in construction and repair.
8    pub value_candidate_limit: Option<usize>,
9    /// Caps group-level construction candidates. Repair selectors do not read
10    /// this limit.
11    pub group_candidate_limit: Option<usize>,
12    /// Caps moves emitted by coverage repair selectors. Construction does not
13    /// read this limit.
14    pub max_moves_per_step: Option<usize>,
15    /// Caps the recursive augmenting path depth used while relocating blockers.
16    pub max_augmenting_depth: Option<usize>,
17}
18
19impl CoverageGroupLimits {
20    pub const fn new() -> Self {
21        Self {
22            value_candidate_limit: None,
23            group_candidate_limit: None,
24            max_moves_per_step: None,
25            max_augmenting_depth: None,
26        }
27    }
28}
29
30impl Default for CoverageGroupLimits {
31    fn default() -> Self {
32        Self::new()
33    }
34}
35
36pub struct CoverageGroup<S> {
37    group_name: &'static str,
38    target: ScalarTarget<S>,
39    required_slot: Option<fn(&S, usize) -> bool>,
40    capacity_key: Option<fn(&S, usize, usize) -> Option<usize>>,
41    entity_order: Option<fn(&S, usize) -> i64>,
42    value_order: Option<fn(&S, usize, usize) -> i64>,
43    limits: CoverageGroupLimits,
44    _phantom: PhantomData<fn() -> S>,
45}
46
47impl<S> Clone for CoverageGroup<S> {
48    fn clone(&self) -> Self {
49        *self
50    }
51}
52
53impl<S> Copy for CoverageGroup<S> {}
54
55impl<S> CoverageGroup<S> {
56    pub const fn new(group_name: &'static str, target: ScalarTarget<S>) -> Self {
57        Self {
58            group_name,
59            target,
60            required_slot: None,
61            capacity_key: None,
62            entity_order: None,
63            value_order: None,
64            limits: CoverageGroupLimits::new(),
65            _phantom: PhantomData,
66        }
67    }
68
69    pub const fn with_required_slot(mut self, required_slot: fn(&S, usize) -> bool) -> Self {
70        self.required_slot = Some(required_slot);
71        self
72    }
73
74    pub const fn with_capacity_key(
75        mut self,
76        capacity_key: fn(&S, usize, usize) -> Option<usize>,
77    ) -> Self {
78        self.capacity_key = Some(capacity_key);
79        self
80    }
81
82    pub const fn with_entity_order(mut self, entity_order: fn(&S, usize) -> i64) -> Self {
83        self.entity_order = Some(entity_order);
84        self
85    }
86
87    pub const fn with_value_order(mut self, value_order: fn(&S, usize, usize) -> i64) -> Self {
88        self.value_order = Some(value_order);
89        self
90    }
91
92    pub const fn with_limits(mut self, limits: CoverageGroupLimits) -> Self {
93        self.limits = limits;
94        self
95    }
96
97    #[doc(hidden)]
98    #[inline]
99    pub fn group_name(&self) -> &'static str {
100        self.group_name
101    }
102
103    #[doc(hidden)]
104    #[inline]
105    pub fn target(&self) -> ScalarTarget<S> {
106        self.target
107    }
108
109    #[doc(hidden)]
110    #[inline]
111    pub fn required_slot(&self) -> Option<fn(&S, usize) -> bool> {
112        self.required_slot
113    }
114
115    #[doc(hidden)]
116    #[inline]
117    pub fn capacity_key(&self) -> Option<fn(&S, usize, usize) -> Option<usize>> {
118        self.capacity_key
119    }
120
121    #[doc(hidden)]
122    #[inline]
123    pub fn entity_order(&self) -> Option<fn(&S, usize) -> i64> {
124        self.entity_order
125    }
126
127    #[doc(hidden)]
128    #[inline]
129    pub fn value_order(&self) -> Option<fn(&S, usize, usize) -> i64> {
130        self.value_order
131    }
132
133    #[doc(hidden)]
134    #[inline]
135    pub fn limits(&self) -> CoverageGroupLimits {
136        self.limits
137    }
138}
139
140impl<S> std::fmt::Debug for CoverageGroup<S> {
141    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
142        f.debug_struct("CoverageGroup")
143            .field("group_name", &self.group_name)
144            .field("target_descriptor_index", &self.target.descriptor_index())
145            .field("target_variable_name", &self.target.variable_name())
146            .field("has_required_slot", &self.required_slot.is_some())
147            .field("has_capacity_key", &self.capacity_key.is_some())
148            .field("limits", &self.limits)
149            .finish_non_exhaustive()
150    }
151}