solverforge_scoring/stream/mod.rs
1//! Fluent constraint stream API for zero-erasure constraint programming.
2//!
3//! This module provides an ergonomic builder pattern for defining constraints
4//! that compile to fully-typed, monomorphized constraint implementations.
5//!
6//! # Overview
7//!
8//! The stream API transforms verbose constraint definitions into concise,
9//! fluent declarations while preserving full type information through the
10//! entire evaluation pipeline.
11//!
12//! # Example
13//!
14//! ```
15//! use solverforge_scoring::stream::ConstraintFactory;
16//! use solverforge_scoring::api::constraint_set::{ConstraintSet, IncrementalConstraint};
17//! use solverforge_core::score::SimpleScore;
18//!
19//! #[derive(Clone)]
20//! struct Schedule {
21//! shifts: Vec<Shift>,
22//! }
23//!
24//! #[derive(Clone, Debug)]
25//! struct Shift {
26//! employee_idx: Option<usize>,
27//! required_skill: String,
28//! }
29//!
30//! // Define constraints using the fluent API
31//! let unassigned = ConstraintFactory::<Schedule, SimpleScore>::new()
32//! .for_each(|s: &Schedule| &s.shifts)
33//! .filter(|shift: &Shift| shift.employee_idx.is_none())
34//! .penalize(SimpleScore::of(1))
35//! .as_constraint("Unassigned shift");
36//!
37//! // Use the constraint
38//! let schedule = Schedule {
39//! shifts: vec![
40//! Shift { employee_idx: Some(0), required_skill: "A".into() },
41//! Shift { employee_idx: None, required_skill: "B".into() },
42//! ],
43//! };
44//!
45//! assert_eq!(unassigned.evaluate(&schedule), SimpleScore::of(-1));
46//! ```
47//!
48//! # Architecture
49//!
50//! The stream builders produce existing constraint types at definition time:
51//!
52//! ```text
53//! ConstraintFactory::new()
54//! .for_each(extractor) -> UniConstraintStream<S, A, Sc>
55//! .filter(predicate) -> UniConstraintStream (accumulates filters)
56//! .penalize(weight) -> UniConstraintBuilder<S, A, Sc>
57//! .as_constraint(name) -> IncrementalUniConstraint<S, A, Sc>
58//! ```
59//!
60//! The final `IncrementalUniConstraint` is fully monomorphized with no
61//! virtual dispatch in the hot path.
62
63mod arity_stream_macros;
64mod balance_stream;
65mod bi_stream;
66pub mod collector;
67mod complemented_stream;
68mod cross_bi_stream;
69mod factory;
70pub mod filter;
71mod flattened_bi_stream;
72mod grouped_stream;
73mod if_exists_stream;
74pub mod joiner;
75mod penta_stream;
76mod quad_stream;
77mod tri_stream;
78mod uni_stream;
79
80pub use balance_stream::{BalanceConstraintBuilder, BalanceConstraintStream};
81pub use bi_stream::{BiConstraintBuilder, BiConstraintStream};
82pub use complemented_stream::{ComplementedConstraintBuilder, ComplementedConstraintStream};
83pub use cross_bi_stream::{CrossBiConstraintBuilder, CrossBiConstraintStream};
84pub use factory::ConstraintFactory;
85pub use flattened_bi_stream::{FlattenedBiConstraintBuilder, FlattenedBiConstraintStream};
86pub use grouped_stream::{GroupedConstraintBuilder, GroupedConstraintStream};
87pub use if_exists_stream::{IfExistsBuilder, IfExistsStream};
88pub use penta_stream::{PentaConstraintBuilder, PentaConstraintStream};
89pub use quad_stream::{QuadConstraintBuilder, QuadConstraintStream};
90pub use tri_stream::{TriConstraintBuilder, TriConstraintStream};
91pub use uni_stream::{UniConstraintBuilder, UniConstraintStream};