aimx/info_library/
registry.rs

1use std::sync::OnceLock;
2use std::collections::HashMap;
3use crate::info_library::FunctionCard;
4
5/// Global registry providing access to all function documentation.
6/// 
7/// Uses static initialization with OnceLock for thread-safe singleton access.
8/// Provides efficient lookup by identifier and category.
9pub struct FunctionInfoRegistry {
10    /// All function cards in insertion order
11    cards: Vec<FunctionCard>,
12    
13    /// Map from function identifier to card index
14    by_identifier: HashMap<&'static str, usize>,
15    
16    /// Map from category name to list of card indices
17    by_category: HashMap<&'static str, Vec<usize>>,
18    
19    /// Search index for text-based lookup
20    search_index: HashMap<String, Vec<usize>>,
21}
22
23impl FunctionInfoRegistry {
24    /// Get the global singleton instance.
25    /// 
26    /// Uses OnceLock for lazy initialization - first call builds the registry,
27    /// subsequent calls return the cached instance.
28    pub fn global() -> &'static Self {
29        static REGISTRY: OnceLock<FunctionInfoRegistry> = OnceLock::new();
30        REGISTRY.get_or_init(Self::initialize)
31    }
32    
33    /// Initialize the registry with all function documentation.
34    fn initialize() -> Self {
35        let mut cards = Vec::new();
36        
37        // Build cards from all modules - these functions will be created
38        // in subsequent sub-plans as each module is documented
39        cards.extend(Self::build_text_cards());
40        cards.extend(Self::build_math_cards());
41        cards.extend(Self::build_business_cards());
42        cards.extend(Self::build_date_cards());
43        cards.extend(Self::build_collection_cards());
44        cards.extend(Self::build_statistical_cards());
45        cards.extend(Self::build_functional_cards());
46        cards.extend(Self::build_set_cards());
47        cards.extend(Self::build_task_cards());
48        cards.extend(Self::build_misc_cards());
49        
50        // Build lookup indices
51        let mut by_identifier = HashMap::new();
52        let mut by_category = HashMap::new();
53        let mut search_index = HashMap::new();
54        
55        for (index, card) in cards.iter().enumerate() {
56            // Identifier index
57            by_identifier.insert(card.identifier, index);
58            
59            // Category index
60            for &category in card.categories {
61                by_category.entry(category).or_insert_with(Vec::new).push(index);
62            }
63            
64            // Search index
65            let searchable_text = format!("{} {} {}", 
66                card.identifier, 
67                card.brief, 
68                card.description
69            ).to_lowercase();
70            
71            // Index by individual words
72            for word in searchable_text.split_whitespace() {
73                // Remove punctuation from the word
74                let clean_word = word.trim_matches(|c: char| !c.is_alphanumeric());
75                if clean_word.len() > 2 { // Skip very short words
76                    search_index.entry(clean_word.to_string())
77                        .or_insert_with(Vec::new)
78                        .push(index);
79                }
80            }
81        }
82        
83        Self {
84            cards,
85            by_identifier,
86            by_category,
87            search_index,
88        }
89    }
90    
91    /// Get function card by identifier.
92    pub fn get(&self, identifier: &str) -> Option<&FunctionCard> {
93        self.by_identifier.get(identifier).map(|&index| &self.cards[index])
94    }
95    
96    /// Get function card by identifier with error handling.
97    pub fn get_required(&self, identifier: &str) -> Result<&FunctionCard, String> {
98        self.get(identifier)
99            .ok_or_else(|| format!("Function '{}' not found in registry", identifier))
100    }
101    
102    /// Get all functions in a specific category.
103    pub fn by_category(&self, category: &str) -> Vec<&FunctionCard> {
104        self.by_category.get(category)
105            .map(|indices| {
106                indices.iter()
107                    .map(|&i| &self.cards[i])
108                    .collect()
109            })
110            .unwrap_or_default()
111    }
112    
113    /// Get all available categories.
114    pub fn categories(&self) -> Vec<&'static str> {
115        super::categories::FunctionCategory::all()
116    }
117    
118    /// Search functions by query string.
119    pub fn search(&self, query: &str) -> Vec<&FunctionCard> {
120        let query = query.to_lowercase();
121        
122        // Direct identifier match (case-insensitive)
123        for (identifier, &index) in &self.by_identifier {
124            if identifier.to_lowercase() == query {
125                return vec![&self.cards[index]];
126            }
127        }
128        
129        // Search by words in identifier, brief, and description
130        let mut results = std::collections::HashSet::new();
131        for word in query.split_whitespace() {
132            if word.len() > 2 { // Skip very short words
133                if let Some(indices) = self.search_index.get(word) {
134                    for &index in indices {
135                        results.insert(index);
136                    }
137                }
138            }
139        }
140        
141        // Sort results by relevance (identifier matches first)
142        let mut result_vec: Vec<_> = results.into_iter()
143            .map(|index| &self.cards[index])
144            .collect();
145        
146        result_vec.sort_by(|a, b| {
147            let a_match = a.identifier.to_lowercase().contains(&query);
148            let b_match = b.identifier.to_lowercase().contains(&query);
149            b_match.cmp(&a_match) // Prioritize identifier matches
150        });
151        
152        result_vec
153    }
154    
155    /// Get all functions.
156    pub fn all_functions(&self) -> Vec<&FunctionCard> {
157        self.cards.iter().collect()
158    }
159    
160    /// Get total function count.
161    pub fn count(&self) -> usize {
162        self.cards.len()
163    }
164    
165    fn build_text_cards() -> Vec<FunctionCard> { 
166        super::text_cards::TEXT_CARDS.to_vec()
167    }
168    fn build_math_cards() -> Vec<FunctionCard> { 
169        super::math_cards::MATH_CARDS.to_vec()
170    }
171    fn build_business_cards() -> Vec<FunctionCard> { 
172        super::business_cards::BUSINESS_CARDS.to_vec()
173    }
174    fn build_date_cards() -> Vec<FunctionCard> { 
175        super::date_cards::DATE_CARDS.to_vec()
176    }
177    fn build_collection_cards() -> Vec<FunctionCard> { 
178        super::collection_cards::COLLECTION_CARDS.to_vec()
179    }
180    fn build_statistical_cards() -> Vec<FunctionCard> { 
181        super::statistical_cards::STATISTICAL_CARDS.to_vec()
182    }
183    fn build_functional_cards() -> Vec<FunctionCard> { 
184        super::functional_cards::FUNCTIONAL_CARDS.iter().map(|&card| card.clone()).collect()
185    }
186    fn build_set_cards() -> Vec<FunctionCard> { 
187        super::set_cards::SET_CARDS.to_vec()
188    }
189    fn build_task_cards() -> Vec<FunctionCard> { 
190        super::task_cards::TASK_CARDS.to_vec()
191    }
192    fn build_misc_cards() -> Vec<FunctionCard> { 
193        super::misc_cards::get_misc_function_cards()
194    }
195}