1use crate::{FactError, Result, Template, TemplateRegistry};
4use serde::{Deserialize, Serialize};
5use std::sync::Arc;
6use std::time::Duration;
7use tokio::time::timeout;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct EngineConfig {
12 pub timeout: Duration,
14
15 pub parallel: bool,
17
18 pub max_concurrent: usize,
20
21 pub monitoring: bool,
23}
24
25impl Default for EngineConfig {
26 fn default() -> Self {
27 Self {
28 timeout: Duration::from_secs(30),
29 parallel: true,
30 max_concurrent: num_cpus::get(),
31 monitoring: true,
32 }
33 }
34}
35
36#[derive(Debug, Clone, Default)]
38pub struct ProcessingOptions {
39 pub timeout: Option<Duration>,
41
42 pub no_cache: bool,
44
45 pub priority: Priority,
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
51pub enum Priority {
52 Low,
53 Normal,
54 High,
55 Critical,
56}
57
58impl Default for Priority {
59 fn default() -> Self {
60 Self::Normal
61 }
62}
63
64pub struct FactEngine {
66 config: EngineConfig,
67 registry: Arc<TemplateRegistry>,
68}
69
70impl FactEngine {
71 pub fn new() -> Self {
73 Self::with_config(EngineConfig::default())
74 }
75
76 pub fn with_config(config: EngineConfig) -> Self {
78 Self {
79 config,
80 registry: Arc::new(TemplateRegistry::new()),
81 }
82 }
83
84 pub async fn process(
86 &self,
87 template_id: &str,
88 context: serde_json::Value,
89 ) -> Result<serde_json::Value> {
90 self.process_with_options(template_id, context, ProcessingOptions::default())
91 .await
92 }
93
94 pub async fn process_with_options(
96 &self,
97 template_id: &str,
98 context: serde_json::Value,
99 options: ProcessingOptions,
100 ) -> Result<serde_json::Value> {
101 let template = self
102 .registry
103 .get(template_id)
104 .ok_or_else(|| FactError::TemplateNotFound(template_id.to_string()))?;
105
106 let timeout_duration = options.timeout.unwrap_or(self.config.timeout);
107
108 match timeout(
109 timeout_duration,
110 self.execute_template(&template, context, &options),
111 )
112 .await
113 {
114 Ok(result) => result,
115 Err(_) => Err(FactError::Timeout(timeout_duration)),
116 }
117 }
118
119 async fn execute_template(
121 &self,
122 template: &Template,
123 mut context: serde_json::Value,
124 options: &ProcessingOptions,
125 ) -> Result<serde_json::Value> {
126 for step in &template.steps {
128 context = self.execute_step(&step, context, options).await?;
129 }
130
131 Ok(serde_json::json!({
132 "template_id": template.id,
133 "template_name": template.name,
134 "result": context,
135 "metadata": {
136 "processed_at": chrono::Utc::now().to_rfc3339(),
137 "priority": format!("{:?}", options.priority),
138 }
139 }))
140 }
141
142 async fn execute_step(
144 &self,
145 step: &ProcessingStep,
146 context: serde_json::Value,
147 _options: &ProcessingOptions,
148 ) -> Result<serde_json::Value> {
149 match &step.operation {
150 Operation::Transform(transform) => self.apply_transform(transform, context),
151 Operation::Analyze(analysis) => self.apply_analysis(analysis, context),
152 Operation::Filter(filter) => self.apply_filter(filter, context),
153 Operation::Aggregate(aggregation) => self.apply_aggregation(aggregation, context),
154 }
155 }
156
157 fn apply_transform(
158 &self,
159 transform: &Transform,
160 mut context: serde_json::Value,
161 ) -> Result<serde_json::Value> {
162 match transform {
163 Transform::Expand => {
164 if let Some(obj) = context.as_object_mut() {
165 obj.insert(
166 "_expanded".to_string(),
167 serde_json::Value::Bool(true),
168 );
169 obj.insert(
170 "_timestamp".to_string(),
171 serde_json::Value::String(chrono::Utc::now().to_rfc3339()),
172 );
173 }
174 }
175 Transform::Compress => {
176 if let Some(obj) = context.as_object_mut() {
177 obj.retain(|k, _| !k.starts_with('_'));
178 }
179 }
180 Transform::Normalize => {
181 context = normalize_json(context);
183 }
184 }
185
186 Ok(context)
187 }
188
189 fn apply_analysis(
190 &self,
191 analysis: &Analysis,
192 context: serde_json::Value,
193 ) -> Result<serde_json::Value> {
194 let result = match analysis {
195 Analysis::Statistical => {
196 serde_json::json!({
197 "original": context,
198 "analysis": {
199 "type": "statistical",
200 "metrics": compute_statistics(&context),
201 }
202 })
203 }
204 Analysis::Pattern => {
205 serde_json::json!({
206 "original": context,
207 "analysis": {
208 "type": "pattern",
209 "patterns": detect_patterns(&context),
210 }
211 })
212 }
213 Analysis::Semantic => {
214 serde_json::json!({
215 "original": context,
216 "analysis": {
217 "type": "semantic",
218 "entities": extract_entities(&context),
219 "concepts": extract_concepts(&context),
220 }
221 })
222 }
223 };
224
225 Ok(result)
226 }
227
228 fn apply_filter(
229 &self,
230 filter: &Filter,
231 context: serde_json::Value,
232 ) -> Result<serde_json::Value> {
233 match filter {
234 Filter::Type(type_name) => {
235 if context.get("type").and_then(|v| v.as_str()) == Some(type_name) {
237 Ok(context)
238 } else {
239 Ok(serde_json::Value::Null)
240 }
241 }
242 Filter::Range { min, max } => {
243 if let Some(value) = context.as_f64() {
245 if value >= *min && value <= *max {
246 Ok(context)
247 } else {
248 Ok(serde_json::Value::Null)
249 }
250 } else {
251 Ok(context)
252 }
253 }
254 Filter::Custom(expr) => {
255 if expr.contains("true") {
258 Ok(context)
259 } else {
260 Ok(serde_json::Value::Null)
261 }
262 }
263 }
264 }
265
266 fn apply_aggregation(
267 &self,
268 aggregation: &Aggregation,
269 context: serde_json::Value,
270 ) -> Result<serde_json::Value> {
271 match aggregation {
272 Aggregation::Sum => {
273 let sum = sum_numeric_values(&context);
274 Ok(serde_json::json!({ "sum": sum }))
275 }
276 Aggregation::Average => {
277 let (sum, count) = sum_and_count_numeric_values(&context);
278 let avg = if count > 0 { sum / count as f64 } else { 0.0 };
279 Ok(serde_json::json!({ "average": avg }))
280 }
281 Aggregation::Count => {
282 let count = count_values(&context);
283 Ok(serde_json::json!({ "count": count }))
284 }
285 }
286 }
287}
288
289impl Default for FactEngine {
290 fn default() -> Self {
291 Self::new()
292 }
293}
294
295#[derive(Debug, Clone, Serialize, Deserialize)]
297pub struct ProcessingStep {
298 pub name: String,
299 pub operation: Operation,
300}
301
302#[derive(Debug, Clone, Serialize, Deserialize)]
304#[serde(tag = "type", rename_all = "lowercase")]
305pub enum Operation {
306 Transform(Transform),
307 Analyze(Analysis),
308 Filter(Filter),
309 Aggregate(Aggregation),
310}
311
312#[derive(Debug, Clone, Serialize, Deserialize)]
314#[serde(rename_all = "lowercase")]
315pub enum Transform {
316 Expand,
317 Compress,
318 Normalize,
319}
320
321#[derive(Debug, Clone, Serialize, Deserialize)]
323#[serde(rename_all = "lowercase")]
324pub enum Analysis {
325 Statistical,
326 Pattern,
327 Semantic,
328}
329
330#[derive(Debug, Clone, Serialize, Deserialize)]
332#[serde(tag = "type", rename_all = "lowercase")]
333pub enum Filter {
334 Type(String),
335 Range { min: f64, max: f64 },
336 Custom(String),
337}
338
339#[derive(Debug, Clone, Serialize, Deserialize)]
341#[serde(rename_all = "lowercase")]
342pub enum Aggregation {
343 Sum,
344 Average,
345 Count,
346}
347
348fn normalize_json(value: serde_json::Value) -> serde_json::Value {
351 match value {
352 serde_json::Value::Object(map) => {
353 let normalized: serde_json::Map<String, serde_json::Value> = map
354 .into_iter()
355 .map(|(k, v)| (k.to_lowercase(), normalize_json(v)))
356 .collect();
357 serde_json::Value::Object(normalized)
358 }
359 serde_json::Value::Array(arr) => {
360 serde_json::Value::Array(arr.into_iter().map(normalize_json).collect())
361 }
362 other => other,
363 }
364}
365
366fn compute_statistics(value: &serde_json::Value) -> serde_json::Value {
367 let numbers = extract_numbers(value);
368
369 if numbers.is_empty() {
370 return serde_json::json!({});
371 }
372
373 let sum: f64 = numbers.iter().sum();
374 let count = numbers.len() as f64;
375 let mean = sum / count;
376
377 let variance = numbers.iter().map(|n| (n - mean).powi(2)).sum::<f64>() / count;
378 let std_dev = variance.sqrt();
379
380 serde_json::json!({
381 "count": count,
382 "sum": sum,
383 "mean": mean,
384 "std_dev": std_dev,
385 "min": numbers.iter().cloned().fold(f64::INFINITY, f64::min),
386 "max": numbers.iter().cloned().fold(f64::NEG_INFINITY, f64::max),
387 })
388}
389
390fn extract_numbers(value: &serde_json::Value) -> Vec<f64> {
391 let mut numbers = Vec::new();
392
393 match value {
394 serde_json::Value::Number(n) => {
395 if let Some(f) = n.as_f64() {
396 numbers.push(f);
397 }
398 }
399 serde_json::Value::Array(arr) => {
400 for v in arr {
401 numbers.extend(extract_numbers(v));
402 }
403 }
404 serde_json::Value::Object(map) => {
405 for v in map.values() {
406 numbers.extend(extract_numbers(v));
407 }
408 }
409 _ => {}
410 }
411
412 numbers
413}
414
415fn detect_patterns(value: &serde_json::Value) -> Vec<String> {
416 let mut patterns = Vec::new();
417
418 if let Some(obj) = value.as_object() {
419 if obj.contains_key("query") || obj.contains_key("question") {
420 patterns.push("inquiry".to_string());
421 }
422 if obj.contains_key("data") || obj.contains_key("dataset") {
423 patterns.push("data-driven".to_string());
424 }
425 if obj.contains_key("rules") || obj.contains_key("constraints") {
426 patterns.push("rule-based".to_string());
427 }
428 }
429
430 patterns
431}
432
433fn extract_entities(value: &serde_json::Value) -> Vec<String> {
434 let text = serde_json::to_string(value).unwrap_or_default();
436
437 text.split_whitespace()
439 .filter(|word| word.chars().next().map_or(false, |c| c.is_uppercase()))
440 .take(10)
441 .map(|s| s.to_string())
442 .collect()
443}
444
445fn extract_concepts(_value: &serde_json::Value) -> Vec<String> {
446 vec![
448 "processing".to_string(),
449 "analysis".to_string(),
450 "transformation".to_string(),
451 ]
452}
453
454fn sum_numeric_values(value: &serde_json::Value) -> f64 {
455 extract_numbers(value).iter().sum()
456}
457
458fn sum_and_count_numeric_values(value: &serde_json::Value) -> (f64, usize) {
459 let numbers = extract_numbers(value);
460 (numbers.iter().sum(), numbers.len())
461}
462
463fn count_values(value: &serde_json::Value) -> usize {
464 match value {
465 serde_json::Value::Array(arr) => arr.len(),
466 serde_json::Value::Object(map) => map.len(),
467 _ => 1,
468 }
469}
470