1use crate::types::{Event, Function};
11use dashmap::DashMap;
12use serde::{Deserialize, Serialize};
13use std::collections::HashMap;
14use std::sync::Arc;
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct EventField {
22 pub name: String,
23 #[serde(default)]
24 pub description: String,
25}
26
27#[derive(Debug, Clone)]
29pub struct MetadataSource {
30 pub extension: String,
31 pub functions_url: Option<String>,
32 pub enums_url: Option<String>,
33 pub events_url: Option<String>,
34}
35
36impl MetadataSource {
37 pub fn new(extension: impl Into<String>) -> Self {
39 Self {
40 extension: extension.into(),
41 functions_url: None,
42 enums_url: None,
43 events_url: None,
44 }
45 }
46
47 pub fn with_functions(mut self, url: impl Into<String>) -> Self {
49 self.functions_url = Some(url.into());
50 self
51 }
52
53 pub fn with_enums(mut self, url: impl Into<String>) -> Self {
55 self.enums_url = Some(url.into());
56 self
57 }
58
59 pub fn with_events(mut self, url: impl Into<String>) -> Self {
61 self.events_url = Some(url.into());
62 self
63 }
64}
65
66#[derive(Debug, Clone)]
71pub enum MetadataError {
72 NetworkError(String),
73 ParseError(String),
74 NotFound(String),
75 InvalidData(String),
76 CacheError(String),
77}
78
79impl std::fmt::Display for MetadataError {
80 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
81 match self {
82 Self::NetworkError(e) => write!(f, "Network error: {}", e),
83 Self::ParseError(e) => write!(f, "Parse error: {}", e),
84 Self::NotFound(e) => write!(f, "Not found: {}", e),
85 Self::InvalidData(e) => write!(f, "Invalid data: {}", e),
86 Self::CacheError(e) => write!(f, "Cache error: {}", e),
87 }
88 }
89}
90
91impl std::error::Error for MetadataError {}
92
93pub type Result<T> = std::result::Result<T, MetadataError>;
94
95#[derive(Default)]
100struct TrieNode {
101 children: HashMap<char, Box<TrieNode>>,
102 value: Option<Arc<Function>>,
103}
104
105#[derive(Default)]
107pub struct FunctionTrie {
108 root: TrieNode,
109 count: usize,
110}
111
112impl FunctionTrie {
113 #[inline]
115 pub fn new() -> Self {
116 Self::default()
117 }
118
119 pub fn insert(&mut self, key: &str, func: Arc<Function>) {
121 let mut node = &mut self.root;
122
123 for ch in key.to_lowercase().chars() {
125 node = node
126 .children
127 .entry(ch)
128 .or_insert_with(|| Box::new(TrieNode::default()));
129 }
130
131 if node.value.is_none() {
132 self.count += 1;
133 }
134 node.value = Some(func);
135 }
136
137 pub fn get_exact(&self, key: &str) -> Option<Arc<Function>> {
139 let mut node = &self.root;
140
141 for ch in key.to_lowercase().chars() {
142 match node.children.get(&ch) {
143 Some(next) => node = next,
144 None => return None,
145 }
146 }
147
148 node.value.clone()
149 }
150
151 pub fn get_prefix(&self, text: &str) -> Option<(String, Arc<Function>)> {
153 let chars: Vec<char> = text.to_lowercase().chars().collect();
154 let mut best_match: Option<(String, Arc<Function>)> = None;
155
156 for start in 0..chars.len() {
157 let mut node = &self.root;
158 let mut matched = String::with_capacity(chars.len() - start);
159
160 for &ch in &chars[start..] {
161 match node.children.get(&ch) {
162 Some(next) => {
163 matched.push(ch);
164 node = next;
165
166 if let Some(func) = &node.value {
167 best_match = Some((matched.clone(), func.clone()));
168 }
169 }
170 None => break,
171 }
172 }
173 }
174
175 best_match
176 }
177
178 pub fn get_completions(&self, prefix: &str) -> Vec<Arc<Function>> {
180 let mut node = &self.root;
181
182 for ch in prefix.to_lowercase().chars() {
184 match node.children.get(&ch) {
185 Some(next) => node = next,
186 None => return Vec::new(),
187 }
188 }
189
190 let mut results = Vec::new();
192 self.collect_all(node, &mut results);
193 results
194 }
195
196 fn collect_all(&self, node: &TrieNode, results: &mut Vec<Arc<Function>>) {
197 if let Some(func) = &node.value {
198 results.push(func.clone());
199 }
200
201 for child in node.children.values() {
202 self.collect_all(child, results);
203 }
204 }
205
206 pub fn all_functions(&self) -> Vec<Arc<Function>> {
208 let mut results = Vec::with_capacity(self.count);
209 self.collect_all(&self.root, &mut results);
210 results
211 }
212
213 #[inline]
215 pub fn len(&self) -> usize {
216 self.count
217 }
218
219 #[inline]
221 pub fn is_empty(&self) -> bool {
222 self.count == 0
223 }
224
225 pub fn clear(&mut self) {
227 self.root = TrieNode::default();
228 self.count = 0;
229 }
230}
231
232pub struct Fetcher {
238 client: reqwest::Client,
239}
240
241impl Fetcher {
242 pub fn new() -> Self {
244 #[cfg(not(target_arch = "wasm32"))]
245 let client = reqwest::Client::builder()
246 .timeout(std::time::Duration::from_secs(30))
247 .build()
248 .unwrap_or_else(|_| reqwest::Client::new());
249
250 #[cfg(target_arch = "wasm32")]
251 let client = reqwest::Client::builder()
252 .build()
253 .unwrap_or_else(|_| reqwest::Client::new());
254
255 Self { client }
256 }
257
258 pub async fn fetch_json<T: serde::de::DeserializeOwned>(&self, url: &str) -> Result<T> {
260 let response =
262 self.client.get(url).send().await.map_err(|e| {
263 MetadataError::NetworkError(format!("Failed to fetch {}: {}", url, e))
264 })?;
265
266 let status = response.status();
268 if status == reqwest::StatusCode::NOT_FOUND {
269 return Err(MetadataError::NotFound(format!("URL not found: {}", url)));
270 }
271
272 if !status.is_success() {
273 return Err(MetadataError::NetworkError(format!(
274 "HTTP {}: {}",
275 status, url
276 )));
277 }
278
279 let text = response.text().await.map_err(|e| {
281 MetadataError::NetworkError(format!("Failed to read response from {}: {}", url, e))
282 })?;
283
284 serde_json::from_str(&text).map_err(|e| {
285 MetadataError::ParseError(format!("Failed to parse JSON from {}: {}", url, e))
286 })
287 }
288
289 pub async fn fetch_functions(&self, url: &str, extension: String) -> Result<Vec<Function>> {
291 let mut functions: Vec<Function> = self.fetch_json(url).await?;
292
293 for func in &mut functions {
295 func.extension = Some(extension.clone());
296 func.source_url = Some(url.to_string());
297 }
298
299 Ok(functions)
300 }
301
302 pub async fn fetch_enums(&self, url: &str) -> Result<HashMap<String, Vec<String>>> {
304 self.fetch_json(url).await
305 }
306
307 pub async fn fetch_events(&self, url: &str) -> Result<Vec<Event>> {
309 self.fetch_json(url).await
310 }
311}
312
313impl Default for Fetcher {
314 fn default() -> Self {
315 Self::new()
316 }
317}
318
319pub struct MetadataManager {
325 trie: std::sync::RwLock<FunctionTrie>,
326 enums: DashMap<String, Vec<String>>,
327 events: DashMap<String, Event>,
328 sources: std::sync::RwLock<Vec<MetadataSource>>,
329 fetcher: Fetcher,
330}
331
332impl MetadataManager {
333 pub fn new() -> Self {
335 Self {
336 trie: std::sync::RwLock::new(FunctionTrie::new()),
337 enums: DashMap::new(),
338 events: DashMap::new(),
339 sources: std::sync::RwLock::new(Vec::new()),
340 fetcher: Fetcher::new(),
341 }
342 }
343
344 pub fn add_source(&self, source: MetadataSource) {
346 self.sources.write().unwrap().push(source);
347 }
348
349 pub async fn fetch_all(&self) -> Result<FetchStats> {
351 let sources = self.sources.read().unwrap().clone();
352
353 let mut total_functions = 0;
354 let mut total_enums = 0;
355 let mut total_events = 0;
356 let mut errors = Vec::new();
357
358 for source in sources {
359 if let Some(url) = &source.functions_url {
361 match self
362 .fetcher
363 .fetch_functions(url, source.extension.clone())
364 .await
365 {
366 Ok(functions) => {
367 total_functions += functions.len();
368 self.add_functions(functions);
369 }
370 Err(e) => {
371 errors.push(format!("Functions from {}: {}", source.extension, e));
372 }
373 }
374 }
375
376 if let Some(url) = &source.enums_url {
378 match self.fetcher.fetch_enums(url).await {
379 Ok(enums) => {
380 total_enums += enums.len();
381 for (name, values) in enums {
382 self.enums.insert(name, values);
383 }
384 }
385 Err(e) => {
386 if !matches!(e, MetadataError::NotFound(_)) {
388 errors.push(format!("Enums from {}: {}", source.extension, e));
389 }
390 }
391 }
392 }
393
394 if let Some(url) = &source.events_url {
396 match self.fetcher.fetch_events(url).await {
397 Ok(events) => {
398 total_events += events.len();
399 for event in events {
400 self.events.insert(event.name.clone(), event);
401 }
402 }
403 Err(e) => {
404 if !matches!(e, MetadataError::NotFound(_)) {
406 errors.push(format!("Events from {}: {}", source.extension, e));
407 }
408 }
409 }
410 }
411 }
412
413 Ok(FetchStats {
414 functions: total_functions,
415 enums: total_enums,
416 events: total_events,
417 errors,
418 })
419 }
420
421 fn add_functions(&self, functions: Vec<Function>) {
423 let mut trie = self.trie.write().unwrap();
424
425 for func in functions {
426 let arc_func = Arc::new(func.clone());
427
428 trie.insert(&func.name, arc_func.clone());
430
431 if let Some(aliases) = &func.aliases {
433 for alias in aliases {
434 let alias_name = if alias.starts_with('$') {
435 alias.clone()
436 } else {
437 format!("${}", alias)
438 };
439
440 let mut alias_func = (*arc_func).clone();
442 alias_func.name = alias_name.clone();
443 trie.insert(&alias_name, Arc::new(alias_func));
444 }
445 }
446 }
447 }
448
449 #[inline]
451 pub fn get_exact(&self, name: &str) -> Option<Arc<Function>> {
452 self.trie.read().unwrap().get_exact(name)
453 }
454
455 #[inline]
457 pub fn get_prefix(&self, text: &str) -> Option<(String, Arc<Function>)> {
458 self.trie.read().unwrap().get_prefix(text)
459 }
460
461 pub fn get(&self, name: &str) -> Option<Arc<Function>> {
463 let trie = self.trie.read().unwrap();
464
465 if let Some(func) = trie.get_exact(name) {
467 return Some(func);
468 }
469
470 trie.get_prefix(name).map(|(_, func)| func)
472 }
473
474 pub fn get_with_match(&self, name: &str) -> Option<(String, Arc<Function>)> {
476 let trie = self.trie.read().unwrap();
477
478 if let Some(func) = trie.get_exact(name) {
480 return Some((name.to_string(), func));
481 }
482
483 trie.get_prefix(name)
485 }
486
487 pub fn get_many(&self, names: &[&str]) -> Vec<Option<Arc<Function>>> {
489 names.iter().map(|name| self.get(name)).collect()
490 }
491
492 #[inline]
494 pub fn get_completions(&self, prefix: &str) -> Vec<Arc<Function>> {
495 self.trie.read().unwrap().get_completions(prefix)
496 }
497
498 #[inline]
500 pub fn all_functions(&self) -> Vec<Arc<Function>> {
501 self.trie.read().unwrap().all_functions()
502 }
503
504 #[inline]
506 pub fn get_enum(&self, name: &str) -> Option<Vec<String>> {
507 self.enums.get(name).map(|v| v.clone())
508 }
509
510 pub fn all_enums(&self) -> HashMap<String, Vec<String>> {
512 self.enums
513 .iter()
514 .map(|e| (e.key().clone(), e.value().clone()))
515 .collect()
516 }
517
518 #[inline]
520 pub fn get_event(&self, name: &str) -> Option<Event> {
521 self.events.get(name).map(|v| v.clone())
522 }
523
524 pub fn all_events(&self) -> Vec<Event> {
526 self.events.iter().map(|e| e.value().clone()).collect()
527 }
528
529 #[inline]
531 pub fn function_count(&self) -> usize {
532 self.trie.read().unwrap().len()
533 }
534
535 #[inline]
537 pub fn enum_count(&self) -> usize {
538 self.enums.len()
539 }
540
541 #[inline]
543 pub fn event_count(&self) -> usize {
544 self.events.len()
545 }
546
547 pub fn clear(&self) {
549 self.trie.write().unwrap().clear();
550 self.enums.clear();
551 self.events.clear();
552 }
553}
554
555impl Default for MetadataManager {
556 fn default() -> Self {
557 Self::new()
558 }
559}
560
561#[derive(Debug, Clone)]
563pub struct FetchStats {
564 pub functions: usize,
565 pub enums: usize,
566 pub events: usize,
567 pub errors: Vec<String>,
568}
569
570impl std::fmt::Display for FetchStats {
571 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
572 write!(
573 f,
574 "Fetched {} functions, {} enums, {} events",
575 self.functions, self.enums, self.events
576 )?;
577
578 if !self.errors.is_empty() {
579 write!(f, " ({} errors)", self.errors.len())?;
580 }
581
582 Ok(())
583 }
584}
585
586#[derive(Debug, Serialize, Deserialize)]
592pub struct MetadataCache {
593 pub functions: Vec<Function>,
594 pub enums: HashMap<String, Vec<String>>,
595 pub events: Vec<Event>,
596 pub version: u32,
597}
598
599impl MetadataCache {
600 const VERSION: u32 = 1;
601
602 pub fn new(
604 functions: Vec<Function>,
605 enums: HashMap<String, Vec<String>>,
606 events: Vec<Event>,
607 ) -> Self {
608 Self {
609 functions,
610 enums,
611 events,
612 version: Self::VERSION,
613 }
614 }
615}
616
617impl MetadataManager {
618 pub fn export_cache(&self) -> MetadataCache {
620 MetadataCache::new(
621 self.all_functions().iter().map(|f| (**f).clone()).collect(),
622 self.all_enums(),
623 self.all_events(),
624 )
625 }
626
627 pub fn import_cache(&self, cache: MetadataCache) -> Result<()> {
629 if cache.version != MetadataCache::VERSION {
630 return Err(MetadataError::CacheError(format!(
631 "Incompatible cache version: expected {}, got {}",
632 MetadataCache::VERSION,
633 cache.version
634 )));
635 }
636
637 self.clear();
639
640 self.add_functions(cache.functions);
642
643 for (name, values) in cache.enums {
645 self.enums.insert(name, values);
646 }
647
648 for event in cache.events {
650 self.events.insert(event.name.clone(), event);
651 }
652
653 Ok(())
654 }
655
656 pub fn cache_to_json(&self) -> Result<String> {
658 let cache = self.export_cache();
659 serde_json::to_string(&cache)
660 .map_err(|e| MetadataError::CacheError(format!("Serialization failed: {}", e)))
661 }
662
663 pub fn cache_from_json(&self, json: &str) -> Result<()> {
665 let cache: MetadataCache = serde_json::from_str(json)
666 .map_err(|e| MetadataError::CacheError(format!("Deserialization failed: {}", e)))?;
667 self.import_cache(cache)
668 }
669}
670
671#[cfg(not(target_arch = "wasm32"))]
676impl MetadataManager {
677 pub fn save_cache_to_file(&self, path: impl AsRef<std::path::Path>) -> Result<()> {
679 use std::io::Write;
680
681 let json = self.cache_to_json()?;
682 let mut file = std::fs::File::create(path)
683 .map_err(|e| MetadataError::CacheError(format!("Failed to create file: {}", e)))?;
684
685 file.write_all(json.as_bytes())
686 .map_err(|e| MetadataError::CacheError(format!("Failed to write file: {}", e)))?;
687
688 Ok(())
689 }
690
691 pub fn load_cache_from_file(&self, path: impl AsRef<std::path::Path>) -> Result<()> {
693 let json = std::fs::read_to_string(path)
694 .map_err(|e| MetadataError::CacheError(format!("Failed to read file: {}", e)))?;
695
696 self.cache_from_json(&json)
697 }
698}
699
700pub fn github_source(extension: impl Into<String>, repo: &str, branch: &str) -> MetadataSource {
706 let base = format!("https://raw.githubusercontent.com/{}/{}/", repo, branch);
707
708 MetadataSource::new(extension)
709 .with_functions(format!("{}functions.json", base))
710 .with_enums(format!("{}enums.json", base))
711 .with_events(format!("{}events.json", base))
712}
713
714pub fn custom_source(extension: impl Into<String>) -> MetadataSource {
716 MetadataSource::new(extension)
717}