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