solverforge-solver 0.15.0

Solver engine for SolverForge
Documentation
use super::{
    ScalarAssignmentDeclaration, ScalarAssignmentRule, ScalarCandidateProvider, ScalarTarget,
};

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ScalarGroupLimits {
    pub value_candidate_limit: Option<usize>,
    pub group_candidate_limit: Option<usize>,
    pub max_moves_per_step: Option<usize>,
    pub max_augmenting_depth: Option<usize>,
    pub max_rematch_size: Option<usize>,
}

impl ScalarGroupLimits {
    pub const fn new() -> Self {
        Self {
            value_candidate_limit: None,
            group_candidate_limit: None,
            max_moves_per_step: None,
            max_augmenting_depth: None,
            max_rematch_size: None,
        }
    }
}

impl Default for ScalarGroupLimits {
    fn default() -> Self {
        Self::new()
    }
}

pub struct ScalarGroup<S> {
    group_name: &'static str,
    targets: Vec<ScalarTarget<S>>,
    kind: ScalarGroupKind<S>,
    limits: ScalarGroupLimits,
}

pub(crate) enum ScalarGroupKind<S> {
    Candidates {
        candidate_provider: ScalarCandidateProvider<S>,
    },
    Assignment(ScalarAssignmentDeclaration<S>),
}

impl<S> Clone for ScalarGroupKind<S> {
    fn clone(&self) -> Self {
        *self
    }
}

impl<S> Copy for ScalarGroupKind<S> {}

impl<S> Clone for ScalarGroup<S> {
    fn clone(&self) -> Self {
        Self {
            group_name: self.group_name,
            targets: self.targets.clone(),
            kind: self.kind,
            limits: self.limits,
        }
    }
}

impl<S> ScalarGroup<S> {
    pub fn candidates(
        group_name: &'static str,
        targets: Vec<ScalarTarget<S>>,
        candidate_provider: ScalarCandidateProvider<S>,
    ) -> Self {
        Self {
            group_name,
            targets,
            kind: ScalarGroupKind::Candidates { candidate_provider },
            limits: ScalarGroupLimits::new(),
        }
    }

    pub fn assignment(group_name: &'static str, target: ScalarTarget<S>) -> Self {
        Self {
            group_name,
            targets: vec![target],
            kind: ScalarGroupKind::Assignment(ScalarAssignmentDeclaration::default()),
            limits: ScalarGroupLimits::new(),
        }
    }

    pub fn with_required_entity(mut self, required_entity: fn(&S, usize) -> bool) -> Self {
        self.assignment_mut().required_entity = Some(required_entity);
        self
    }

    pub fn with_capacity_key(
        mut self,
        capacity_key: fn(&S, usize, usize) -> Option<usize>,
    ) -> Self {
        self.assignment_mut().capacity_key = Some(capacity_key);
        self
    }

    pub fn with_assignment_rule(mut self, assignment_rule: ScalarAssignmentRule<S>) -> Self {
        self.assignment_mut().assignment_rule = Some(assignment_rule);
        self
    }

    pub fn with_position_key(mut self, position_key: fn(&S, usize) -> i64) -> Self {
        self.assignment_mut().position_key = Some(position_key);
        self
    }

    pub fn with_sequence_key(
        mut self,
        sequence_key: fn(&S, usize, usize) -> Option<usize>,
    ) -> Self {
        self.assignment_mut().sequence_key = Some(sequence_key);
        self
    }

    pub fn with_entity_order(mut self, entity_order: fn(&S, usize) -> i64) -> Self {
        self.assignment_mut().entity_order = Some(entity_order);
        self
    }

    pub fn with_value_order(mut self, value_order: fn(&S, usize, usize) -> i64) -> Self {
        self.assignment_mut().value_order = Some(value_order);
        self
    }

    pub fn with_limits(mut self, limits: ScalarGroupLimits) -> Self {
        self.limits = limits;
        self
    }

    fn assignment_mut(&mut self) -> &mut ScalarAssignmentDeclaration<S> {
        let ScalarGroupKind::Assignment(declaration) = &mut self.kind else {
            panic!(
                "scalar group `{}` is candidate-backed; assignment hooks require ScalarGroup::assignment",
                self.group_name
            );
        };
        declaration
    }

    #[doc(hidden)]
    #[inline]
    pub fn group_name(&self) -> &'static str {
        self.group_name
    }

    #[doc(hidden)]
    #[inline]
    pub fn targets(&self) -> &[ScalarTarget<S>] {
        &self.targets
    }

    #[doc(hidden)]
    #[inline]
    pub(crate) fn kind(&self) -> ScalarGroupKind<S> {
        self.kind
    }

    #[doc(hidden)]
    #[inline]
    pub fn limits(&self) -> ScalarGroupLimits {
        self.limits
    }
}

impl<S> std::fmt::Debug for ScalarGroup<S> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("ScalarGroup")
            .field("group_name", &self.group_name)
            .field("target_count", &self.targets.len())
            .field(
                "kind",
                match self.kind {
                    ScalarGroupKind::Assignment(_) => &"assignment",
                    ScalarGroupKind::Candidates { .. } => &"candidates",
                },
            )
            .field("limits", &self.limits)
            .finish_non_exhaustive()
    }
}