1use std::collections::HashMap;
29
30use crate::validation::rules::ValidationRule;
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34#[non_exhaustive]
35pub enum InheritanceMode {
36 Override,
38 Merge,
40 ChildFirst,
42 ParentFirst,
44}
45
46impl InheritanceMode {
47 pub const fn description(&self) -> &'static str {
49 match self {
50 Self::Override => "Child rules override parent rules completely",
51 Self::Merge => "All parent and child rules apply (union)",
52 Self::ChildFirst => "Child rules applied first, then parent rules",
53 Self::ParentFirst => "Parent rules applied first, then child rules",
54 }
55 }
56}
57
58#[derive(Debug, Clone)]
60pub struct RuleMetadata {
61 pub rule: ValidationRule,
63 pub overrideable: bool,
65 pub inherited: bool,
67 pub source: String,
69}
70
71impl RuleMetadata {
72 pub fn new(rule: ValidationRule, source: impl Into<String>) -> Self {
74 Self {
75 rule,
76 overrideable: true,
77 inherited: false,
78 source: source.into(),
79 }
80 }
81
82 pub const fn non_overrideable(mut self) -> Self {
84 self.overrideable = false;
85 self
86 }
87
88 pub const fn as_inherited(mut self) -> Self {
90 self.inherited = true;
91 self
92 }
93}
94
95#[derive(Debug, Clone, Default)]
97pub struct ValidationRuleRegistry {
98 rules_by_type: HashMap<String, Vec<RuleMetadata>>,
100 parent_types: HashMap<String, String>,
102}
103
104impl ValidationRuleRegistry {
105 pub fn new() -> Self {
107 Self {
108 rules_by_type: HashMap::new(),
109 parent_types: HashMap::new(),
110 }
111 }
112
113 pub fn register_type(&mut self, type_name: impl Into<String>, rules: Vec<RuleMetadata>) {
115 self.rules_by_type.insert(type_name.into(), rules);
116 }
117
118 pub fn set_parent(&mut self, child_type: impl Into<String>, parent_type: impl Into<String>) {
120 self.parent_types.insert(child_type.into(), parent_type.into());
121 }
122
123 pub fn get_rules(&self, type_name: &str, mode: InheritanceMode) -> Vec<RuleMetadata> {
125 let mut rules = Vec::new();
126
127 if let Some(parent_name) = self.parent_types.get(type_name) {
129 let parent_rules = self.get_rules(parent_name, mode);
130 rules.extend(parent_rules.iter().map(|r| r.clone().as_inherited()));
131 }
132
133 if let Some(own_rules) = self.rules_by_type.get(type_name) {
135 match mode {
136 InheritanceMode::Override => {
137 return own_rules.clone();
139 },
140 InheritanceMode::Merge => {
141 for own_rule in own_rules {
143 rules.push(own_rule.clone());
144 }
145 },
146 InheritanceMode::ChildFirst => {
147 let mut result = own_rules.clone();
149 result.extend(rules);
150 return result;
151 },
152 InheritanceMode::ParentFirst => {
153 rules.extend(own_rules.clone());
155 },
156 }
157 }
158
159 rules
160 }
161
162 pub fn get_parent(&self, type_name: &str) -> Option<&str> {
164 self.parent_types.get(type_name).map(|s| s.as_str())
165 }
166
167 pub fn has_parent(&self, type_name: &str) -> bool {
169 self.parent_types.contains_key(type_name)
170 }
171}
172
173pub fn inherit_validation_rules(
183 parent_rules: &[ValidationRule],
184 child_rules: &[ValidationRule],
185 mode: InheritanceMode,
186) -> Vec<ValidationRule> {
187 match mode {
188 InheritanceMode::Override => {
189 child_rules.to_vec()
191 },
192 InheritanceMode::Merge => {
193 let mut combined = parent_rules.to_vec();
195 combined.extend_from_slice(child_rules);
196 combined
197 },
198 InheritanceMode::ChildFirst => {
199 let mut combined = child_rules.to_vec();
201 combined.extend_from_slice(parent_rules);
202 combined
203 },
204 InheritanceMode::ParentFirst => {
205 let mut combined = parent_rules.to_vec();
207 combined.extend_from_slice(child_rules);
208 combined
209 },
210 }
211}
212
213pub fn validate_inheritance(
224 _child_name: &str,
225 parent_name: &str,
226 registry: &ValidationRuleRegistry,
227) -> Result<(), String> {
228 if !registry.rules_by_type.contains_key(parent_name) {
230 return Err(format!("Parent type '{}' not found in validation registry", parent_name));
231 }
232
233 let mut visited = std::collections::HashSet::new();
235 let mut current = Some(parent_name.to_string());
236
237 while let Some(type_name) = current {
238 if visited.contains(&type_name) {
239 return Err(format!(
240 "Circular inheritance detected: '{}' inherits from itself",
241 type_name
242 ));
243 }
244 visited.insert(type_name.clone());
245
246 current = registry.get_parent(&type_name).map(|s| s.to_string());
247 }
248
249 Ok(())
250}
251
252#[cfg(test)]
253mod tests {
254 #![allow(clippy::unwrap_used)] use super::*;
257
258 #[test]
259 fn test_override_mode() {
260 let parent = vec![
261 ValidationRule::Required,
262 ValidationRule::Length {
263 min: Some(5),
264 max: None,
265 },
266 ];
267 let child = vec![ValidationRule::Pattern {
268 pattern: "^[a-z]+$".to_string(),
269 message: None,
270 }];
271
272 let result = inherit_validation_rules(&parent, &child, InheritanceMode::Override);
273 assert_eq!(result.len(), 1);
274 assert!(matches!(result[0], ValidationRule::Pattern { .. }));
275 }
276
277 #[test]
278 fn test_merge_mode() {
279 let parent = vec![
280 ValidationRule::Required,
281 ValidationRule::Length {
282 min: Some(5),
283 max: None,
284 },
285 ];
286 let child = vec![ValidationRule::Pattern {
287 pattern: "^[a-z]+$".to_string(),
288 message: None,
289 }];
290
291 let result = inherit_validation_rules(&parent, &child, InheritanceMode::Merge);
292 assert_eq!(result.len(), 3);
293 }
294
295 #[test]
296 fn test_child_first_mode() {
297 let parent = vec![ValidationRule::Required];
298 let child = vec![ValidationRule::Pattern {
299 pattern: "^[a-z]+$".to_string(),
300 message: None,
301 }];
302
303 let result = inherit_validation_rules(&parent, &child, InheritanceMode::ChildFirst);
304 assert_eq!(result.len(), 2);
305 assert!(matches!(result[0], ValidationRule::Pattern { .. }));
306 assert!(matches!(result[1], ValidationRule::Required));
307 }
308
309 #[test]
310 fn test_parent_first_mode() {
311 let parent = vec![ValidationRule::Required];
312 let child = vec![ValidationRule::Pattern {
313 pattern: "^[a-z]+$".to_string(),
314 message: None,
315 }];
316
317 let result = inherit_validation_rules(&parent, &child, InheritanceMode::ParentFirst);
318 assert_eq!(result.len(), 2);
319 assert!(matches!(result[0], ValidationRule::Required));
320 assert!(matches!(result[1], ValidationRule::Pattern { .. }));
321 }
322
323 #[test]
324 fn test_registry_register_type() {
325 let mut registry = ValidationRuleRegistry::new();
326 let rules = vec![RuleMetadata::new(ValidationRule::Required, "UserInput")];
327 registry.register_type("UserInput", rules);
328
329 assert!(registry.rules_by_type.contains_key("UserInput"));
330 }
331
332 #[test]
333 fn test_registry_set_parent() {
334 let mut registry = ValidationRuleRegistry::new();
335 registry.set_parent("AdminUserInput", "UserInput");
336
337 assert_eq!(registry.get_parent("AdminUserInput"), Some("UserInput"));
338 }
339
340 #[test]
341 fn test_registry_has_parent() {
342 let mut registry = ValidationRuleRegistry::new();
343 registry.set_parent("ChildType", "ParentType");
344
345 assert!(registry.has_parent("ChildType"));
346 assert!(!registry.has_parent("ParentType"));
347 }
348
349 #[test]
350 fn test_registry_get_rules_with_merge() {
351 let mut registry = ValidationRuleRegistry::new();
352
353 let parent_rules = vec![RuleMetadata::new(ValidationRule::Required, "UserInput")];
354 registry.register_type("UserInput", parent_rules);
355
356 let child_rules = vec![RuleMetadata::new(
357 ValidationRule::Length {
358 min: Some(5),
359 max: None,
360 },
361 "AdminUserInput",
362 )];
363 registry.register_type("AdminUserInput", child_rules);
364 registry.set_parent("AdminUserInput", "UserInput");
365
366 let inherited = registry.get_rules("AdminUserInput", InheritanceMode::Merge);
367 assert_eq!(inherited.len(), 2);
368 }
369
370 #[test]
371 fn test_registry_get_rules_with_override() {
372 let mut registry = ValidationRuleRegistry::new();
373
374 let parent_rules = vec![RuleMetadata::new(ValidationRule::Required, "UserInput")];
375 registry.register_type("UserInput", parent_rules);
376
377 let child_rules = vec![RuleMetadata::new(
378 ValidationRule::Length {
379 min: Some(5),
380 max: None,
381 },
382 "AdminUserInput",
383 )];
384 registry.register_type("AdminUserInput", child_rules);
385 registry.set_parent("AdminUserInput", "UserInput");
386
387 let inherited = registry.get_rules("AdminUserInput", InheritanceMode::Override);
388 assert_eq!(inherited.len(), 1);
389 assert!(matches!(inherited[0].rule, ValidationRule::Length { .. }));
390 }
391
392 #[test]
393 fn test_validate_inheritance_success() {
394 let mut registry = ValidationRuleRegistry::new();
395 let parent_rules = vec![RuleMetadata::new(ValidationRule::Required, "UserInput")];
396 registry.register_type("UserInput", parent_rules);
397
398 let result = validate_inheritance("AdminUserInput", "UserInput", ®istry);
399 result.unwrap_or_else(|e| panic!("inheritance from registered parent should succeed: {e}"));
400 }
401
402 #[test]
403 fn test_validate_inheritance_parent_not_found() {
404 let registry = ValidationRuleRegistry::new();
405 let result = validate_inheritance("AdminUserInput", "NonExistent", ®istry);
406 assert!(result.is_err(), "inheritance from unknown parent should fail, got: {result:?}");
407 assert!(result.unwrap_err().contains("not found"));
408 }
409
410 #[test]
411 fn test_validate_inheritance_circular() {
412 let mut registry = ValidationRuleRegistry::new();
413
414 let user_rules = vec![RuleMetadata::new(ValidationRule::Required, "UserInput")];
415 registry.register_type("UserInput", user_rules);
416
417 let admin_rules = vec![RuleMetadata::new(
418 ValidationRule::Required,
419 "AdminUserInput",
420 )];
421 registry.register_type("AdminUserInput", admin_rules);
422
423 registry.set_parent("UserInput", "AdminUserInput");
424 registry.set_parent("AdminUserInput", "UserInput");
425
426 let result = validate_inheritance("UserInput", "AdminUserInput", ®istry);
427 assert!(result.is_err(), "circular inheritance should fail, got: {result:?}");
428 assert!(result.unwrap_err().contains("Circular"));
429 }
430
431 #[test]
432 fn test_multi_level_inheritance() {
433 let mut registry = ValidationRuleRegistry::new();
434
435 let grandparent_rules = vec![RuleMetadata::new(ValidationRule::Required, "BaseInput")];
437 registry.register_type("BaseInput", grandparent_rules);
438
439 let parent_rules = vec![RuleMetadata::new(
441 ValidationRule::Length {
442 min: Some(5),
443 max: None,
444 },
445 "UserInput",
446 )];
447 registry.register_type("UserInput", parent_rules);
448 registry.set_parent("UserInput", "BaseInput");
449
450 let child_rules = vec![RuleMetadata::new(
452 ValidationRule::Pattern {
453 pattern: "^[a-z]+$".to_string(),
454 message: None,
455 },
456 "AdminUserInput",
457 )];
458 registry.register_type("AdminUserInput", child_rules);
459 registry.set_parent("AdminUserInput", "UserInput");
460
461 let inherited = registry.get_rules("AdminUserInput", InheritanceMode::Merge);
462 assert_eq!(inherited.len(), 3);
464 }
465
466 #[test]
467 fn test_rule_metadata_non_overrideable() {
468 let rule = RuleMetadata::new(ValidationRule::Required, "UserInput").non_overrideable();
469 assert!(!rule.overrideable);
470 assert!(!rule.inherited);
471 }
472
473 #[test]
474 fn test_rule_metadata_as_inherited() {
475 let mut rule = RuleMetadata::new(ValidationRule::Required, "UserInput");
476 rule = rule.as_inherited();
477 assert!(rule.inherited);
478 assert!(rule.overrideable);
479 }
480
481 #[test]
482 fn test_inheritance_mode_description() {
483 assert!(!InheritanceMode::Override.description().is_empty());
484 assert!(!InheritanceMode::Merge.description().is_empty());
485 assert!(!InheritanceMode::ChildFirst.description().is_empty());
486 assert!(!InheritanceMode::ParentFirst.description().is_empty());
487 }
488
489 #[test]
490 fn test_complex_inheritance_scenario() {
491 let mut registry = ValidationRuleRegistry::new();
492
493 let base_rules = vec![
495 RuleMetadata::new(ValidationRule::Required, "BaseInput"),
496 RuleMetadata::new(
497 ValidationRule::Length {
498 min: Some(5),
499 max: None,
500 },
501 "BaseInput",
502 ),
503 ];
504 registry.register_type("BaseInput", base_rules);
505
506 let user_rules = vec![RuleMetadata::new(
508 ValidationRule::Pattern {
509 pattern: "^[a-z]+$".to_string(),
510 message: None,
511 },
512 "UserInput",
513 )];
514 registry.register_type("UserInput", user_rules);
515 registry.set_parent("UserInput", "BaseInput");
516
517 let admin_rules = vec![RuleMetadata::new(
519 ValidationRule::Enum {
520 values: vec!["admin".to_string(), "moderator".to_string()],
521 },
522 "AdminUserInput",
523 )];
524 registry.register_type("AdminUserInput", admin_rules);
525 registry.set_parent("AdminUserInput", "UserInput");
526
527 let inherited = registry.get_rules("AdminUserInput", InheritanceMode::Merge);
528 assert_eq!(inherited.len(), 4);
530 }
531
532 #[test]
533 fn test_empty_child_rules() {
534 let parent = vec![ValidationRule::Required];
535 let child: Vec<ValidationRule> = vec![];
536
537 let result = inherit_validation_rules(&parent, &child, InheritanceMode::Merge);
538 assert_eq!(result.len(), 1);
539 }
540
541 #[test]
542 fn test_empty_parent_rules() {
543 let parent: Vec<ValidationRule> = vec![];
544 let child = vec![ValidationRule::Required];
545
546 let result = inherit_validation_rules(&parent, &child, InheritanceMode::Merge);
547 assert_eq!(result.len(), 1);
548 }
549
550 #[test]
551 fn test_empty_both_rules() {
552 let parent: Vec<ValidationRule> = vec![];
553 let child: Vec<ValidationRule> = vec![];
554
555 let result = inherit_validation_rules(&parent, &child, InheritanceMode::Merge);
556 assert!(result.is_empty());
557 }
558}