Skip to main content

solverforge_scoring/stream/
factory.rs

1/* Constraint factory for creating typed 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 entities extracted from the solution.
60
61    The extractor function receives a reference to the solution and returns
62    a slice of entities to iterate over. The extractor type is preserved
63    as a concrete generic for full zero-erasure.
64    */
65    pub fn for_each<A, E>(self, extractor: E) -> UniConstraintStream<S, A, E, TrueFilter, Sc>
66    where
67        A: Clone + Send + Sync + 'static,
68        E: CollectionExtract<S, Item = A>,
69    {
70        UniConstraintStream::new(extractor)
71    }
72}
73
74impl<S, Sc> Default for ConstraintFactory<S, Sc>
75where
76    S: Send + Sync + 'static,
77    Sc: Score + 'static,
78{
79    fn default() -> Self {
80        Self::new()
81    }
82}
83
84impl<S, Sc: Score> Clone for ConstraintFactory<S, Sc> {
85    fn clone(&self) -> Self {
86        Self {
87            _phantom: PhantomData,
88        }
89    }
90}
91
92impl<S, Sc: Score> std::fmt::Debug for ConstraintFactory<S, Sc> {
93    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94        f.debug_struct("ConstraintFactory").finish()
95    }
96}