Skip to main content

csp_solver/constraint/
lambda.rs

1//! Generic closure-based constraint.
2//!
3//! Tests: `tests/optimize.rs`.
4
5use crate::domain::Domain;
6
7use super::traits::{Constraint, VarId};
8
9/// Boxed predicate over a partial assignment.
10///
11/// `Send + Sync` — required so `Csp<D>` can be moved into a
12/// `pyo3::Python::allow_threads` closure (see `constraint::traits::Constraint`).
13pub(crate) type CheckerFn<D> = Box<dyn Fn(&[Option<<D as Domain>::Value>]) -> bool + Send + Sync>;
14
15pub struct LambdaConstraint<D: Domain> {
16    pub(crate) scope: Vec<VarId>,
17    pub(crate) checker: CheckerFn<D>,
18    label: String,
19}
20
21impl<D: Domain> std::fmt::Debug for LambdaConstraint<D> {
22    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23        write!(f, "LambdaConstraint({}, {:?})", self.label, self.scope)
24    }
25}
26
27impl<D: Domain> LambdaConstraint<D> {
28    pub fn new(
29        scope: Vec<VarId>,
30        checker: impl Fn(&[Option<D::Value>]) -> bool + Send + Sync + 'static,
31        label: impl Into<String>,
32    ) -> Self {
33        Self {
34            scope,
35            checker: Box::new(checker),
36            label: label.into(),
37        }
38    }
39}
40
41impl<D: Domain> Constraint<D> for LambdaConstraint<D> {
42    fn scope(&self) -> &[VarId] {
43        &self.scope
44    }
45    fn check(&self, assignment: &[Option<D::Value>]) -> bool {
46        (self.checker)(assignment)
47    }
48}