1use crate::engine::{analytics::RuleAnalytics, facts::Facts, knowledge_base::KnowledgeBase};
2use crate::errors::{Result, RuleEngineError};
3use crate::types::{ActionType, Value};
4use std::collections::HashMap;
5use std::time::{Duration, Instant};
6
7pub type CustomFunction = Box<dyn Fn(&[Value], &Facts) -> Result<Value> + Send + Sync>;
9
10#[derive(Debug, Clone)]
12pub struct EngineConfig {
13 pub max_cycles: usize,
15 pub timeout: Option<Duration>,
17 pub enable_stats: bool,
19 pub debug_mode: bool,
21}
22
23impl Default for EngineConfig {
24 fn default() -> Self {
25 Self {
26 max_cycles: 100,
27 timeout: Some(Duration::from_secs(30)),
28 enable_stats: true,
29 debug_mode: false,
30 }
31 }
32}
33
34#[derive(Debug, Clone)]
36pub struct GruleExecutionResult {
37 pub cycle_count: usize,
39 pub rules_evaluated: usize,
41 pub rules_fired: usize,
43 pub execution_time: Duration,
45}
46
47pub struct RustRuleEngine {
49 knowledge_base: KnowledgeBase,
50 config: EngineConfig,
51 custom_functions: HashMap<String, CustomFunction>,
52 analytics: Option<RuleAnalytics>,
53}
54
55impl RustRuleEngine {
56 pub fn new(knowledge_base: KnowledgeBase) -> Self {
58 Self {
59 knowledge_base,
60 config: EngineConfig::default(),
61 custom_functions: HashMap::new(),
62 analytics: None,
63 }
64 }
65
66 pub fn with_config(knowledge_base: KnowledgeBase, config: EngineConfig) -> Self {
68 Self {
69 knowledge_base,
70 config,
71 custom_functions: HashMap::new(),
72 analytics: None,
73 }
74 }
75
76 pub fn register_function<F>(&mut self, name: &str, func: F)
78 where
79 F: Fn(&[Value], &Facts) -> Result<Value> + Send + Sync + 'static,
80 {
81 self.custom_functions
82 .insert(name.to_string(), Box::new(func));
83 }
84
85 pub fn enable_analytics(&mut self, analytics: RuleAnalytics) {
87 self.analytics = Some(analytics);
88 }
89
90 pub fn disable_analytics(&mut self) {
92 self.analytics = None;
93 }
94
95 pub fn analytics(&self) -> Option<&RuleAnalytics> {
97 self.analytics.as_ref()
98 }
99
100 pub fn has_function(&self, name: &str) -> bool {
102 self.custom_functions.contains_key(name)
103 }
104
105 pub fn knowledge_base(&self) -> &KnowledgeBase {
107 &self.knowledge_base
108 }
109
110 pub fn knowledge_base_mut(&mut self) -> &mut KnowledgeBase {
112 &mut self.knowledge_base
113 }
114
115 pub fn execute(&mut self, facts: &Facts) -> Result<GruleExecutionResult> {
117 let start_time = Instant::now();
118 let mut cycle_count = 0;
119 let mut rules_evaluated = 0;
120 let mut rules_fired = 0;
121
122 if self.config.debug_mode {
123 println!(
124 "🚀 Starting rule execution with {} rules",
125 self.knowledge_base.get_rules().len()
126 );
127 }
128
129 for cycle in 0..self.config.max_cycles {
130 cycle_count = cycle + 1;
131 let mut any_rule_fired = false;
132
133 if let Some(timeout) = self.config.timeout {
135 if start_time.elapsed() > timeout {
136 return Err(RuleEngineError::EvaluationError {
137 message: "Execution timeout exceeded".to_string(),
138 });
139 }
140 }
141
142 let mut rules = self.knowledge_base.get_rules().clone();
144 rules.sort_by(|a, b| b.salience.cmp(&a.salience));
145
146 for rule in &rules {
147 if !rule.enabled {
148 continue;
149 }
150
151 rules_evaluated += 1;
152 let rule_start = Instant::now();
153
154 if self.config.debug_mode {
155 println!("📝 Evaluating rule: {}", rule.name);
156 }
157
158 if self.evaluate_conditions(&rule.conditions, facts)? {
160 if self.config.debug_mode {
161 println!(
162 "🔥 Rule '{}' fired (salience: {})",
163 rule.name, rule.salience
164 );
165 }
166
167 for action in &rule.actions {
169 self.execute_action(action, facts)?;
170 }
171
172 let rule_duration = rule_start.elapsed();
173
174 if let Some(analytics) = &mut self.analytics {
176 analytics.record_execution(&rule.name, rule_duration, true, true, None, 0);
177 }
178
179 rules_fired += 1;
180 any_rule_fired = true;
181 } else {
182 let rule_duration = rule_start.elapsed();
183
184 if let Some(analytics) = &mut self.analytics {
186 analytics.record_execution(
187 &rule.name,
188 rule_duration,
189 false,
190 false,
191 None,
192 0,
193 );
194 }
195 }
196 }
197
198 if !any_rule_fired {
200 break;
201 }
202 }
203
204 let execution_time = start_time.elapsed();
205
206 Ok(GruleExecutionResult {
207 cycle_count,
208 rules_evaluated,
209 rules_fired,
210 execution_time,
211 })
212 }
213
214 fn evaluate_conditions(
216 &self,
217 conditions: &crate::engine::rule::ConditionGroup,
218 facts: &Facts,
219 ) -> Result<bool> {
220 use crate::engine::rule::ConditionGroup;
221
222 match conditions {
223 ConditionGroup::Single(condition) => self.evaluate_single_condition(condition, facts),
224 ConditionGroup::Compound {
225 left,
226 operator,
227 right,
228 } => {
229 let left_result = self.evaluate_conditions(left, facts)?;
230 let right_result = self.evaluate_conditions(right, facts)?;
231
232 match operator {
233 crate::types::LogicalOperator::And => Ok(left_result && right_result),
234 crate::types::LogicalOperator::Or => Ok(left_result || right_result),
235 crate::types::LogicalOperator::Not => Err(RuleEngineError::EvaluationError {
236 message: "NOT operator should not appear in compound conditions"
237 .to_string(),
238 }),
239 }
240 }
241 ConditionGroup::Not(condition) => {
242 let result = self.evaluate_conditions(condition, facts)?;
243 Ok(!result)
244 }
245 }
246 }
247
248 fn evaluate_single_condition(
250 &self,
251 condition: &crate::engine::rule::Condition,
252 facts: &Facts,
253 ) -> Result<bool> {
254 let field_value = facts.get_nested(&condition.field);
256
257 if field_value.is_none() {
258 return Ok(false); }
260
261 let field_value = field_value.unwrap();
262
263 Ok(condition.operator.evaluate(&field_value, &condition.value))
265 }
266
267 fn execute_action(&self, action: &ActionType, facts: &Facts) -> Result<()> {
269 match action {
270 ActionType::Set { field, value } => {
271 facts.set_nested(field, value.clone())?;
272 if self.config.debug_mode {
273 println!(" ✅ Set {field} = {value:?}");
274 }
275 }
276 ActionType::Log { message } => {
277 println!("📋 LOG: {}", message);
278 }
279 ActionType::Call { function, args } => {
280 let result = self.execute_function_call(function, args, facts)?;
281 if self.config.debug_mode {
282 println!(" 📞 Called {function}({args:?}) -> {result}");
283 }
284 }
285 ActionType::MethodCall {
286 object,
287 method,
288 args,
289 } => {
290 let result = self.execute_method_call(object, method, args, facts)?;
291 if self.config.debug_mode {
292 println!(" 🔧 Called {object}.{method}({args:?}) -> {result}");
293 }
294 }
295 ActionType::Update { object } => {
296 if self.config.debug_mode {
297 println!(" 🔄 Updated {object}");
298 }
299 }
302 ActionType::Custom {
303 action_type,
304 params,
305 } => {
306 if self.config.debug_mode {
307 println!(" 🎯 Custom action: {action_type} with params: {params:?}");
308 }
309 }
310 }
311 Ok(())
312 }
313
314 fn execute_function_call(
316 &self,
317 function: &str,
318 args: &[Value],
319 facts: &Facts,
320 ) -> Result<String> {
321 let function_lower = function.to_lowercase();
322
323 match function_lower.as_str() {
325 "log" | "print" | "println" => self.handle_log_function(args),
326 "update" | "refresh" => self.handle_update_function(args),
327 "now" | "timestamp" => self.handle_timestamp_function(),
328 "random" => self.handle_random_function(args),
329 "format" | "sprintf" => self.handle_format_function(args),
330 "length" | "size" | "count" => self.handle_length_function(args),
331 "sum" | "add" => self.handle_sum_function(args),
332 "max" | "maximum" => self.handle_max_function(args),
333 "min" | "minimum" => self.handle_min_function(args),
334 "avg" | "average" => self.handle_average_function(args),
335 "round" => self.handle_round_function(args),
336 "floor" => self.handle_floor_function(args),
337 "ceil" | "ceiling" => self.handle_ceil_function(args),
338 "abs" | "absolute" => self.handle_abs_function(args),
339 "contains" | "includes" => self.handle_contains_function(args),
340 "startswith" | "begins_with" => self.handle_starts_with_function(args),
341 "endswith" | "ends_with" => self.handle_ends_with_function(args),
342 "lowercase" | "tolower" => self.handle_lowercase_function(args),
343 "uppercase" | "toupper" => self.handle_uppercase_function(args),
344 "trim" | "strip" => self.handle_trim_function(args),
345 "split" => self.handle_split_function(args),
346 "join" => self.handle_join_function(args),
347 _ => {
348 self.handle_custom_function(function, args, facts)
350 }
351 }
352 }
353
354 fn handle_log_function(&self, args: &[Value]) -> Result<String> {
356 let message = if args.is_empty() {
357 "".to_string()
358 } else if args.len() == 1 {
359 args[0].to_string()
360 } else {
361 args.iter()
362 .map(|v| v.to_string())
363 .collect::<Vec<_>>()
364 .join(" ")
365 };
366
367 println!("📋 {}", message);
368 Ok(message)
369 }
370
371 fn handle_update_function(&self, args: &[Value]) -> Result<String> {
373 if let Some(arg) = args.first() {
374 Ok(format!("Updated: {}", arg.to_string()))
375 } else {
376 Ok("Updated".to_string())
377 }
378 }
379
380 fn handle_timestamp_function(&self) -> Result<String> {
382 use std::time::{SystemTime, UNIX_EPOCH};
383 let timestamp = SystemTime::now()
384 .duration_since(UNIX_EPOCH)
385 .map_err(|e| RuleEngineError::EvaluationError {
386 message: format!("Failed to get timestamp: {}", e),
387 })?
388 .as_secs();
389 Ok(timestamp.to_string())
390 }
391
392 fn handle_random_function(&self, args: &[Value]) -> Result<String> {
394 use std::collections::hash_map::DefaultHasher;
395 use std::hash::{Hash, Hasher};
396
397 let mut hasher = DefaultHasher::new();
399 std::time::SystemTime::now().hash(&mut hasher);
400 let random_value = hasher.finish();
401
402 if args.is_empty() {
403 Ok((random_value % 100).to_string()) } else if let Some(Value::Number(max)) = args.first() {
405 let max_val = *max as u64;
406 Ok((random_value % max_val).to_string())
407 } else {
408 Ok(random_value.to_string())
409 }
410 }
411
412 fn handle_format_function(&self, args: &[Value]) -> Result<String> {
414 if args.is_empty() {
415 return Ok("".to_string());
416 }
417
418 let template = args[0].to_string();
419 let values: Vec<String> = args[1..].iter().map(|v| v.to_string()).collect();
420
421 let mut result = template;
423 for (i, value) in values.iter().enumerate() {
424 result = result.replace(&format!("{{{}}}", i), value);
425 }
426
427 Ok(result)
428 }
429
430 fn handle_length_function(&self, args: &[Value]) -> Result<String> {
432 if let Some(arg) = args.first() {
433 match arg {
434 Value::String(s) => Ok(s.len().to_string()),
435 Value::Array(arr) => Ok(arr.len().to_string()),
436 Value::Object(obj) => Ok(obj.len().to_string()),
437 _ => Ok("1".to_string()), }
439 } else {
440 Ok("0".to_string())
441 }
442 }
443
444 fn handle_sum_function(&self, args: &[Value]) -> Result<String> {
446 let sum = args.iter().fold(0.0, |acc, val| match val {
447 Value::Number(n) => acc + n,
448 Value::Integer(i) => acc + (*i as f64),
449 _ => acc,
450 });
451 Ok(sum.to_string())
452 }
453
454 fn handle_max_function(&self, args: &[Value]) -> Result<String> {
456 let max = args.iter().fold(f64::NEG_INFINITY, |acc, val| match val {
457 Value::Number(n) => acc.max(*n),
458 Value::Integer(i) => acc.max(*i as f64),
459 _ => acc,
460 });
461 Ok(max.to_string())
462 }
463
464 fn handle_min_function(&self, args: &[Value]) -> Result<String> {
466 let min = args.iter().fold(f64::INFINITY, |acc, val| match val {
467 Value::Number(n) => acc.min(*n),
468 Value::Integer(i) => acc.min(*i as f64),
469 _ => acc,
470 });
471 Ok(min.to_string())
472 }
473
474 fn handle_average_function(&self, args: &[Value]) -> Result<String> {
476 if args.is_empty() {
477 return Ok("0".to_string());
478 }
479
480 let (sum, count) = args.iter().fold((0.0, 0), |(sum, count), val| match val {
481 Value::Number(n) => (sum + n, count + 1),
482 Value::Integer(i) => (sum + (*i as f64), count + 1),
483 _ => (sum, count),
484 });
485
486 if count > 0 {
487 Ok((sum / count as f64).to_string())
488 } else {
489 Ok("0".to_string())
490 }
491 }
492
493 fn handle_round_function(&self, args: &[Value]) -> Result<String> {
495 if let Some(Value::Number(n)) = args.first() {
496 Ok(n.round().to_string())
497 } else if let Some(Value::Integer(i)) = args.first() {
498 Ok(i.to_string())
499 } else {
500 Err(RuleEngineError::EvaluationError {
501 message: "round() requires a numeric argument".to_string(),
502 })
503 }
504 }
505
506 fn handle_floor_function(&self, args: &[Value]) -> Result<String> {
507 if let Some(Value::Number(n)) = args.first() {
508 Ok(n.floor().to_string())
509 } else if let Some(Value::Integer(i)) = args.first() {
510 Ok(i.to_string())
511 } else {
512 Err(RuleEngineError::EvaluationError {
513 message: "floor() requires a numeric argument".to_string(),
514 })
515 }
516 }
517
518 fn handle_ceil_function(&self, args: &[Value]) -> Result<String> {
519 if let Some(Value::Number(n)) = args.first() {
520 Ok(n.ceil().to_string())
521 } else if let Some(Value::Integer(i)) = args.first() {
522 Ok(i.to_string())
523 } else {
524 Err(RuleEngineError::EvaluationError {
525 message: "ceil() requires a numeric argument".to_string(),
526 })
527 }
528 }
529
530 fn handle_abs_function(&self, args: &[Value]) -> Result<String> {
531 if let Some(Value::Number(n)) = args.first() {
532 Ok(n.abs().to_string())
533 } else if let Some(Value::Integer(i)) = args.first() {
534 Ok(i.abs().to_string())
535 } else {
536 Err(RuleEngineError::EvaluationError {
537 message: "abs() requires a numeric argument".to_string(),
538 })
539 }
540 }
541
542 fn handle_contains_function(&self, args: &[Value]) -> Result<String> {
544 if args.len() >= 2 {
545 let haystack = args[0].to_string();
546 let needle = args[1].to_string();
547 Ok(haystack.contains(&needle).to_string())
548 } else {
549 Err(RuleEngineError::EvaluationError {
550 message: "contains() requires 2 arguments".to_string(),
551 })
552 }
553 }
554
555 fn handle_starts_with_function(&self, args: &[Value]) -> Result<String> {
556 if args.len() >= 2 {
557 let text = args[0].to_string();
558 let prefix = args[1].to_string();
559 Ok(text.starts_with(&prefix).to_string())
560 } else {
561 Err(RuleEngineError::EvaluationError {
562 message: "startswith() requires 2 arguments".to_string(),
563 })
564 }
565 }
566
567 fn handle_ends_with_function(&self, args: &[Value]) -> Result<String> {
568 if args.len() >= 2 {
569 let text = args[0].to_string();
570 let suffix = args[1].to_string();
571 Ok(text.ends_with(&suffix).to_string())
572 } else {
573 Err(RuleEngineError::EvaluationError {
574 message: "endswith() requires 2 arguments".to_string(),
575 })
576 }
577 }
578
579 fn handle_lowercase_function(&self, args: &[Value]) -> Result<String> {
580 if let Some(arg) = args.first() {
581 Ok(arg.to_string().to_lowercase())
582 } else {
583 Err(RuleEngineError::EvaluationError {
584 message: "lowercase() requires 1 argument".to_string(),
585 })
586 }
587 }
588
589 fn handle_uppercase_function(&self, args: &[Value]) -> Result<String> {
590 if let Some(arg) = args.first() {
591 Ok(arg.to_string().to_uppercase())
592 } else {
593 Err(RuleEngineError::EvaluationError {
594 message: "uppercase() requires 1 argument".to_string(),
595 })
596 }
597 }
598
599 fn handle_trim_function(&self, args: &[Value]) -> Result<String> {
600 if let Some(arg) = args.first() {
601 Ok(arg.to_string().trim().to_string())
602 } else {
603 Err(RuleEngineError::EvaluationError {
604 message: "trim() requires 1 argument".to_string(),
605 })
606 }
607 }
608
609 fn handle_split_function(&self, args: &[Value]) -> Result<String> {
610 if args.len() >= 2 {
611 let text = args[0].to_string();
612 let delimiter = args[1].to_string();
613 let parts: Vec<String> = text.split(&delimiter).map(|s| s.to_string()).collect();
614 Ok(format!("{:?}", parts)) } else {
616 Err(RuleEngineError::EvaluationError {
617 message: "split() requires 2 arguments".to_string(),
618 })
619 }
620 }
621
622 fn handle_join_function(&self, args: &[Value]) -> Result<String> {
623 if args.len() >= 2 {
624 let delimiter = args[0].to_string();
625 let parts: Vec<String> = args[1..].iter().map(|v| v.to_string()).collect();
626 Ok(parts.join(&delimiter))
627 } else {
628 Err(RuleEngineError::EvaluationError {
629 message: "join() requires at least 2 arguments".to_string(),
630 })
631 }
632 }
633
634 fn handle_custom_function(
636 &self,
637 function: &str,
638 args: &[Value],
639 facts: &Facts,
640 ) -> Result<String> {
641 if let Some(custom_func) = self.custom_functions.get(function) {
643 if self.config.debug_mode {
644 println!("🎯 Calling registered function: {}({:?})", function, args);
645 }
646
647 match custom_func(args, facts) {
648 Ok(result) => Ok(result.to_string()),
649 Err(e) => Err(e),
650 }
651 } else {
652 if self.config.debug_mode {
654 println!("⚠️ Custom function '{}' not registered", function);
655 }
656
657 Err(RuleEngineError::EvaluationError {
658 message: format!("Function '{}' is not registered. Use engine.register_function() to add custom functions.", function),
659 })
660 }
661 }
662
663 fn execute_method_call(
665 &self,
666 object_name: &str,
667 method: &str,
668 args: &[Value],
669 facts: &Facts,
670 ) -> Result<String> {
671 let Some(object_value) = facts.get(object_name) else {
673 return Err(RuleEngineError::EvaluationError {
674 message: format!("Object '{}' not found in facts", object_name),
675 });
676 };
677
678 let method_lower = method.to_lowercase();
679
680 if method_lower.starts_with("set") && args.len() == 1 {
682 return self.handle_setter_method(object_name, method, &args[0], object_value, facts);
683 }
684
685 if method_lower.starts_with("get") && args.is_empty() {
687 return self.handle_getter_method(object_name, method, &object_value);
688 }
689
690 match method_lower.as_str() {
692 "tostring" => Ok(object_value.to_string()),
693 "update" => {
694 facts.add_value(object_name, object_value)?;
695 Ok(format!("Updated {}", object_name))
696 }
697 "reset" => self.handle_reset_method(object_name, object_value, facts),
698 _ => self.handle_property_access_or_fallback(
699 object_name,
700 method,
701 args.len(),
702 &object_value,
703 ),
704 }
705 }
706
707 fn handle_setter_method(
709 &self,
710 object_name: &str,
711 method: &str,
712 new_value: &Value,
713 mut object_value: Value,
714 facts: &Facts,
715 ) -> Result<String> {
716 let property_name = Self::extract_property_name_from_setter(method);
717
718 match object_value {
719 Value::Object(ref mut obj) => {
720 obj.insert(property_name.clone(), new_value.clone());
721 facts.add_value(object_name, object_value)?;
722 Ok(format!(
723 "Set {} to {}",
724 property_name,
725 new_value.to_string()
726 ))
727 }
728 _ => Err(RuleEngineError::EvaluationError {
729 message: format!("Cannot call setter on non-object type: {}", object_name),
730 }),
731 }
732 }
733
734 fn handle_getter_method(
736 &self,
737 object_name: &str,
738 method: &str,
739 object_value: &Value,
740 ) -> Result<String> {
741 let property_name = Self::extract_property_name_from_getter(method);
742
743 match object_value {
744 Value::Object(obj) => {
745 if let Some(value) = obj.get(&property_name) {
746 Ok(value.to_string())
747 } else {
748 Err(RuleEngineError::EvaluationError {
749 message: format!(
750 "Property '{}' not found on object '{}'",
751 property_name, object_name
752 ),
753 })
754 }
755 }
756 _ => Err(RuleEngineError::EvaluationError {
757 message: format!("Cannot call getter on non-object type: {}", object_name),
758 }),
759 }
760 }
761
762 fn handle_reset_method(
764 &self,
765 object_name: &str,
766 mut object_value: Value,
767 facts: &Facts,
768 ) -> Result<String> {
769 match object_value {
770 Value::Object(ref mut obj) => {
771 obj.clear();
772 facts.add_value(object_name, object_value)?;
773 Ok(format!("Reset {}", object_name))
774 }
775 _ => Err(RuleEngineError::EvaluationError {
776 message: format!("Cannot reset non-object type: {}", object_name),
777 }),
778 }
779 }
780
781 fn handle_property_access_or_fallback(
783 &self,
784 object_name: &str,
785 method: &str,
786 arg_count: usize,
787 object_value: &Value,
788 ) -> Result<String> {
789 if let Value::Object(obj) = object_value {
790 if let Some(value) = obj.get(method) {
792 return Ok(value.to_string());
793 }
794
795 let capitalized_method = Self::capitalize_first_letter(method);
797 if let Some(value) = obj.get(&capitalized_method) {
798 return Ok(value.to_string());
799 }
800 }
801
802 Ok(format!(
804 "Called {}.{} with {} args",
805 object_name, method, arg_count
806 ))
807 }
808
809 fn extract_property_name_from_setter(method: &str) -> String {
811 let property_name = &method[3..]; Self::capitalize_first_letter(property_name)
813 }
814
815 fn extract_property_name_from_getter(method: &str) -> String {
817 let property_name = &method[3..]; Self::capitalize_first_letter(property_name)
819 }
820
821 fn capitalize_first_letter(s: &str) -> String {
823 if s.is_empty() {
824 return String::new();
825 }
826 let mut chars = s.chars();
827 match chars.next() {
828 None => String::new(),
829 Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
830 }
831 }
832}