Skip to main content

fact_tools/
templates.rs

1//! Cognitive template system for FACT
2
3use crate::engine::{Operation, ProcessingStep, Transform, Analysis, Filter, Aggregation};
4use ahash::AHashMap;
5use serde::{Deserialize, Serialize};
6use parking_lot::RwLock;
7use std::sync::Arc;
8
9/// A cognitive template for processing
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct Template {
12    /// Unique template identifier
13    pub id: String,
14    
15    /// Human-readable name
16    pub name: String,
17    
18    /// Template description
19    pub description: String,
20    
21    /// Processing steps
22    pub steps: Vec<ProcessingStep>,
23    
24    /// Template metadata
25    pub metadata: TemplateMetadata,
26}
27
28/// Template metadata
29#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct TemplateMetadata {
31    /// Template version
32    pub version: String,
33    
34    /// Template author
35    pub author: String,
36    
37    /// Creation date
38    pub created_at: String,
39    
40    /// Last modified date
41    pub updated_at: String,
42    
43    /// Tags for categorization
44    pub tags: Vec<String>,
45    
46    /// Performance characteristics
47    pub performance: PerformanceProfile,
48}
49
50/// Performance profile for a template
51#[derive(Debug, Clone, Serialize, Deserialize)]
52pub struct PerformanceProfile {
53    /// Average execution time in milliseconds
54    pub avg_execution_time_ms: f64,
55    
56    /// Memory usage in bytes
57    pub memory_usage_bytes: usize,
58    
59    /// Complexity rating (1-10)
60    pub complexity: u8,
61}
62
63/// Registry for managing templates
64pub struct TemplateRegistry {
65    templates: Arc<RwLock<AHashMap<String, Template>>>,
66}
67
68impl TemplateRegistry {
69    /// Create a new template registry
70    pub fn new() -> Self {
71        let registry = Self {
72            templates: Arc::new(RwLock::new(AHashMap::new())),
73        };
74        
75        // Load default templates
76        registry.load_default_templates();
77        
78        registry
79    }
80    
81    /// Register a template
82    pub fn register(&self, template: Template) {
83        self.templates.write().insert(template.id.clone(), template);
84    }
85    
86    /// Get a template by ID
87    pub fn get(&self, id: &str) -> Option<Template> {
88        self.templates.read().get(id).cloned()
89    }
90    
91    /// List all template IDs
92    pub fn list(&self) -> Vec<String> {
93        self.templates.read().keys().cloned().collect()
94    }
95    
96    /// Remove a template
97    pub fn remove(&self, id: &str) -> Option<Template> {
98        self.templates.write().remove(id)
99    }
100    
101    /// Load default templates
102    fn load_default_templates(&self) {
103        // Analysis template
104        self.register(Template {
105            id: "analysis-basic".to_string(),
106            name: "Basic Analysis".to_string(),
107            description: "Performs basic statistical and pattern analysis".to_string(),
108            steps: vec![
109                ProcessingStep {
110                    name: "normalize".to_string(),
111                    operation: Operation::Transform(Transform::Normalize),
112                },
113                ProcessingStep {
114                    name: "analyze".to_string(),
115                    operation: Operation::Analyze(Analysis::Statistical),
116                },
117                ProcessingStep {
118                    name: "expand".to_string(),
119                    operation: Operation::Transform(Transform::Expand),
120                },
121            ],
122            metadata: TemplateMetadata {
123                version: "1.0.0".to_string(),
124                author: "FACT Team".to_string(),
125                created_at: chrono::Utc::now().to_rfc3339(),
126                updated_at: chrono::Utc::now().to_rfc3339(),
127                tags: vec!["analysis".to_string(), "statistics".to_string()],
128                performance: PerformanceProfile {
129                    avg_execution_time_ms: 50.0,
130                    memory_usage_bytes: 1024 * 1024, // 1MB
131                    complexity: 3,
132                },
133            },
134        });
135        
136        // Pattern detection template
137        self.register(Template {
138            id: "pattern-detection".to_string(),
139            name: "Pattern Detection".to_string(),
140            description: "Detects patterns in structured data".to_string(),
141            steps: vec![
142                ProcessingStep {
143                    name: "normalize".to_string(),
144                    operation: Operation::Transform(Transform::Normalize),
145                },
146                ProcessingStep {
147                    name: "pattern-analysis".to_string(),
148                    operation: Operation::Analyze(Analysis::Pattern),
149                },
150                ProcessingStep {
151                    name: "semantic-enrichment".to_string(),
152                    operation: Operation::Analyze(Analysis::Semantic),
153                },
154            ],
155            metadata: TemplateMetadata {
156                version: "1.0.0".to_string(),
157                author: "FACT Team".to_string(),
158                created_at: chrono::Utc::now().to_rfc3339(),
159                updated_at: chrono::Utc::now().to_rfc3339(),
160                tags: vec!["pattern".to_string(), "detection".to_string(), "ai".to_string()],
161                performance: PerformanceProfile {
162                    avg_execution_time_ms: 75.0,
163                    memory_usage_bytes: 2 * 1024 * 1024, // 2MB
164                    complexity: 5,
165                },
166            },
167        });
168        
169        // Data aggregation template
170        self.register(Template {
171            id: "data-aggregation".to_string(),
172            name: "Data Aggregation".to_string(),
173            description: "Aggregates numerical data with various operations".to_string(),
174            steps: vec![
175                ProcessingStep {
176                    name: "filter-numbers".to_string(),
177                    operation: Operation::Filter(Filter::Range { min: 0.0, max: 1000000.0 }),
178                },
179                ProcessingStep {
180                    name: "sum".to_string(),
181                    operation: Operation::Aggregate(Aggregation::Sum),
182                },
183                ProcessingStep {
184                    name: "average".to_string(),
185                    operation: Operation::Aggregate(Aggregation::Average),
186                },
187                ProcessingStep {
188                    name: "count".to_string(),
189                    operation: Operation::Aggregate(Aggregation::Count),
190                },
191            ],
192            metadata: TemplateMetadata {
193                version: "1.0.0".to_string(),
194                author: "FACT Team".to_string(),
195                created_at: chrono::Utc::now().to_rfc3339(),
196                updated_at: chrono::Utc::now().to_rfc3339(),
197                tags: vec!["aggregation".to_string(), "numerical".to_string(), "statistics".to_string()],
198                performance: PerformanceProfile {
199                    avg_execution_time_ms: 25.0,
200                    memory_usage_bytes: 512 * 1024, // 512KB
201                    complexity: 2,
202                },
203            },
204        });
205        
206        // Quick transform template
207        self.register(Template {
208            id: "quick-transform".to_string(),
209            name: "Quick Transform".to_string(),
210            description: "Fast data transformation for caching".to_string(),
211            steps: vec![
212                ProcessingStep {
213                    name: "compress".to_string(),
214                    operation: Operation::Transform(Transform::Compress),
215                },
216                ProcessingStep {
217                    name: "normalize".to_string(),
218                    operation: Operation::Transform(Transform::Normalize),
219                },
220            ],
221            metadata: TemplateMetadata {
222                version: "1.0.0".to_string(),
223                author: "FACT Team".to_string(),
224                created_at: chrono::Utc::now().to_rfc3339(),
225                updated_at: chrono::Utc::now().to_rfc3339(),
226                tags: vec!["transform".to_string(), "fast".to_string(), "cache".to_string()],
227                performance: PerformanceProfile {
228                    avg_execution_time_ms: 10.0,
229                    memory_usage_bytes: 256 * 1024, // 256KB
230                    complexity: 1,
231                },
232            },
233        });
234    }
235    
236    /// Search templates by tags
237    pub fn search_by_tags(&self, tags: &[String]) -> Vec<Template> {
238        self.templates
239            .read()
240            .values()
241            .filter(|template| {
242                tags.iter().any(|tag| template.metadata.tags.contains(tag))
243            })
244            .cloned()
245            .collect()
246    }
247    
248    /// Get templates sorted by performance
249    pub fn get_by_performance(&self, max_complexity: u8) -> Vec<Template> {
250        let mut templates: Vec<_> = self.templates
251            .read()
252            .values()
253            .filter(|t| t.metadata.performance.complexity <= max_complexity)
254            .cloned()
255            .collect();
256            
257        templates.sort_by(|a, b| {
258            a.metadata.performance.avg_execution_time_ms
259                .partial_cmp(&b.metadata.performance.avg_execution_time_ms)
260                .unwrap()
261        });
262        
263        templates
264    }
265}
266
267impl Default for TemplateRegistry {
268    fn default() -> Self {
269        Self::new()
270    }
271}
272
273/// Builder for creating templates
274pub struct TemplateBuilder {
275    id: String,
276    name: String,
277    description: String,
278    steps: Vec<ProcessingStep>,
279    tags: Vec<String>,
280}
281
282impl TemplateBuilder {
283    /// Create a new template builder
284    pub fn new(id: impl Into<String>) -> Self {
285        Self {
286            id: id.into(),
287            name: String::new(),
288            description: String::new(),
289            steps: Vec::new(),
290            tags: Vec::new(),
291        }
292    }
293    
294    /// Set the template name
295    pub fn name(mut self, name: impl Into<String>) -> Self {
296        self.name = name.into();
297        self
298    }
299    
300    /// Set the template description
301    pub fn description(mut self, description: impl Into<String>) -> Self {
302        self.description = description.into();
303        self
304    }
305    
306    /// Add a processing step
307    pub fn add_step(mut self, step: ProcessingStep) -> Self {
308        self.steps.push(step);
309        self
310    }
311    
312    /// Add a tag
313    pub fn add_tag(mut self, tag: impl Into<String>) -> Self {
314        self.tags.push(tag.into());
315        self
316    }
317    
318    /// Build the template
319    pub fn build(self) -> Template {
320        Template {
321            id: self.id,
322            name: self.name,
323            description: self.description,
324            steps: self.steps,
325            metadata: TemplateMetadata {
326                version: "1.0.0".to_string(),
327                author: "Custom".to_string(),
328                created_at: chrono::Utc::now().to_rfc3339(),
329                updated_at: chrono::Utc::now().to_rfc3339(),
330                tags: self.tags,
331                performance: PerformanceProfile {
332                    avg_execution_time_ms: 0.0,
333                    memory_usage_bytes: 0,
334                    complexity: 5,
335                },
336            },
337        }
338    }
339}
340
341#[cfg(test)]
342mod tests {
343    use super::*;
344    
345    #[test]
346    fn test_template_registry() {
347        let registry = TemplateRegistry::new();
348        
349        // Check default templates are loaded
350        assert!(registry.get("analysis-basic").is_some());
351        assert!(registry.get("pattern-detection").is_some());
352        assert!(registry.get("data-aggregation").is_some());
353        assert!(registry.get("quick-transform").is_some());
354        
355        // Test listing
356        let templates = registry.list();
357        assert!(templates.len() >= 4);
358    }
359    
360    #[test]
361    fn test_template_builder() {
362        let template = TemplateBuilder::new("custom-template")
363            .name("Custom Template")
364            .description("A custom template for testing")
365            .add_tag("custom")
366            .add_tag("test")
367            .add_step(ProcessingStep {
368                name: "normalize".to_string(),
369                operation: Operation::Transform(Transform::Normalize),
370            })
371            .build();
372        
373        assert_eq!(template.id, "custom-template");
374        assert_eq!(template.name, "Custom Template");
375        assert_eq!(template.steps.len(), 1);
376        assert_eq!(template.metadata.tags.len(), 2);
377    }
378    
379    #[test]
380    fn test_search_by_tags() {
381        let registry = TemplateRegistry::new();
382        
383        let analysis_templates = registry.search_by_tags(&[String::from("analysis")]);
384        assert!(!analysis_templates.is_empty());
385        
386        let pattern_templates = registry.search_by_tags(&[String::from("pattern")]);
387        assert!(!pattern_templates.is_empty());
388    }
389}