aimx/info_library/
registry.rs1use std::sync::OnceLock;
2use std::collections::HashMap;
3use crate::info_library::FunctionCard;
4
5pub struct FunctionInfoRegistry {
10 cards: Vec<FunctionCard>,
12
13 by_identifier: HashMap<&'static str, usize>,
15
16 by_category: HashMap<&'static str, Vec<usize>>,
18
19 search_index: HashMap<String, Vec<usize>>,
21}
22
23impl FunctionInfoRegistry {
24 pub fn global() -> &'static Self {
29 static REGISTRY: OnceLock<FunctionInfoRegistry> = OnceLock::new();
30 REGISTRY.get_or_init(Self::initialize)
31 }
32
33 fn initialize() -> Self {
35 let mut cards = Vec::new();
36
37 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 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 by_identifier.insert(card.identifier, index);
58
59 for &category in card.categories {
61 by_category.entry(category).or_insert_with(Vec::new).push(index);
62 }
63
64 let searchable_text = format!("{} {} {}",
66 card.identifier,
67 card.brief,
68 card.description
69 ).to_lowercase();
70
71 for word in searchable_text.split_whitespace() {
73 let clean_word = word.trim_matches(|c: char| !c.is_alphanumeric());
75 if clean_word.len() > 2 { 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 pub fn get(&self, identifier: &str) -> Option<&FunctionCard> {
93 self.by_identifier.get(identifier).map(|&index| &self.cards[index])
94 }
95
96 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 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 pub fn categories(&self) -> Vec<&'static str> {
115 super::categories::FunctionCategory::all()
116 }
117
118 pub fn search(&self, query: &str) -> Vec<&FunctionCard> {
120 let query = query.to_lowercase();
121
122 for (identifier, &index) in &self.by_identifier {
124 if identifier.to_lowercase() == query {
125 return vec![&self.cards[index]];
126 }
127 }
128
129 let mut results = std::collections::HashSet::new();
131 for word in query.split_whitespace() {
132 if word.len() > 2 { if let Some(indices) = self.search_index.get(word) {
134 for &index in indices {
135 results.insert(index);
136 }
137 }
138 }
139 }
140
141 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) });
151
152 result_vec
153 }
154
155 pub fn all_functions(&self) -> Vec<&FunctionCard> {
157 self.cards.iter().collect()
158 }
159
160 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}