use std::marker::PhantomData;
use solverforge_core::score::Score;
use solverforge_core::{ConstraintRef, ImpactType};
use super::collection_extract::CollectionExtract;
use super::joiner::plan::{CompileCondition, ExecutablePlan, IndexedPlan};
use super::relational::operator::{FilterNode, FilterPredicate, JoinNode, Operator};
use super::relational::Leaf;
use crate::constraint::relational::OperatorTerminal;
pub struct Chain<S: 'static, O, Sc>
where
O: Operator<S>,
{
tree: O,
next_binding: u32,
_phantom: PhantomData<fn() -> (S, Sc)>,
}
impl<S, O, Sc> Chain<S, O, Sc>
where
S: Send + Sync + 'static,
O: Operator<S> + Send + Sync,
Sc: Score + 'static,
{
pub fn new(tree: O, next_binding: u32) -> Self {
Self {
tree,
next_binding,
_phantom: PhantomData,
}
}
pub fn filter<P>(self, predicate: P) -> Chain<S, FilterNode<O, P>, Sc>
where
P: for<'a> FilterPredicate<S, O::View<'a>> + 'static,
FilterNode<O, P>: Operator<S>,
{
Chain {
tree: FilterNode::new(self.tree, predicate),
next_binding: self.next_binding,
_phantom: PhantomData,
}
}
pub fn join<B, EB, P>(
self,
target: (EB, P),
) -> Chain<S, JoinNode<S, O, CollectionNodeAlias<S, EB>, P::Plan>, Sc>
where
B: Clone + Send + Sync + 'static,
EB: CollectionExtract<S, Item = B> + 'static,
P: CompileCondition + 'static,
P::Plan: IndexedPlan,
for<'a> CollectionNodeAlias<S, EB>: Operator<S, View<'a> = Leaf<'a, B>>,
for<'a> P::Plan: ExecutablePlan<O::View<'a>, Leaf<'a, B>>,
JoinNode<S, O, CollectionNodeAlias<S, EB>, P::Plan>: Operator<S>,
{
let (extractor, condition) = target;
let tree = JoinNode::new(
self.tree,
super::relational::operator::CollectionNode::new(extractor, self.next_binding),
condition,
);
Chain {
tree,
next_binding: self.next_binding + 1,
_phantom: PhantomData,
}
}
pub fn penalize<W>(self, weight: W) -> ChainBuilder<S, O, W, Sc>
where
W: for<'a> Fn(&S, &O::View<'a>) -> Sc + Send + Sync,
{
ChainBuilder {
tree: self.tree,
impact_type: ImpactType::Penalty,
weight,
is_hard: false,
_phantom: PhantomData,
}
}
pub fn reward<W>(self, weight: W) -> ChainBuilder<S, O, W, Sc>
where
W: for<'a> Fn(&S, &O::View<'a>) -> Sc + Send + Sync,
{
ChainBuilder {
tree: self.tree,
impact_type: ImpactType::Reward,
weight,
is_hard: false,
_phantom: PhantomData,
}
}
}
type CollectionNodeAlias<S, E> = super::relational::operator::CollectionNode<S, E>;
pub struct ChainBuilder<S: 'static, O, W, Sc>
where
O: Operator<S>,
{
tree: O,
impact_type: ImpactType,
weight: W,
is_hard: bool,
_phantom: PhantomData<fn() -> (S, Sc)>,
}
impl<S, O, W, Sc> ChainBuilder<S, O, W, Sc>
where
S: Send + Sync + 'static,
O: Operator<S> + Send + Sync,
W: for<'a> Fn(&S, &O::View<'a>) -> Sc + Send + Sync,
Sc: Score + 'static,
for<'a> O::View<'a>: super::relational::operator::ExplainRow,
{
pub fn hard(mut self) -> Self {
self.is_hard = true;
self
}
pub fn named(self, name: &str) -> OperatorTerminal<S, O, W, Sc> {
OperatorTerminal::new(
ConstraintRef::new("", name),
self.impact_type,
self.tree,
self.weight,
self.is_hard,
)
}
}