Skip to main content

configbuilder_pattern_substitution/
composite_policy.rs

1use crate::{SubstitutionError, SubstitutionPolicy};
2
3/// Combines multiple [`SubstitutionPolicy`] implementations with AND logic.
4pub struct CompositePolicy {
5    policies: Vec<Box<dyn SubstitutionPolicy>>,
6}
7
8impl CompositePolicy {
9    /// Create a composite policy from the supplied policy list.
10    pub fn new(policies: Vec<Box<dyn SubstitutionPolicy>>) -> Self {
11        Self { policies }
12    }
13}
14
15impl std::fmt::Debug for CompositePolicy {
16    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17        f.debug_struct("CompositePolicy")
18            .field("policy_count", &self.policies.len())
19            .finish()
20    }
21}
22
23impl SubstitutionPolicy for CompositePolicy {
24    fn validate(&self, var_name: &str) -> Result<(), SubstitutionError> {
25        let mut reasons = Vec::new();
26        for policy in &self.policies {
27            if let Err(SubstitutionError::VariableRejected { reason, .. }) =
28                policy.validate(var_name)
29            {
30                reasons.push(reason);
31            }
32        }
33        if reasons.is_empty() {
34            Ok(())
35        } else {
36            Err(SubstitutionError::VariableRejected {
37                var_name: var_name.to_string(),
38                reason: reasons.join(" AND "),
39                policy: self.description(),
40            })
41        }
42    }
43
44    fn description(&self) -> String {
45        format!(
46            "Composite({})",
47            self.policies
48                .iter()
49                .map(|p| p.description())
50                .collect::<Vec<_>>()
51                .join(" AND ")
52        )
53    }
54}