Skip to main content

csp_solver/constraint/
dispatch.rs

1//! ConstraintEnum: devirtualized dispatch for hot-path constraints.
2
3use crate::domain::Domain;
4use crate::variable::Variable;
5
6use super::all_different::AllDifferent;
7use super::all_different_except::AllDifferentExcept;
8use super::not_equal::NotEqual;
9use super::traits::{Constraint, Revision, VarId};
10
11/// Enum-dispatched constraint storage. Avoids vtable indirection for built-in types.
12///
13/// There is deliberately no `Lambda` variant: every closure-based constraint
14/// (`add_equals`, `add_less_than`, `add_greater_than`, and external
15/// `LambdaConstraint`s) enters through [`Custom`](Self::Custom), which boxes
16/// the `dyn Constraint`. A devirtualized `Lambda` arm carried zero
17/// construction sites (Pass-1 R1) and was excised; W10 may re-introduce it
18/// behind profiling if the boxed dispatch shows up hot.
19pub enum ConstraintEnum<D: Domain> {
20    NotEqual(NotEqual),
21    AllDifferent(AllDifferent),
22    AllDifferentExcept(AllDifferentExcept<D::Value>),
23    Custom(Box<dyn Constraint<D>>),
24}
25
26impl<D: Domain> std::fmt::Debug for ConstraintEnum<D> {
27    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28        match self {
29            Self::NotEqual(c) => c.fmt(f),
30            Self::AllDifferent(c) => c.fmt(f),
31            Self::AllDifferentExcept(c) => c.fmt(f),
32            Self::Custom(c) => c.fmt(f),
33        }
34    }
35}
36
37impl<D: Domain> ConstraintEnum<D>
38where
39    D::Value: PartialEq,
40{
41    #[inline]
42    pub fn scope(&self) -> &[VarId] {
43        match self {
44            Self::NotEqual(c) => &c.scope,
45            Self::AllDifferent(c) => &c.scope,
46            Self::AllDifferentExcept(c) => &c.scope,
47            Self::Custom(c) => c.scope(),
48        }
49    }
50
51    #[inline]
52    pub fn check(&self, assignment: &[Option<D::Value>]) -> bool {
53        match self {
54            Self::NotEqual(c) => c.check_impl(assignment),
55            Self::AllDifferent(c) => c.check_impl(assignment),
56            Self::AllDifferentExcept(c) => c.check_impl(assignment),
57            Self::Custom(c) => c.check(assignment),
58        }
59    }
60}
61
62impl<D: Domain> ConstraintEnum<D>
63where
64    D::Value: PartialEq + 'static,
65{
66    #[inline]
67    pub fn revise(&self, vars: &mut [Variable<D>], depth: usize) -> Revision {
68        match self {
69            Self::NotEqual(c) => c.revise_impl(vars, depth),
70            Self::AllDifferent(c) => c.revise_impl(vars, depth),
71            Self::AllDifferentExcept(c) => c.revise_impl(vars, depth),
72            Self::Custom(c) => c.revise(vars, depth),
73        }
74    }
75}