Skip to main content

solverforge_scoring/stream/
factory.rs

1/* Constraint factory for creating monomorphized constraint streams.
2
3The factory is the entry point for the fluent constraint API.
4*/
5
6use std::marker::PhantomData;
7
8use solverforge_core::score::Score;
9
10use super::collection_extract::CollectionExtract;
11use super::filter::TrueFilter;
12use super::UniConstraintStream;
13
14/* Factory for creating constraint streams.
15
16`ConstraintFactory` is parameterized by the solution type `S` and score type `Sc`.
17It serves as the entry point for defining constraints using the fluent API.
18
19# Example
20
21```
22use solverforge_scoring::stream::ConstraintFactory;
23use solverforge_scoring::api::constraint_set::IncrementalConstraint;
24use solverforge_core::score::SoftScore;
25
26#[derive(Clone)]
27struct Solution {
28values: Vec<Option<i32>>,
29}
30
31let factory = ConstraintFactory::<Solution, SoftScore>::new();
32
33let constraint = factory
34.for_each(|s: &Solution| &s.values)
35.filter(|v: &Option<i32>| v.is_none())
36.penalize(SoftScore::of(1))
37.named("Unassigned");
38
39let solution = Solution { values: vec![Some(1), None, None] };
40assert_eq!(constraint.evaluate(&solution), SoftScore::of(-2));
41```
42*/
43pub struct ConstraintFactory<S, Sc: Score> {
44    _phantom: PhantomData<(fn() -> S, fn() -> Sc)>,
45}
46
47impl<S, Sc> ConstraintFactory<S, Sc>
48where
49    S: Send + Sync + 'static,
50    Sc: Score + 'static,
51{
52    // Creates a new constraint factory.
53    pub fn new() -> Self {
54        Self {
55            _phantom: PhantomData,
56        }
57    }
58
59    /* Creates a zero-erasure uni-constraint stream over a collection source.
60
61    For macro-generated models, pass the inherent solution source method:
62    `ConstraintFactory::new().for_each(Schedule::shifts())`.
63    Low-level callers can still pass any `CollectionExtract<S, Item = A>`.
64    The extractor type is preserved as a concrete generic for full zero-erasure.
65    */
66    pub fn for_each<A, E>(self, extractor: E) -> UniConstraintStream<S, A, E, TrueFilter, Sc>
67    where
68        A: Clone + Send + Sync + 'static,
69        E: CollectionExtract<S, Item = A>,
70    {
71        UniConstraintStream::new(extractor)
72    }
73}
74
75impl<S, Sc> Default for ConstraintFactory<S, Sc>
76where
77    S: Send + Sync + 'static,
78    Sc: Score + 'static,
79{
80    fn default() -> Self {
81        Self::new()
82    }
83}
84
85impl<S, Sc: Score> Clone for ConstraintFactory<S, Sc> {
86    fn clone(&self) -> Self {
87        Self {
88            _phantom: PhantomData,
89        }
90    }
91}
92
93impl<S, Sc: Score> std::fmt::Debug for ConstraintFactory<S, Sc> {
94    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
95        f.debug_struct("ConstraintFactory").finish()
96    }
97}