1use crate::rete::alpha::AlphaNode;
2pub fn build_rete_ul_from_condition_group(group: &crate::rete::auto_network::ConditionGroup) -> ReteUlNode {
4 use crate::rete::auto_network::ConditionGroup;
5 match group {
6 ConditionGroup::Single(cond) => {
7 ReteUlNode::UlAlpha(AlphaNode {
8 field: cond.field.clone(),
9 operator: cond.operator.clone(),
10 value: cond.value.clone(),
11 })
12 }
13 ConditionGroup::Compound { left, operator, right } => {
14 match operator.as_str() {
15 "AND" => ReteUlNode::UlAnd(
16 Box::new(build_rete_ul_from_condition_group(left)),
17 Box::new(build_rete_ul_from_condition_group(right)),
18 ),
19 "OR" => ReteUlNode::UlOr(
20 Box::new(build_rete_ul_from_condition_group(left)),
21 Box::new(build_rete_ul_from_condition_group(right)),
22 ),
23 _ => ReteUlNode::UlAnd(
24 Box::new(build_rete_ul_from_condition_group(left)),
25 Box::new(build_rete_ul_from_condition_group(right)),
26 ),
27 }
28 }
29 ConditionGroup::Not(inner) => {
30 ReteUlNode::UlNot(Box::new(build_rete_ul_from_condition_group(inner)))
31 }
32 ConditionGroup::Exists(inner) => {
33 ReteUlNode::UlExists(Box::new(build_rete_ul_from_condition_group(inner)))
34 }
35 ConditionGroup::Forall(inner) => {
36 ReteUlNode::UlForall(Box::new(build_rete_ul_from_condition_group(inner)))
37 }
38 }
39}
40use std::collections::HashMap;
41
42fn evaluate_condition_string(condition: &str, facts: &HashMap<String, String>) -> bool {
44 let condition = condition.trim();
45 let operators = ["==", "!=", ">=", "<=", ">", "<"];
46
47 for op in &operators {
48 if let Some(pos) = condition.find(op) {
49 let field = condition[..pos].trim();
50 let value_str = condition[pos + op.len()..]
51 .trim()
52 .trim_matches('"')
53 .trim_matches('\'');
54
55 if let Some(field_value) = facts.get(field) {
56 return compare_string_values(field_value, op, value_str);
57 } else {
58 return false;
59 }
60 }
61 }
62 false
63}
64
65fn compare_string_values(field_value: &str, operator: &str, value_str: &str) -> bool {
67 if let (Ok(field_num), Ok(val_num)) = (field_value.parse::<f64>(), value_str.parse::<f64>()) {
69 match operator {
70 "==" => (field_num - val_num).abs() < f64::EPSILON,
71 "!=" => (field_num - val_num).abs() >= f64::EPSILON,
72 ">" => field_num > val_num,
73 "<" => field_num < val_num,
74 ">=" => field_num >= val_num,
75 "<=" => field_num <= val_num,
76 _ => false,
77 }
78 } else {
79 match operator {
81 "==" => field_value == value_str,
82 "!=" => field_value != value_str,
83 _ => false,
84 }
85 }
86}
87
88pub fn evaluate_rete_ul_node(node: &ReteUlNode, facts: &HashMap<String, String>) -> bool {
90 match node {
91 ReteUlNode::UlAlpha(alpha) => {
92 let val = if alpha.field.contains('.') {
93 let parts: Vec<&str> = alpha.field.split('.').collect();
94 if parts.len() == 2 {
95 let prefix = parts[0];
96 let suffix = parts[1];
97 facts.get(&format!("{}.{}", prefix, suffix)).or_else(|| facts.get(&format!("{}:{}", prefix, suffix)))
98 } else {
99 facts.get(&alpha.field)
100 }
101 } else {
102 facts.get(&alpha.field)
103 };
104 if let Some(val) = val {
105 match alpha.operator.as_str() {
106 "==" => val == &alpha.value,
107 "!=" => val != &alpha.value,
108 ">" => val.parse::<f64>().unwrap_or(0.0) > alpha.value.parse::<f64>().unwrap_or(0.0),
109 "<" => val.parse::<f64>().unwrap_or(0.0) < alpha.value.parse::<f64>().unwrap_or(0.0),
110 ">=" => val.parse::<f64>().unwrap_or(0.0) >= alpha.value.parse::<f64>().unwrap_or(0.0),
111 "<=" => val.parse::<f64>().unwrap_or(0.0) <= alpha.value.parse::<f64>().unwrap_or(0.0),
112 _ => false,
113 }
114 } else {
115 false
116 }
117 }
118 ReteUlNode::UlAnd(left, right) => {
119 evaluate_rete_ul_node(left, facts) && evaluate_rete_ul_node(right, facts)
120 }
121 ReteUlNode::UlOr(left, right) => {
122 evaluate_rete_ul_node(left, facts) || evaluate_rete_ul_node(right, facts)
123 }
124 ReteUlNode::UlNot(inner) => {
125 !evaluate_rete_ul_node(inner, facts)
126 }
127 ReteUlNode::UlExists(inner) => {
128 let target_field = match &**inner {
129 ReteUlNode::UlAlpha(alpha) => alpha.field.clone(),
130 _ => "".to_string(),
131 };
132 if target_field.contains('.') {
133 let parts: Vec<&str> = target_field.split('.').collect();
134 if parts.len() == 2 {
135 let prefix = parts[0];
136 let suffix = parts[1];
137 let filtered: Vec<_> = facts.iter()
138 .filter(|(k, _)| k.starts_with(prefix) && k.ends_with(suffix))
139 .collect();
140 filtered.iter().any(|(_, value)| {
141 let mut sub_facts = HashMap::new();
142 sub_facts.insert(target_field.clone(), (*value).clone());
143 evaluate_rete_ul_node(inner, &sub_facts)
144 })
145 } else {
146 facts.iter().any(|(field, value)| {
147 let mut sub_facts = HashMap::new();
148 sub_facts.insert(field.clone(), value.clone());
149 evaluate_rete_ul_node(inner, &sub_facts)
150 })
151 }
152 } else {
153 facts.iter().any(|(field, value)| {
154 let mut sub_facts = HashMap::new();
155 sub_facts.insert(field.clone(), value.clone());
156 evaluate_rete_ul_node(inner, &sub_facts)
157 })
158 }
159 }
160 ReteUlNode::UlForall(inner) => {
161 let target_field = match &**inner {
162 ReteUlNode::UlAlpha(alpha) => alpha.field.clone(),
163 _ => "".to_string(),
164 };
165 if target_field.contains('.') {
166 let parts: Vec<&str> = target_field.split('.').collect();
167 if parts.len() == 2 {
168 let prefix = parts[0];
169 let suffix = parts[1];
170 let filtered: Vec<_> = facts.iter()
171 .filter(|(k, _)| k.starts_with(prefix) && k.ends_with(suffix))
172 .collect();
173 if filtered.is_empty() {
174 return true; }
176 filtered.iter().all(|(_, value)| {
177 let mut sub_facts = HashMap::new();
178 sub_facts.insert(target_field.clone(), (*value).clone());
179 evaluate_rete_ul_node(inner, &sub_facts)
180 })
181 } else {
182 facts.iter().all(|(field, value)| {
183 let mut sub_facts = HashMap::new();
184 sub_facts.insert(field.clone(), value.clone());
185 evaluate_rete_ul_node(inner, &sub_facts)
186 })
187 }
188 } else {
189 facts.iter().all(|(field, value)| {
190 let mut sub_facts = HashMap::new();
191 sub_facts.insert(field.clone(), value.clone());
192 evaluate_rete_ul_node(inner, &sub_facts)
193 })
194 }
195 }
196 ReteUlNode::UlAccumulate {
197 source_pattern,
198 extract_field,
199 source_conditions,
200 function,
201 ..
202 } => {
203 use super::accumulate::*;
205
206 let pattern_prefix = format!("{}.", source_pattern);
207 let mut matching_values = Vec::new();
208
209 let mut instances: std::collections::HashMap<String, std::collections::HashMap<String, String>> =
211 std::collections::HashMap::new();
212
213 for (key, value) in facts {
214 if key.starts_with(&pattern_prefix) {
215 let parts: Vec<&str> = key.strip_prefix(&pattern_prefix).unwrap().split('.').collect();
216
217 if parts.len() >= 2 {
218 let instance_id = parts[0];
219 let field_name = parts[1..].join(".");
220
221 instances
222 .entry(instance_id.to_string())
223 .or_insert_with(std::collections::HashMap::new)
224 .insert(field_name, value.clone());
225 } else if parts.len() == 1 {
226 instances
227 .entry("default".to_string())
228 .or_insert_with(std::collections::HashMap::new)
229 .insert(parts[0].to_string(), value.clone());
230 }
231 }
232 }
233
234 for (_instance_id, instance_facts) in instances {
236 let mut matches = true;
237
238 for condition_str in source_conditions {
239 if !evaluate_condition_string(condition_str, &instance_facts) {
240 matches = false;
241 break;
242 }
243 }
244
245 if matches {
246 if let Some(value_str) = instance_facts.get(extract_field) {
247 let fact_value = if let Ok(i) = value_str.parse::<i64>() {
249 super::facts::FactValue::Integer(i)
250 } else if let Ok(f) = value_str.parse::<f64>() {
251 super::facts::FactValue::Float(f)
252 } else if let Ok(b) = value_str.parse::<bool>() {
253 super::facts::FactValue::Boolean(b)
254 } else {
255 super::facts::FactValue::String(value_str.clone())
256 };
257 matching_values.push(fact_value);
258 }
259 }
260 }
261
262 let has_results = !matching_values.is_empty();
264
265 match function.as_str() {
266 "count" => has_results, "sum" | "average" | "min" | "max" => {
268 has_results
270 }
271 _ => true, }
273 }
274 ReteUlNode::UlTerminal(_) => true }
276}
277
278#[derive(Debug, Clone)]
280pub enum ReteUlNode {
281 UlAlpha(AlphaNode),
282 UlAnd(Box<ReteUlNode>, Box<ReteUlNode>),
283 UlOr(Box<ReteUlNode>, Box<ReteUlNode>),
284 UlNot(Box<ReteUlNode>),
285 UlExists(Box<ReteUlNode>),
286 UlForall(Box<ReteUlNode>),
287 UlAccumulate {
288 result_var: String,
289 source_pattern: String,
290 extract_field: String,
291 source_conditions: Vec<String>,
292 function: String,
293 function_arg: String,
294 },
295 UlTerminal(String), }
297
298impl ReteUlNode {
299 pub fn evaluate_typed(&self, facts: &super::facts::TypedFacts) -> bool {
301 evaluate_rete_ul_node_typed(self, facts)
302 }
303}
304
305pub struct ReteUlRule {
307 pub name: String,
308 pub node: ReteUlNode,
309 pub priority: i32,
310 pub no_loop: bool,
311 pub action: Box<dyn FnMut(&mut std::collections::HashMap<String, String>)>,
312}
313
314pub fn fire_rete_ul_rules(
317 rules: &mut [(String, ReteUlNode, Box<dyn FnMut(&mut std::collections::HashMap<String, String>)>)],
318 facts: &mut std::collections::HashMap<String, String>,
319) -> Vec<String> {
320 let mut fired_rules = Vec::new();
321 let mut changed = true;
322 while changed {
323 changed = false;
324 for (rule_name, node, action) in rules.iter_mut() {
325 let fired_flag = format!("{}_fired", rule_name);
326 if facts.get(&fired_flag) == Some(&"true".to_string()) {
327 continue;
328 }
329 if evaluate_rete_ul_node(node, facts) {
330 action(facts);
331 facts.insert(fired_flag.clone(), "true".to_string());
332 fired_rules.push(rule_name.clone());
333 changed = true;
334 }
335 }
336 }
337 fired_rules
338}
339
340pub fn fire_rete_ul_rules_with_agenda(
342 rules: &mut [ReteUlRule],
343 facts: &mut std::collections::HashMap<String, String>,
344) -> Vec<String> {
345 let mut fired_rules = Vec::new();
346 let mut fired_flags = std::collections::HashSet::new();
347 let max_iterations = 100; let mut iterations = 0;
349
350 loop {
351 iterations += 1;
352 if iterations > max_iterations {
353 eprintln!("Warning: RETE engine reached max iterations ({})", max_iterations);
354 break;
355 }
356
357 let mut agenda: Vec<usize> = rules
359 .iter()
360 .enumerate()
361 .filter(|(_, rule)| {
362 if fired_flags.contains(&rule.name) {
364 return false;
365 }
366 evaluate_rete_ul_node(&rule.node, facts)
368 })
369 .map(|(i, _)| i)
370 .collect();
371
372 if agenda.is_empty() {
374 break;
375 }
376
377 agenda.sort_by_key(|&i| -rules[i].priority);
379
380 for &i in &agenda {
382 let rule = &mut rules[i];
383
384 (rule.action)(facts);
386
387 fired_rules.push(rule.name.clone());
389 fired_flags.insert(rule.name.clone());
390
391 let fired_flag = format!("{}_fired", rule.name);
392 facts.insert(fired_flag, "true".to_string());
393 }
394
395 if rules.iter().all(|r| r.no_loop) {
397 break;
398 }
399 }
400
401 fired_rules
402}
403
404pub struct ReteUlEngine {
407 rules: Vec<ReteUlRule>,
408 facts: std::collections::HashMap<String, String>,
409}
410
411impl ReteUlEngine {
412 pub fn new() -> Self {
414 Self {
415 rules: Vec::new(),
416 facts: std::collections::HashMap::new(),
417 }
418 }
419
420 pub fn add_rule_with_action<F>(
422 &mut self,
423 name: String,
424 node: ReteUlNode,
425 priority: i32,
426 no_loop: bool,
427 action: F,
428 ) where
429 F: FnMut(&mut std::collections::HashMap<String, String>) + 'static,
430 {
431 self.rules.push(ReteUlRule {
432 name,
433 node,
434 priority,
435 no_loop,
436 action: Box::new(action),
437 });
438 }
439
440 pub fn add_rule_from_definition(
442 &mut self,
443 rule: &crate::rete::auto_network::Rule,
444 priority: i32,
445 no_loop: bool,
446 ) {
447 let node = build_rete_ul_from_condition_group(&rule.conditions);
448 let rule_name = rule.name.clone();
449
450 let action = Box::new(move |facts: &mut std::collections::HashMap<String, String>| {
452 facts.insert(format!("{}_executed", rule_name), "true".to_string());
453 }) as Box<dyn FnMut(&mut std::collections::HashMap<String, String>)>;
454
455 self.rules.push(ReteUlRule {
456 name: rule.name.clone(),
457 node,
458 priority,
459 no_loop,
460 action,
461 });
462 }
463
464 pub fn set_fact(&mut self, key: String, value: String) {
466 self.facts.insert(key, value);
467 }
468
469 pub fn get_fact(&self, key: &str) -> Option<&String> {
471 self.facts.get(key)
472 }
473
474 pub fn remove_fact(&mut self, key: &str) -> Option<String> {
476 self.facts.remove(key)
477 }
478
479 pub fn get_all_facts(&self) -> &std::collections::HashMap<String, String> {
481 &self.facts
482 }
483
484 pub fn clear_facts(&mut self) {
486 self.facts.clear();
487 }
488
489 pub fn fire_all(&mut self) -> Vec<String> {
491 fire_rete_ul_rules_with_agenda(&mut self.rules, &mut self.facts)
492 }
493
494 pub fn matches(&self, rule_name: &str) -> bool {
496 self.rules
497 .iter()
498 .find(|r| r.name == rule_name)
499 .map(|r| evaluate_rete_ul_node(&r.node, &self.facts))
500 .unwrap_or(false)
501 }
502
503 pub fn get_matching_rules(&self) -> Vec<&str> {
505 self.rules
506 .iter()
507 .filter(|r| evaluate_rete_ul_node(&r.node, &self.facts))
508 .map(|r| r.name.as_str())
509 .collect()
510 }
511
512 pub fn reset_fired_flags(&mut self) {
514 let keys_to_remove: Vec<_> = self.facts
515 .keys()
516 .filter(|k| k.ends_with("_fired") || k.ends_with("_executed"))
517 .cloned()
518 .collect();
519 for key in keys_to_remove {
520 self.facts.remove(&key);
521 }
522 }
523}
524
525use super::facts::{FactValue, TypedFacts};
530
531pub fn evaluate_rete_ul_node_typed(node: &ReteUlNode, facts: &TypedFacts) -> bool {
533 match node {
534 ReteUlNode::UlAlpha(alpha) => {
535 alpha.matches_typed(facts)
536 }
537 ReteUlNode::UlAnd(left, right) => {
538 evaluate_rete_ul_node_typed(left, facts) && evaluate_rete_ul_node_typed(right, facts)
539 }
540 ReteUlNode::UlOr(left, right) => {
541 evaluate_rete_ul_node_typed(left, facts) || evaluate_rete_ul_node_typed(right, facts)
542 }
543 ReteUlNode::UlNot(inner) => {
544 !evaluate_rete_ul_node_typed(inner, facts)
545 }
546 ReteUlNode::UlExists(inner) => {
547 let target_field = match &**inner {
548 ReteUlNode::UlAlpha(alpha) => alpha.field.clone(),
549 _ => "".to_string(),
550 };
551 if target_field.contains('.') {
552 let parts: Vec<&str> = target_field.split('.').collect();
553 if parts.len() == 2 {
554 let prefix = parts[0];
555 let suffix = parts[1];
556 let filtered: Vec<_> = facts.get_all().iter()
557 .filter(|(k, _)| k.starts_with(prefix) && k.ends_with(suffix))
558 .collect();
559 filtered.iter().any(|(_, _)| {
560 evaluate_rete_ul_node_typed(inner, facts)
561 })
562 } else {
563 evaluate_rete_ul_node_typed(inner, facts)
564 }
565 } else {
566 evaluate_rete_ul_node_typed(inner, facts)
567 }
568 }
569 ReteUlNode::UlForall(inner) => {
570 let target_field = match &**inner {
571 ReteUlNode::UlAlpha(alpha) => alpha.field.clone(),
572 _ => "".to_string(),
573 };
574 if target_field.contains('.') {
575 let parts: Vec<&str> = target_field.split('.').collect();
576 if parts.len() == 2 {
577 let prefix = parts[0];
578 let suffix = parts[1];
579 let filtered: Vec<_> = facts.get_all().iter()
580 .filter(|(k, _)| k.starts_with(prefix) && k.ends_with(suffix))
581 .collect();
582 if filtered.is_empty() {
583 return true; }
585 filtered.iter().all(|(_, _)| {
586 evaluate_rete_ul_node_typed(inner, facts)
587 })
588 } else {
589 if facts.get_all().is_empty() {
590 return true; }
592 evaluate_rete_ul_node_typed(inner, facts)
593 }
594 } else {
595 if facts.get_all().is_empty() {
596 return true; }
598 evaluate_rete_ul_node_typed(inner, facts)
599 }
600 }
601 ReteUlNode::UlAccumulate {
602 source_pattern,
603 extract_field,
604 source_conditions,
605 function,
606 ..
607 } => {
608 use super::accumulate::*;
610
611 let pattern_prefix = format!("{}.", source_pattern);
612 let mut matching_values = Vec::new();
613
614 let mut instances: std::collections::HashMap<String, std::collections::HashMap<String, FactValue>> =
616 std::collections::HashMap::new();
617
618 for (key, value) in facts.get_all() {
619 if key.starts_with(&pattern_prefix) {
620 let parts: Vec<&str> = key.strip_prefix(&pattern_prefix).unwrap().split('.').collect();
621
622 if parts.len() >= 2 {
623 let instance_id = parts[0];
624 let field_name = parts[1..].join(".");
625
626 instances
627 .entry(instance_id.to_string())
628 .or_insert_with(std::collections::HashMap::new)
629 .insert(field_name, value.clone());
630 } else if parts.len() == 1 {
631 instances
632 .entry("default".to_string())
633 .or_insert_with(std::collections::HashMap::new)
634 .insert(parts[0].to_string(), value.clone());
635 }
636 }
637 }
638
639 for (_instance_id, instance_facts) in instances {
641 let mut matches = true;
642
643 for condition_str in source_conditions {
644 let string_facts: HashMap<String, String> = instance_facts
646 .iter()
647 .map(|(k, v)| (k.clone(), format!("{:?}", v)))
648 .collect();
649
650 if !evaluate_condition_string(condition_str, &string_facts) {
651 matches = false;
652 break;
653 }
654 }
655
656 if matches {
657 if let Some(value) = instance_facts.get(extract_field) {
658 matching_values.push(value.clone());
659 }
660 }
661 }
662
663 let has_results = !matching_values.is_empty();
665
666 match function.as_str() {
667 "count" => has_results,
668 "sum" | "average" | "min" | "max" => has_results,
669 _ => true,
670 }
671 }
672 ReteUlNode::UlTerminal(_) => true
673 }
674}
675
676pub struct TypedReteUlRule {
678 pub name: String,
679 pub node: ReteUlNode,
680 pub priority: i32,
681 pub no_loop: bool,
682 pub action: Box<dyn FnMut(&mut TypedFacts)>,
683}
684
685pub struct TypedReteUlEngine {
688 rules: Vec<TypedReteUlRule>,
689 facts: TypedFacts,
690}
691
692impl TypedReteUlEngine {
693 pub fn new() -> Self {
695 Self {
696 rules: Vec::new(),
697 facts: TypedFacts::new(),
698 }
699 }
700
701 pub fn add_rule_with_action<F>(
703 &mut self,
704 name: String,
705 node: ReteUlNode,
706 priority: i32,
707 no_loop: bool,
708 action: F,
709 ) where
710 F: FnMut(&mut TypedFacts) + 'static,
711 {
712 self.rules.push(TypedReteUlRule {
713 name,
714 node,
715 priority,
716 no_loop,
717 action: Box::new(action),
718 });
719 }
720
721 pub fn add_rule_from_definition(
723 &mut self,
724 rule: &crate::rete::auto_network::Rule,
725 priority: i32,
726 no_loop: bool,
727 ) {
728 let node = build_rete_ul_from_condition_group(&rule.conditions);
729 let rule_name = rule.name.clone();
730
731 let action = Box::new(move |facts: &mut TypedFacts| {
732 facts.set(format!("{}_executed", rule_name), true);
733 }) as Box<dyn FnMut(&mut TypedFacts)>;
734
735 self.rules.push(TypedReteUlRule {
736 name: rule.name.clone(),
737 node,
738 priority,
739 no_loop,
740 action,
741 });
742 }
743
744 pub fn set_fact<K: Into<String>, V: Into<FactValue>>(&mut self, key: K, value: V) {
746 self.facts.set(key, value);
747 }
748
749 pub fn get_fact(&self, key: &str) -> Option<&FactValue> {
751 self.facts.get(key)
752 }
753
754 pub fn remove_fact(&mut self, key: &str) -> Option<FactValue> {
756 self.facts.remove(key)
757 }
758
759 pub fn get_all_facts(&self) -> &TypedFacts {
761 &self.facts
762 }
763
764 pub fn clear_facts(&mut self) {
766 self.facts.clear();
767 }
768
769 pub fn fire_all(&mut self) -> Vec<String> {
771 let mut fired_rules = Vec::new();
772 let mut agenda: Vec<usize>;
773 let mut changed = true;
774 let mut fired_flags = std::collections::HashSet::new();
775
776 while changed {
777 changed = false;
778
779 agenda = self.rules.iter().enumerate()
781 .filter(|(_, rule)| {
782 let fired_flag = format!("{}_fired", rule.name);
783 let already_fired = fired_flags.contains(&rule.name) ||
784 self.facts.get(&fired_flag).and_then(|v| v.as_boolean()) == Some(true);
785 !rule.no_loop || !already_fired
786 })
787 .filter(|(_, rule)| evaluate_rete_ul_node_typed(&rule.node, &self.facts))
788 .map(|(i, _)| i)
789 .collect();
790
791 agenda.sort_by_key(|&i| -self.rules[i].priority);
793
794 for &i in &agenda {
795 let rule = &mut self.rules[i];
796 let fired_flag = format!("{}_fired", rule.name);
797 let already_fired = fired_flags.contains(&rule.name) ||
798 self.facts.get(&fired_flag).and_then(|v| v.as_boolean()) == Some(true);
799
800 if rule.no_loop && already_fired {
801 continue;
802 }
803
804 (rule.action)(&mut self.facts);
805 fired_rules.push(rule.name.clone());
806 fired_flags.insert(rule.name.clone());
807 self.facts.set(fired_flag, true);
808 changed = true;
809 }
810 }
811
812 fired_rules
813 }
814
815 pub fn matches(&self, rule_name: &str) -> bool {
817 self.rules
818 .iter()
819 .find(|r| r.name == rule_name)
820 .map(|r| evaluate_rete_ul_node_typed(&r.node, &self.facts))
821 .unwrap_or(false)
822 }
823
824 pub fn get_matching_rules(&self) -> Vec<&str> {
826 self.rules
827 .iter()
828 .filter(|r| evaluate_rete_ul_node_typed(&r.node, &self.facts))
829 .map(|r| r.name.as_str())
830 .collect()
831 }
832
833 pub fn reset_fired_flags(&mut self) {
835 let keys_to_remove: Vec<_> = self.facts.get_all()
836 .keys()
837 .filter(|k| k.ends_with("_fired") || k.ends_with("_executed"))
838 .cloned()
839 .collect();
840 for key in keys_to_remove {
841 self.facts.remove(&key);
842 }
843 }
844}
845
846impl Default for TypedReteUlEngine {
847 fn default() -> Self {
848 Self::new()
849 }
850}
851