solverforge_core/domain/supply/
mod.rs

1//! Supply infrastructure for variable relationship tracking.
2//!
3//! Supplies provide efficient access to derived information about planning variables,
4//! such as inverse relationships (who points to whom) and anchor tracking (chain roots).
5//!
6//! The supply pattern enables O(1) lookups that would otherwise require O(n) scans.
7//!
8//! # Architecture
9//!
10//! - [`Supply`]: Marker trait for all supply types
11//! - [`SupplyDemand`]: Request a specific supply type from the manager
12//! - [`SupplyManager`]: Registry holding all active supplies
13//! - [`ListVariableStateSupply`]: Centralized tracking for list variable shadow state
14
15mod anchor;
16mod inverse;
17mod list_state;
18
19pub use anchor::{AnchorVariableDemand, AnchorVariableSupply, ExternalizedAnchorVariableSupply};
20pub use inverse::{
21    ExternalizedSingletonInverseVariableSupply, SingletonInverseVariableDemand,
22    SingletonInverseVariableSupply,
23};
24pub use list_state::{
25    ElementPosition, IndexVariableSupply, InverseVariableSupply, ListVariableStateDemand,
26    ListVariableStateSupply,
27};
28
29use std::any::{Any, TypeId};
30use std::collections::HashMap;
31use std::sync::Arc;
32
33/// Marker trait for all supply types.
34///
35/// Supplies are automatically maintained data structures that track
36/// relationships between entities and values. They provide O(1) lookups
37/// for information that would otherwise require scanning all entities.
38///
39/// # Examples
40///
41/// - `SingletonInverseVariableSupply`: Given a value, find the entity pointing to it
42/// - `AnchorVariableSupply`: Given an entity in a chain, find its anchor
43pub trait Supply: Send + Sync + 'static {
44    /// Returns the type ID of this supply for registration purposes.
45    fn supply_type_id(&self) -> TypeId {
46        TypeId::of::<Self>()
47    }
48}
49
50/// Trait for requesting a specific type of supply.
51///
52/// A demand describes what supply is needed. The `SupplyManager` uses
53/// demands to create or retrieve the appropriate supply instance.
54pub trait SupplyDemand: Send + Sync + 'static {
55    /// The type of supply this demand requests.
56    type Output: Supply;
57
58    /// Returns a unique key identifying this specific demand.
59    ///
60    /// Demands for the same variable should return the same key.
61    fn demand_key(&self) -> DemandKey;
62
63    /// Creates a new supply instance for this demand.
64    fn create_supply(&self) -> Self::Output;
65}
66
67/// A unique key identifying a supply demand.
68///
69/// The key combines the supply type with the variable it tracks,
70/// allowing multiple supplies of the same type for different variables.
71#[derive(Debug, Clone, PartialEq, Eq, Hash)]
72pub struct DemandKey {
73    /// The type of supply being requested.
74    pub supply_type: TypeId,
75    /// The name of the variable this supply tracks.
76    pub variable_name: String,
77    /// Optional discriminator for multiple supplies of the same type/variable.
78    pub discriminator: Option<String>,
79}
80
81impl DemandKey {
82    /// Creates a new demand key.
83    pub fn new<S: Supply>(variable_name: impl Into<String>) -> Self {
84        Self {
85            supply_type: TypeId::of::<S>(),
86            variable_name: variable_name.into(),
87            discriminator: None,
88        }
89    }
90
91    /// Creates a demand key with a discriminator.
92    pub fn with_discriminator<S: Supply>(
93        variable_name: impl Into<String>,
94        discriminator: impl Into<String>,
95    ) -> Self {
96        Self {
97            supply_type: TypeId::of::<S>(),
98            variable_name: variable_name.into(),
99            discriminator: Some(discriminator.into()),
100        }
101    }
102}
103
104/// Manager that holds and provides supplies.
105///
106/// The `SupplyManager` is the central registry for all supplies used by the solver.
107/// It creates supplies on-demand when first requested and caches them for reuse.
108///
109/// # Thread Safety
110///
111/// The manager uses `Arc` for shared ownership, allowing supplies to be accessed
112/// from multiple threads during parallel solving.
113#[derive(Default)]
114pub struct SupplyManager {
115    /// Cached supplies keyed by their demand key.
116    supplies: HashMap<DemandKey, Arc<dyn Any + Send + Sync>>,
117}
118
119impl SupplyManager {
120    /// Creates a new empty supply manager.
121    pub fn new() -> Self {
122        Self {
123            supplies: HashMap::new(),
124        }
125    }
126
127    /// Gets or creates a supply for the given demand.
128    ///
129    /// If the supply already exists, returns a clone of the Arc.
130    /// Otherwise, creates a new supply using the demand's `create_supply` method.
131    pub fn demand<D: SupplyDemand>(&mut self, demand: &D) -> Arc<D::Output> {
132        let key = demand.demand_key();
133
134        if let Some(supply) = self.supplies.get(&key) {
135            // Safe: we only insert Arc<D::Output> for this key
136            supply
137                .clone()
138                .downcast::<D::Output>()
139                .expect("Supply type mismatch")
140        } else {
141            let supply = Arc::new(demand.create_supply());
142            self.supplies
143                .insert(key, supply.clone() as Arc<dyn Any + Send + Sync>);
144            supply
145        }
146    }
147
148    /// Registers a pre-created supply.
149    ///
150    /// This is useful when supplies are created externally and need to be
151    /// registered with the manager.
152    pub fn register<S: Supply>(&mut self, key: DemandKey, supply: Arc<S>) {
153        self.supplies
154            .insert(key, supply as Arc<dyn Any + Send + Sync>);
155    }
156
157    /// Gets an existing supply without creating one.
158    ///
159    /// Returns `None` if the supply has not been created yet.
160    pub fn get<S: Supply>(&self, key: &DemandKey) -> Option<Arc<S>> {
161        self.supplies
162            .get(key)
163            .and_then(|s| s.clone().downcast::<S>().ok())
164    }
165
166    /// Removes a supply from the manager.
167    pub fn remove(&mut self, key: &DemandKey) -> bool {
168        self.supplies.remove(key).is_some()
169    }
170
171    /// Clears all supplies from the manager.
172    pub fn clear(&mut self) {
173        self.supplies.clear();
174    }
175
176    /// Returns the number of registered supplies.
177    pub fn len(&self) -> usize {
178        self.supplies.len()
179    }
180
181    /// Returns true if no supplies are registered.
182    pub fn is_empty(&self) -> bool {
183        self.supplies.is_empty()
184    }
185}
186
187impl std::fmt::Debug for SupplyManager {
188    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
189        f.debug_struct("SupplyManager")
190            .field("supply_count", &self.supplies.len())
191            .finish()
192    }
193}
194
195#[cfg(test)]
196mod tests {
197    use super::*;
198
199    // Test supply implementation
200    struct TestSupply {
201        value: i32,
202    }
203
204    impl Supply for TestSupply {}
205
206    // Test demand implementation
207    struct TestDemand {
208        variable_name: String,
209        initial_value: i32,
210    }
211
212    impl SupplyDemand for TestDemand {
213        type Output = TestSupply;
214
215        fn demand_key(&self) -> DemandKey {
216            DemandKey::new::<TestSupply>(&self.variable_name)
217        }
218
219        fn create_supply(&self) -> TestSupply {
220            TestSupply {
221                value: self.initial_value,
222            }
223        }
224    }
225
226    #[test]
227    fn test_supply_manager_demand_creates_supply() {
228        let mut manager = SupplyManager::new();
229        let demand = TestDemand {
230            variable_name: "test_var".to_string(),
231            initial_value: 42,
232        };
233
234        let supply = manager.demand(&demand);
235        assert_eq!(supply.value, 42);
236    }
237
238    #[test]
239    fn test_supply_manager_demand_returns_cached() {
240        let mut manager = SupplyManager::new();
241        let demand = TestDemand {
242            variable_name: "test_var".to_string(),
243            initial_value: 42,
244        };
245
246        let supply1 = manager.demand(&demand);
247        let supply2 = manager.demand(&demand);
248
249        // Should return the same Arc
250        assert!(Arc::ptr_eq(&supply1, &supply2));
251    }
252
253    #[test]
254    fn test_supply_manager_different_variables() {
255        let mut manager = SupplyManager::new();
256
257        let demand1 = TestDemand {
258            variable_name: "var1".to_string(),
259            initial_value: 1,
260        };
261        let demand2 = TestDemand {
262            variable_name: "var2".to_string(),
263            initial_value: 2,
264        };
265
266        let supply1 = manager.demand(&demand1);
267        let supply2 = manager.demand(&demand2);
268
269        assert_eq!(supply1.value, 1);
270        assert_eq!(supply2.value, 2);
271        assert!(!Arc::ptr_eq(&supply1, &supply2));
272    }
273
274    #[test]
275    fn test_supply_manager_register() {
276        let mut manager = SupplyManager::new();
277        let key = DemandKey::new::<TestSupply>("registered_var");
278        let supply = Arc::new(TestSupply { value: 100 });
279
280        manager.register(key.clone(), supply);
281
282        let retrieved = manager.get::<TestSupply>(&key);
283        assert!(retrieved.is_some());
284        assert_eq!(retrieved.unwrap().value, 100);
285    }
286
287    #[test]
288    fn test_supply_manager_remove() {
289        let mut manager = SupplyManager::new();
290        let demand = TestDemand {
291            variable_name: "to_remove".to_string(),
292            initial_value: 1,
293        };
294
295        let _ = manager.demand(&demand);
296        assert_eq!(manager.len(), 1);
297
298        let key = demand.demand_key();
299        assert!(manager.remove(&key));
300        assert_eq!(manager.len(), 0);
301    }
302
303    #[test]
304    fn test_supply_manager_clear() {
305        let mut manager = SupplyManager::new();
306
307        let demand1 = TestDemand {
308            variable_name: "var1".to_string(),
309            initial_value: 1,
310        };
311        let demand2 = TestDemand {
312            variable_name: "var2".to_string(),
313            initial_value: 2,
314        };
315
316        let _ = manager.demand(&demand1);
317        let _ = manager.demand(&demand2);
318        assert_eq!(manager.len(), 2);
319
320        manager.clear();
321        assert!(manager.is_empty());
322    }
323
324    #[test]
325    fn test_demand_key_with_discriminator() {
326        let key1 = DemandKey::new::<TestSupply>("var");
327        let key2 = DemandKey::with_discriminator::<TestSupply>("var", "disc");
328
329        assert_ne!(key1, key2);
330        assert!(key1.discriminator.is_none());
331        assert_eq!(key2.discriminator, Some("disc".to_string()));
332    }
333}