function_calls_demo/
function_calls_demo.rs

1use rust_rule_engine::engine::facts::Facts;
2use rust_rule_engine::engine::knowledge_base::KnowledgeBase;
3use rust_rule_engine::engine::rule::{Condition, ConditionGroup, Rule};
4use rust_rule_engine::engine::{EngineConfig, RustRuleEngine};
5use rust_rule_engine::types::{ActionType, Operator, Value};
6use std::collections::HashMap;
7
8fn main() -> Result<(), Box<dyn std::error::Error>> {
9    println!("=== Demo: Generic Function Calls ===\n");
10
11    // Create test data
12    let mut user_props = HashMap::new();
13    user_props.insert("Name".to_string(), Value::String("John Doe".to_string()));
14    user_props.insert("Score".to_string(), Value::Number(85.5));
15    user_props.insert("Active".to_string(), Value::Boolean(true));
16
17    let numbers = vec![
18        Value::Number(10.0),
19        Value::Number(20.0),
20        Value::Number(30.0),
21        Value::Number(15.5),
22        Value::Number(25.2),
23    ];
24
25    // Create facts
26    let facts = Facts::new();
27    facts.add_value("User", Value::Object(user_props))?;
28    facts.add_value("Numbers", Value::Array(numbers))?;
29    facts.add_value("Message", Value::String("Hello World".to_string()))?;
30
31    println!("šŸ Initial state:");
32    if let Some(user) = facts.get("User") {
33        println!("   User = {user:?}");
34    }
35    if let Some(numbers) = facts.get("Numbers") {
36        println!("   Numbers = {numbers:?}");
37    }
38    if let Some(message) = facts.get("Message") {
39        println!("   Message = {message:?}");
40    }
41    println!();
42
43    // Create knowledge base
44    let mut kb = KnowledgeBase::new("FunctionCallDemo");
45
46    // Rule 1: Log message if user is active
47    let log_rule = Rule::new(
48        "LogUserInfo".to_string(),
49        ConditionGroup::single(Condition::new(
50            "User.Active".to_string(),
51            Operator::Equal,
52            Value::Boolean(true),
53        )),
54        vec![ActionType::Call {
55            function: "log".to_string(),
56            args: vec![
57                Value::String("User is active!".to_string()),
58                Value::String("Processing user data...".to_string()),
59            ],
60        }],
61    )
62    .with_salience(10);
63
64    // Rule 2: Calculate statistics if score > 80
65    let stats_rule = Rule::new(
66        "CalculateStats".to_string(),
67        ConditionGroup::single(Condition::new(
68            "User.Score".to_string(),
69            Operator::GreaterThan,
70            Value::Number(80.0),
71        )),
72        vec![
73            ActionType::Call {
74                function: "sum".to_string(),
75                args: vec![
76                    Value::Number(10.0),
77                    Value::Number(20.0),
78                    Value::Number(30.0),
79                ],
80            },
81            ActionType::Call {
82                function: "max".to_string(),
83                args: vec![
84                    Value::Number(85.5),
85                    Value::Number(90.0),
86                    Value::Number(78.2),
87                ],
88            },
89            ActionType::Call {
90                function: "average".to_string(),
91                args: vec![
92                    Value::Number(85.5),
93                    Value::Number(90.0),
94                    Value::Number(78.2),
95                ],
96            },
97        ],
98    )
99    .with_salience(8);
100
101    // Rule 3: String manipulation
102    let string_rule = Rule::new(
103        "StringManipulation".to_string(),
104        ConditionGroup::single(Condition::new(
105            "Message".to_string(),
106            Operator::Contains,
107            Value::String("Hello".to_string()),
108        )),
109        vec![
110            ActionType::Call {
111                function: "uppercase".to_string(),
112                args: vec![Value::String("hello world".to_string())],
113            },
114            ActionType::Call {
115                function: "contains".to_string(),
116                args: vec![
117                    Value::String("Hello World".to_string()),
118                    Value::String("World".to_string()),
119                ],
120            },
121            ActionType::Call {
122                function: "format".to_string(),
123                args: vec![
124                    Value::String("User {0} has score {1}".to_string()),
125                    Value::String("John Doe".to_string()),
126                    Value::Number(85.5),
127                ],
128            },
129        ],
130    )
131    .with_salience(6);
132
133    // Rule 4: Mathematical functions
134    let math_rule = Rule::new(
135        "MathFunctions".to_string(),
136        ConditionGroup::single(Condition::new(
137            "User.Score".to_string(),
138            Operator::GreaterThanOrEqual,
139            Value::Number(80.0),
140        )),
141        vec![
142            ActionType::Call {
143                function: "round".to_string(),
144                args: vec![Value::Number(85.7)],
145            },
146            ActionType::Call {
147                function: "floor".to_string(),
148                args: vec![Value::Number(85.7)],
149            },
150            ActionType::Call {
151                function: "ceil".to_string(),
152                args: vec![Value::Number(85.2)],
153            },
154            ActionType::Call {
155                function: "abs".to_string(),
156                args: vec![Value::Number(-42.5)],
157            },
158        ],
159    )
160    .with_salience(4);
161
162    // Rule 5: Utility functions
163    let utility_rule = Rule::new(
164        "UtilityFunctions".to_string(),
165        ConditionGroup::single(Condition::new(
166            "User.Name".to_string(),
167            Operator::NotEqual,
168            Value::String("".to_string()),
169        )),
170        vec![
171            ActionType::Call {
172                function: "timestamp".to_string(),
173                args: vec![],
174            },
175            ActionType::Call {
176                function: "random".to_string(),
177                args: vec![Value::Number(100.0)],
178            },
179            ActionType::Call {
180                function: "length".to_string(),
181                args: vec![Value::String("Hello World".to_string())],
182            },
183            ActionType::Call {
184                function: "split".to_string(),
185                args: vec![
186                    Value::String("apple,banana,cherry".to_string()),
187                    Value::String(",".to_string()),
188                ],
189            },
190        ],
191    )
192    .with_salience(2);
193
194    // Add rules to knowledge base
195    let _ = kb.add_rule(log_rule);
196    let _ = kb.add_rule(stats_rule);
197    let _ = kb.add_rule(string_rule);
198    let _ = kb.add_rule(math_rule);
199    let _ = kb.add_rule(utility_rule);
200
201    // Create engine with debug mode
202    let config = EngineConfig {
203        debug_mode: true,
204        max_cycles: 5,
205        ..Default::default()
206    };
207    let engine = RustRuleEngine::with_config(kb, config);
208
209    // Execute rules
210    println!("šŸš€ Executing rules with generic function calls...");
211    let result = engine.execute(&facts)?;
212
213    println!("\nšŸ“Š Execution Results:");
214    println!("   Cycles: {}", result.cycle_count);
215    println!("   Rules evaluated: {}", result.rules_evaluated);
216    println!("   Rules fired: {}", result.rules_fired);
217    println!("   Execution time: {:?}", result.execution_time);
218
219    println!("\nšŸŽÆ Function call examples demonstrated:");
220    println!("   šŸ“‹ Logging: log(), print()");
221    println!("   šŸ”¢ Math: sum(), max(), average(), round(), floor(), ceil(), abs()");
222    println!("   šŸ“ String: uppercase(), contains(), format(), length(), split()");
223    println!("   šŸ› ļø Utility: timestamp(), random(), update()");
224    println!("   šŸŽØ Custom: Any user-defined function names");
225
226    Ok(())
227}