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}