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}