custom_functions_demo/
custom_functions_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() -> std::result::Result<(), Box<dyn std::error::Error>> {
9    println!("šŸŽÆ Custom Function Calls Demo");
10    println!("=============================\n");
11
12    // Create facts
13    let facts = Facts::new();
14
15    // Car data
16    let mut car_props = HashMap::new();
17    car_props.insert("Speed".to_string(), Value::Number(60.0));
18    car_props.insert("MaxSpeed".to_string(), Value::Number(120.0));
19    car_props.insert("Engine".to_string(), Value::String("V6".to_string()));
20    car_props.insert("IsRunning".to_string(), Value::Boolean(true));
21
22    // Driver data
23    let mut driver_props = HashMap::new();
24    driver_props.insert("Name".to_string(), Value::String("John Doe".to_string()));
25    driver_props.insert("Experience".to_string(), Value::Integer(5));
26    driver_props.insert("License".to_string(), Value::String("VALID".to_string()));
27
28    facts.add_value("Car", Value::Object(car_props))?;
29    facts.add_value("Driver", Value::Object(driver_props))?;
30
31    println!("šŸ Initial state:");
32    if let Some(car) = facts.get("Car") {
33        println!("   Car = {car:?}");
34    }
35    if let Some(driver) = facts.get("Driver") {
36        println!("   Driver = {driver:?}");
37    }
38    println!();
39
40    // Create knowledge base
41    let mut kb = KnowledgeBase::new("CustomFunctionRules");
42
43    // Rule 1: Speed Check with custom function
44    let speed_check_rule = Rule::new(
45        "SpeedCheck".to_string(),
46        ConditionGroup::single(Condition::new(
47            "Car.Speed".to_string(),
48            Operator::GreaterThan,
49            Value::Number(80.0),
50        )),
51        vec![
52            ActionType::Call {
53                function: "checkSpeedLimit".to_string(),
54                args: vec![Value::String("Car.Speed".to_string()), Value::Number(80.0)],
55            },
56            ActionType::Call {
57                function: "sendAlert".to_string(),
58                args: vec![
59                    Value::String("Speed limit exceeded!".to_string()),
60                    Value::String("Driver.Name".to_string()),
61                ],
62            },
63        ],
64    )
65    .with_salience(20);
66
67    // Rule 2: Driver validation
68    let driver_validation_rule = Rule::new(
69        "DriverValidation".to_string(),
70        ConditionGroup::single(Condition::new(
71            "Driver.License".to_string(),
72            Operator::Equal,
73            Value::String("VALID".to_string()),
74        )),
75        vec![
76            ActionType::Call {
77                function: "validateDriver".to_string(),
78                args: vec![
79                    Value::String("Driver.Name".to_string()),
80                    Value::String("Driver.Experience".to_string()),
81                ],
82            },
83            ActionType::Call {
84                function: "calculateInsurance".to_string(),
85                args: vec![
86                    Value::String("Driver.Experience".to_string()),
87                    Value::String("Car.Engine".to_string()),
88                ],
89            },
90        ],
91    )
92    .with_salience(15);
93
94    // Rule 3: Engine diagnostics
95    let engine_diagnostics_rule = Rule::new(
96        "EngineDiagnostics".to_string(),
97        ConditionGroup::single(Condition::new(
98            "Car.IsRunning".to_string(),
99            Operator::Equal,
100            Value::Boolean(true),
101        )),
102        vec![
103            ActionType::Call {
104                function: "performDiagnostics".to_string(),
105                args: vec![
106                    Value::String("Car.Engine".to_string()),
107                    Value::String("Car.Speed".to_string()),
108                ],
109            },
110            ActionType::Call {
111                function: "optimizePerformance".to_string(),
112                args: vec![
113                    Value::String("Car.Speed".to_string()),
114                    Value::String("Car.MaxSpeed".to_string()),
115                ],
116            },
117        ],
118    )
119    .with_salience(10);
120
121    // Add rules to knowledge base
122    let _ = kb.add_rule(speed_check_rule);
123    let _ = kb.add_rule(driver_validation_rule);
124    let _ = kb.add_rule(engine_diagnostics_rule);
125
126    // Create engine
127    let config = EngineConfig {
128        debug_mode: true,
129        max_cycles: 3,
130        ..Default::default()
131    };
132    let mut engine = RustRuleEngine::with_config(kb, config);
133
134    // Register custom functions
135    println!("šŸ“ Registering custom functions...");
136
137    // Function 1: Check speed limit
138    engine.register_function("checkSpeedLimit", |args, facts| {
139        let speed_field = args.get(0).unwrap().to_string();
140        let limit = args.get(1).unwrap();
141
142        // Get actual speed value from facts
143        let speed = if let Some(car) = facts.get("Car") {
144            if let Value::Object(obj) = car {
145                obj.get("Speed").cloned().unwrap_or(Value::Number(0.0))
146            } else {
147                Value::Number(0.0)
148            }
149        } else {
150            Value::Number(0.0)
151        };
152
153        let result = format!("Speed check: {:?} vs limit {:?}", speed, limit);
154        println!("🚦 {}", result);
155        Ok(Value::String(result))
156    });
157
158    // Function 2: Send alert
159    engine.register_function("sendAlert", |args, facts| {
160        let message = args.get(0).unwrap().to_string();
161        let driver_field = args.get(1).unwrap().to_string();
162
163        // Get driver name from facts
164        let driver_name = if let Some(driver) = facts.get("Driver") {
165            if let Value::Object(obj) = driver {
166                obj.get("Name")
167                    .cloned()
168                    .unwrap_or(Value::String("Unknown".to_string()))
169            } else {
170                Value::String("Unknown".to_string())
171            }
172        } else {
173            Value::String("Unknown".to_string())
174        };
175
176        let alert = format!("🚨 ALERT to {:?}: {}", driver_name, message);
177        println!("{}", alert);
178        Ok(Value::String(alert))
179    });
180
181    // Function 3: Validate driver
182    engine.register_function("validateDriver", |args, _facts| {
183        let name_field = args.get(0).unwrap().to_string();
184        let exp_field = args.get(1).unwrap().to_string();
185
186        let result = format!(
187            "āœ… Driver validation passed for {} (experience: {})",
188            name_field, exp_field
189        );
190        println!("{}", result);
191        Ok(Value::String(result))
192    });
193
194    // Function 4: Calculate insurance
195    engine.register_function("calculateInsurance", |args, _facts| {
196        let exp_field = args.get(0).unwrap().to_string();
197        let engine_field = args.get(1).unwrap().to_string();
198
199        let result = format!(
200            "šŸ’° Insurance calculated: Experience {} + Engine {} = Premium rate",
201            exp_field, engine_field
202        );
203        println!("{}", result);
204        Ok(Value::String(result))
205    });
206
207    // Function 5: Perform diagnostics
208    engine.register_function("performDiagnostics", |args, _facts| {
209        let engine_field = args.get(0).unwrap().to_string();
210        let speed_field = args.get(1).unwrap().to_string();
211
212        let result = format!(
213            "šŸ”§ Diagnostics: Engine {} running at speed {} - All systems OK",
214            engine_field, speed_field
215        );
216        println!("{}", result);
217        Ok(Value::String(result))
218    });
219
220    // Function 6: Optimize performance
221    engine.register_function("optimizePerformance", |args, _facts| {
222        let current_speed = args.get(0).unwrap().to_string();
223        let max_speed = args.get(1).unwrap().to_string();
224
225        let result = format!(
226            "⚔ Performance optimization: Current {} / Max {} - Efficiency tuned",
227            current_speed, max_speed
228        );
229        println!("{}", result);
230        Ok(Value::String(result))
231    });
232
233    println!("āœ… Registered {} custom functions:", 6);
234    println!("   🚦 checkSpeedLimit - Check if speed exceeds limit");
235    println!("   🚨 sendAlert - Send alert message to driver");
236    println!("   āœ… validateDriver - Validate driver credentials");
237    println!("   šŸ’° calculateInsurance - Calculate insurance premium");
238    println!("   šŸ”§ performDiagnostics - Run engine diagnostics");
239    println!("   ⚔ optimizePerformance - Optimize engine performance");
240    println!();
241
242    // Execute rules
243    println!("šŸš€ Executing rules with custom functions...");
244    let result = engine.execute(&facts)?;
245
246    println!("\nšŸ“Š Custom Function Execution Results:");
247    println!("   Cycles: {}", result.cycle_count);
248    println!("   Rules evaluated: {}", result.rules_evaluated);
249    println!("   Rules fired: {}", result.rules_fired);
250    println!("   Execution time: {:?}", result.execution_time);
251
252    println!("\nšŸ Final state:");
253    if let Some(car) = facts.get("Car") {
254        println!("   Car = {car:?}");
255    }
256    if let Some(driver) = facts.get("Driver") {
257        println!("   Driver = {driver:?}");
258    }
259
260    println!("\nšŸŽÆ Custom Function Calls Demonstrated:");
261    println!("   šŸ“ž User-defined functions called from rules");
262    println!("   šŸ”§ Custom business logic execution");
263    println!("   šŸŽŖ Function registry system");
264    println!("   šŸ“‹ Rule-based custom function invocation");
265    println!("   ⚔ Real-time function parameter resolution");
266
267    Ok(())
268}