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