Skip to main content

fix_engine/
registry.rs

1//! Registry of [`FixContext`] implementations, keyed by ruleset name.
2//!
3//! The registry maps Konveyor ruleset names to framework-specific LLM
4//! prompt contexts. When the fix engine encounters a ruleset, it looks
5//! up the matching context. If none is found, a generic fallback is used.
6
7use crate::context::{FixContext, GenericFixContext};
8use std::collections::HashMap;
9
10/// Registry that maps ruleset names to their [`FixContext`] implementations.
11pub struct FixContextRegistry {
12    contexts: HashMap<String, Box<dyn FixContext>>,
13    fallback: GenericFixContext,
14}
15
16impl FixContextRegistry {
17    /// Create a new empty registry with the generic fallback.
18    pub fn new() -> Self {
19        Self {
20            contexts: HashMap::new(),
21            fallback: GenericFixContext,
22        }
23    }
24
25    /// Register a [`FixContext`] implementation.
26    /// The context is keyed by its `ruleset_name()`.
27    pub fn register(&mut self, ctx: Box<dyn FixContext>) {
28        let name = ctx.ruleset_name().to_string();
29        self.contexts.insert(name, ctx);
30    }
31
32    /// Look up the [`FixContext`] for a given ruleset name.
33    /// Returns the generic fallback if no match is found.
34    pub fn get(&self, ruleset_name: &str) -> &dyn FixContext {
35        self.contexts
36            .get(ruleset_name)
37            .map(|b| b.as_ref())
38            .unwrap_or(&self.fallback)
39    }
40
41    /// Returns true if a context is registered for the given ruleset name.
42    pub fn has(&self, ruleset_name: &str) -> bool {
43        self.contexts.contains_key(ruleset_name)
44    }
45}
46
47impl Default for FixContextRegistry {
48    fn default() -> Self {
49        Self::new()
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56
57    struct TestContext {
58        name: String,
59    }
60
61    impl FixContext for TestContext {
62        fn ruleset_name(&self) -> &str {
63            &self.name
64        }
65
66        fn migration_description(&self) -> &str {
67            "test migration"
68        }
69
70        fn llm_constraints(&self) -> &[String] {
71            &[]
72        }
73    }
74
75    #[test]
76    fn test_registry_fallback() {
77        let registry = FixContextRegistry::new();
78        let ctx = registry.get("nonexistent");
79        assert_eq!(ctx.migration_description(), "code migration");
80    }
81
82    #[test]
83    fn test_registry_register_and_lookup() {
84        let mut registry = FixContextRegistry::new();
85        registry.register(Box::new(TestContext {
86            name: "test-rules".to_string(),
87        }));
88
89        let ctx = registry.get("test-rules");
90        assert_eq!(ctx.migration_description(), "test migration");
91        assert!(registry.has("test-rules"));
92        assert!(!registry.has("other-rules"));
93    }
94
95    #[test]
96    fn test_registry_unknown_returns_fallback() {
97        let mut registry = FixContextRegistry::new();
98        registry.register(Box::new(TestContext {
99            name: "test-rules".to_string(),
100        }));
101
102        let ctx = registry.get("unknown-rules");
103        assert_eq!(ctx.migration_description(), "code migration");
104    }
105}