use std::collections::HashMap;
use crate::validation::rules::ValidationRule;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum InheritanceMode {
Override,
Merge,
ChildFirst,
ParentFirst,
}
impl InheritanceMode {
#[must_use]
pub const fn description(&self) -> &'static str {
match self {
Self::Override => "Child rules override parent rules completely",
Self::Merge => "All parent and child rules apply (union)",
Self::ChildFirst => "Child rules applied first, then parent rules",
Self::ParentFirst => "Parent rules applied first, then child rules",
}
}
}
#[derive(Debug, Clone)]
pub struct RuleMetadata {
pub rule: ValidationRule,
pub overrideable: bool,
pub inherited: bool,
pub source: String,
}
impl RuleMetadata {
pub fn new(rule: ValidationRule, source: impl Into<String>) -> Self {
Self {
rule,
overrideable: true,
inherited: false,
source: source.into(),
}
}
#[must_use]
pub const fn non_overrideable(mut self) -> Self {
self.overrideable = false;
self
}
#[must_use]
pub const fn as_inherited(mut self) -> Self {
self.inherited = true;
self
}
}
#[derive(Debug, Clone, Default)]
pub struct ValidationRuleRegistry {
pub(crate) rules_by_type: HashMap<String, Vec<RuleMetadata>>,
parent_types: HashMap<String, String>,
}
impl ValidationRuleRegistry {
#[must_use]
pub fn new() -> Self {
Self {
rules_by_type: HashMap::new(),
parent_types: HashMap::new(),
}
}
pub fn register_type(&mut self, type_name: impl Into<String>, rules: Vec<RuleMetadata>) {
self.rules_by_type.insert(type_name.into(), rules);
}
pub fn set_parent(&mut self, child_type: impl Into<String>, parent_type: impl Into<String>) {
self.parent_types.insert(child_type.into(), parent_type.into());
}
#[must_use]
pub fn get_rules(&self, type_name: &str, mode: InheritanceMode) -> Vec<RuleMetadata> {
let mut rules = Vec::new();
if let Some(parent_name) = self.parent_types.get(type_name) {
let parent_rules = self.get_rules(parent_name, mode);
rules.extend(parent_rules.iter().map(|r| r.clone().as_inherited()));
}
if let Some(own_rules) = self.rules_by_type.get(type_name) {
match mode {
InheritanceMode::Override => {
return own_rules.clone();
},
InheritanceMode::Merge => {
for own_rule in own_rules {
rules.push(own_rule.clone());
}
},
InheritanceMode::ChildFirst => {
let mut result = own_rules.clone();
result.extend(rules);
return result;
},
InheritanceMode::ParentFirst => {
rules.extend(own_rules.clone());
},
}
}
rules
}
#[must_use]
pub fn get_parent(&self, type_name: &str) -> Option<&str> {
self.parent_types.get(type_name).map(|s| s.as_str())
}
#[must_use]
pub fn has_parent(&self, type_name: &str) -> bool {
self.parent_types.contains_key(type_name)
}
}
#[must_use]
pub fn inherit_validation_rules(
parent_rules: &[ValidationRule],
child_rules: &[ValidationRule],
mode: InheritanceMode,
) -> Vec<ValidationRule> {
match mode {
InheritanceMode::Override => {
child_rules.to_vec()
},
InheritanceMode::Merge => {
let mut combined = parent_rules.to_vec();
combined.extend_from_slice(child_rules);
combined
},
InheritanceMode::ChildFirst => {
let mut combined = child_rules.to_vec();
combined.extend_from_slice(parent_rules);
combined
},
InheritanceMode::ParentFirst => {
let mut combined = parent_rules.to_vec();
combined.extend_from_slice(child_rules);
combined
},
}
}
pub fn validate_inheritance(
_child_name: &str,
parent_name: &str,
registry: &ValidationRuleRegistry,
) -> Result<(), String> {
if !registry.rules_by_type.contains_key(parent_name) {
return Err(format!("Parent type '{}' not found in validation registry", parent_name));
}
let mut visited = std::collections::HashSet::new();
let mut current = Some(parent_name.to_string());
while let Some(type_name) = current {
if visited.contains(&type_name) {
return Err(format!(
"Circular inheritance detected: '{}' inherits from itself",
type_name
));
}
visited.insert(type_name.clone());
current = registry.get_parent(&type_name).map(|s| s.to_string());
}
Ok(())
}