KnowledgeBase

Struct KnowledgeBase 

Source
pub struct KnowledgeBase { /* private fields */ }
Expand description

Knowledge Base - manages collections of rules and facts Similar to Grule’s KnowledgeBase concept

ImplementationsΒ§

SourceΒ§

impl KnowledgeBase

Source

pub fn new(name: &str) -> Self

Create a new knowledge base

Examples found in repository?
examples/grule_demo.rs (line 32)
27fn demo_knowledge_base() -> std::result::Result<(), Box<dyn std::error::Error>> {
28    println!("πŸ“š Demo 1: Knowledge Base with Code-based Rules");
29    println!("-----------------------------------------------");
30
31    // Create knowledge base
32    let kb = KnowledgeBase::new("UserRules");
33
34    println!("βœ… Knowledge Base created: {}", kb.get_statistics().name);
35    println!("   Total rules: {}", kb.get_statistics().total_rules);
36    println!("   Version: {}\n", kb.get_statistics().version);
37
38    Ok(())
39}
40
41fn demo_facts_manipulation() -> std::result::Result<(), Box<dyn std::error::Error>> {
42    println!("πŸ—‚οΈ Demo 2: Facts Manipulation");
43    println!("-----------------------------");
44
45    // Create facts
46    let facts = Facts::new();
47
48    // Add user data
49    let mut user_props = HashMap::new();
50    user_props.insert("Name".to_string(), Value::String("John Doe".to_string()));
51    user_props.insert("Age".to_string(), Value::Integer(25));
52    user_props.insert("Country".to_string(), Value::String("US".to_string()));
53    user_props.insert("SpendingTotal".to_string(), Value::Number(1500.0));
54    user_props.insert("IsAdult".to_string(), Value::Boolean(false));
55    user_props.insert("IsVIP".to_string(), Value::Boolean(false));
56
57    facts.add_value("User", Value::Object(user_props))?;
58
59    println!("βœ… Facts created and populated:");
60    if let Some(user) = facts.get("User") {
61        println!("   User = {user:?}");
62    }
63    println!();
64
65    Ok(())
66}
67
68fn demo_engine_execution() -> std::result::Result<(), Box<dyn std::error::Error>> {
69    println!("πŸš€ Demo 3: Engine Execution");
70    println!("---------------------------");
71
72    // Create facts
73    let facts = Facts::new();
74    let mut user_props = HashMap::new();
75    user_props.insert("Age".to_string(), Value::Integer(25));
76    user_props.insert("Country".to_string(), Value::String("US".to_string()));
77    user_props.insert("SpendingTotal".to_string(), Value::Number(1500.0));
78    user_props.insert("IsAdult".to_string(), Value::Boolean(false));
79    user_props.insert("IsVIP".to_string(), Value::Boolean(false));
80    user_props.insert("Category".to_string(), Value::String("unknown".to_string()));
81    user_props.insert("DiscountRate".to_string(), Value::Number(0.0));
82
83    facts.add_value("User", Value::Object(user_props))?;
84
85    // Create knowledge base
86    let mut kb = KnowledgeBase::new("UserRules");
87
88    // Rule 1: Adult Check (salience 10)
89    let adult_rule = Rule::new(
90        "AdultCheck".to_string(),
91        ConditionGroup::and(
92            ConditionGroup::single(Condition::new(
93                "User.Age".to_string(),
94                Operator::GreaterThanOrEqual,
95                Value::Integer(18),
96            )),
97            ConditionGroup::single(Condition::new(
98                "User.Country".to_string(),
99                Operator::Equal,
100                Value::String("US".to_string()),
101            )),
102        ),
103        vec![
104            ActionType::MethodCall {
105                object: "User".to_string(),
106                method: "setIsAdult".to_string(),
107                args: vec![Value::Boolean(true)],
108            },
109            ActionType::MethodCall {
110                object: "User".to_string(),
111                method: "setCategory".to_string(),
112                args: vec![Value::String("Adult".to_string())],
113            },
114            ActionType::Call {
115                function: "log".to_string(),
116                args: vec![Value::String("User qualified as adult".to_string())],
117            },
118        ],
119    )
120    .with_salience(10);
121
122    // Rule 2: VIP Check (salience 20)
123    let vip_rule = Rule::new(
124        "VIPCheck".to_string(),
125        ConditionGroup::and(
126            ConditionGroup::and(
127                ConditionGroup::single(Condition::new(
128                    "User.Age".to_string(),
129                    Operator::GreaterThanOrEqual,
130                    Value::Integer(21),
131                )),
132                ConditionGroup::single(Condition::new(
133                    "User.IsAdult".to_string(),
134                    Operator::Equal,
135                    Value::Boolean(true),
136                )),
137            ),
138            ConditionGroup::single(Condition::new(
139                "User.SpendingTotal".to_string(),
140                Operator::GreaterThan,
141                Value::Number(1000.0),
142            )),
143        ),
144        vec![
145            ActionType::MethodCall {
146                object: "User".to_string(),
147                method: "setIsVIP".to_string(),
148                args: vec![Value::Boolean(true)],
149            },
150            ActionType::MethodCall {
151                object: "User".to_string(),
152                method: "setDiscountRate".to_string(),
153                args: vec![Value::Number(0.15)],
154            },
155            ActionType::Call {
156                function: "log".to_string(),
157                args: vec![Value::String("User upgraded to VIP".to_string())],
158            },
159        ],
160    )
161    .with_salience(20);
162
163    // Rule 3: Senior Discount (salience 15)
164    let senior_rule = Rule::new(
165        "SeniorDiscount".to_string(),
166        ConditionGroup::single(Condition::new(
167            "User.Age".to_string(),
168            Operator::GreaterThanOrEqual,
169            Value::Integer(65),
170        )),
171        vec![
172            ActionType::MethodCall {
173                object: "User".to_string(),
174                method: "setDiscountRate".to_string(),
175                args: vec![Value::Number(0.20)],
176            },
177            ActionType::MethodCall {
178                object: "User".to_string(),
179                method: "setCategory".to_string(),
180                args: vec![Value::String("Senior".to_string())],
181            },
182            ActionType::Call {
183                function: "log".to_string(),
184                args: vec![Value::String("Senior discount applied".to_string())],
185            },
186        ],
187    )
188    .with_salience(15);
189
190    // Add rules to knowledge base
191    let _ = kb.add_rule(adult_rule);
192    let _ = kb.add_rule(vip_rule);
193    let _ = kb.add_rule(senior_rule);
194
195    // Create engine
196    let config = EngineConfig {
197        debug_mode: true,
198        max_cycles: 3,
199        ..Default::default()
200    };
201    let engine = RustRuleEngine::with_config(kb, config);
202
203    println!("🏁 Initial state:");
204    if let Some(user) = facts.get("User") {
205        println!("   User = {user:?}");
206    }
207    println!();
208
209    // Execute rules
210    println!("πŸš€ Executing rules...");
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🏁 Final state:");
220    if let Some(user) = facts.get("User") {
221        println!("   User = {user:?}");
222    }
223    println!();
224
225    Ok(())
226}
227
228fn demo_ecommerce_scenario() -> std::result::Result<(), Box<dyn std::error::Error>> {
229    println!("πŸ›’ Demo 4: E-commerce Scenario");
230    println!("------------------------------");
231
232    // Create facts
233    let facts = Facts::new();
234
235    // Customer data
236    let mut customer_props = HashMap::new();
237    customer_props.insert(
238        "Email".to_string(),
239        Value::String("customer@example.com".to_string()),
240    );
241    customer_props.insert("Age".to_string(), Value::Integer(28));
242    customer_props.insert("IsNew".to_string(), Value::Boolean(true));
243    customer_props.insert("LoyaltyPoints".to_string(), Value::Integer(0));
244    customer_props.insert("TotalSpent".to_string(), Value::Number(0.0));
245
246    // Order data
247    let mut order_props = HashMap::new();
248    order_props.insert("Id".to_string(), Value::String("ORD-12345".to_string()));
249    order_props.insert("Amount".to_string(), Value::Number(150.0));
250    order_props.insert(
251        "Category".to_string(),
252        Value::String("electronics".to_string()),
253    );
254    order_props.insert("DiscountPercent".to_string(), Value::Number(0.0));
255    order_props.insert("FinalAmount".to_string(), Value::Number(150.0));
256
257    facts.add_value("Customer", Value::Object(customer_props))?;
258    facts.add_value("Order", Value::Object(order_props))?;
259
260    // Create knowledge base
261    let mut kb = KnowledgeBase::new("EcommerceRules");
262
263    // Rule 1: New Customer Discount
264    let new_customer_rule = Rule::new(
265        "NewCustomerDiscount".to_string(),
266        ConditionGroup::and(
267            ConditionGroup::single(Condition::new(
268                "Customer.IsNew".to_string(),
269                Operator::Equal,
270                Value::Boolean(true),
271            )),
272            ConditionGroup::single(Condition::new(
273                "Order.Amount".to_string(),
274                Operator::GreaterThan,
275                Value::Number(100.0),
276            )),
277        ),
278        vec![
279            ActionType::MethodCall {
280                object: "Order".to_string(),
281                method: "setDiscountPercent".to_string(),
282                args: vec![Value::Number(10.0)],
283            },
284            ActionType::MethodCall {
285                object: "Customer".to_string(),
286                method: "setLoyaltyPoints".to_string(),
287                args: vec![Value::Integer(100)],
288            },
289            ActionType::Call {
290                function: "log".to_string(),
291                args: vec![Value::String("New customer discount applied".to_string())],
292            },
293        ],
294    )
295    .with_salience(10);
296
297    // Rule 2: Calculate Final Amount
298    let calculate_final_rule = Rule::new(
299        "CalculateFinalAmount".to_string(),
300        ConditionGroup::single(Condition::new(
301            "Order.DiscountPercent".to_string(),
302            Operator::GreaterThan,
303            Value::Number(0.0),
304        )),
305        vec![ActionType::Call {
306            function: "log".to_string(),
307            args: vec![Value::String(
308                "Calculating final amount with discount".to_string(),
309            )],
310        }],
311    )
312    .with_salience(5);
313
314    // Add rules
315    let _ = kb.add_rule(new_customer_rule);
316    let _ = kb.add_rule(calculate_final_rule);
317
318    // Create engine
319    let config = EngineConfig {
320        debug_mode: true,
321        max_cycles: 3,
322        ..Default::default()
323    };
324    let engine = RustRuleEngine::with_config(kb, config);
325
326    println!("🏁 Initial e-commerce state:");
327    if let Some(customer) = facts.get("Customer") {
328        println!("   Customer = {customer:?}");
329    }
330    if let Some(order) = facts.get("Order") {
331        println!("   Order = {order:?}");
332    }
333    println!();
334
335    // Execute rules
336    println!("πŸš€ Executing e-commerce rules...");
337    let result = engine.execute(&facts)?;
338
339    println!("\nπŸ“Š E-commerce Results:");
340    println!("   Cycles: {}", result.cycle_count);
341    println!("   Rules evaluated: {}", result.rules_evaluated);
342    println!("   Rules fired: {}", result.rules_fired);
343    println!("   Execution time: {:?}", result.execution_time);
344
345    println!("\n🏁 Final e-commerce state:");
346    if let Some(customer) = facts.get("Customer") {
347        println!("   Customer = {customer:?}");
348    }
349    if let Some(order) = facts.get("Order") {
350        println!("   Order = {order:?}");
351    }
352
353    println!("\n🎯 Demo Completed Successfully!");
354    println!("   βœ… Knowledge Base management");
355    println!("   βœ… Facts manipulation");
356    println!("   βœ… Rule execution engine");
357    println!("   βœ… E-commerce scenario");
358    println!("   βœ… Method calls and function calls");
359    println!("   βœ… Salience-based rule ordering");
360
361    Ok(())
362}
More examples
Hide additional examples
examples/debug_conditions.rs (line 13)
9fn test_simple_conditions() -> std::result::Result<(), Box<dyn Error>> {
10    println!("=== Testing Simple Conditions ===");
11
12    // Create Knowledge Base
13    let kb = KnowledgeBase::new("TestConditions");
14
15    // Test compound condition with &&
16    let compound_rule = r#"rule "CompoundRule" { when TestCar.speedUp == true && TestCar.speed < TestCar.maxSpeed then TestCar.result = "compound_fired"; }"#;
17
18    println!("Testing rule: {}", compound_rule);
19
20    // Parse and add rule
21    let rules = GRLParser::parse_rules(compound_rule)?;
22    let rule = rules.into_iter().next().unwrap();
23    println!("Parsed rule: {:?}", rule);
24
25    let _ = kb.add_rule(rule);
26
27    // Create engine with debug mode
28    let config = EngineConfig {
29        max_cycles: 10,
30        timeout: None,
31        enable_stats: true,
32        debug_mode: true,
33    };
34    let engine = RustRuleEngine::with_config(kb, config);
35
36    // Create facts
37    let facts = Facts::new();
38
39    // Create simple TestCar object with all needed properties
40    let test_car = FactHelper::create_object(vec![
41        ("speedUp", Value::Boolean(true)),
42        ("speed", Value::Number(30.0)),
43        ("maxSpeed", Value::Number(100.0)),
44        ("result", Value::String("not_fired".to_string())),
45    ]);
46
47    facts.add_value("TestCar", test_car)?;
48
49    println!("\n🏁 Before execution:");
50    if let Some(car) = facts.get("TestCar") {
51        println!("   TestCar.speedUp = {:?}", car.get_property("speedUp"));
52        println!("   TestCar.speed = {:?}", car.get_property("speed"));
53        println!("   TestCar.maxSpeed = {:?}", car.get_property("maxSpeed"));
54        println!("   TestCar.result = {:?}", car.get_property("result"));
55    }
56
57    // Execute rules
58    println!("\nπŸš€ Executing rule...");
59    let result = engine.execute(&facts)?;
60
61    println!("Rules fired: {}", result.rules_fired);
62
63    println!("\n🏁 After execution:");
64    if let Some(car) = facts.get("TestCar") {
65        println!("   TestCar.speedUp = {:?}", car.get_property("speedUp"));
66        println!("   TestCar.result = {:?}", car.get_property("result"));
67    }
68
69    Ok(())
70}
examples/advanced_method_calls.rs (line 13)
9fn demo_method_calls() -> std::result::Result<(), Box<dyn Error>> {
10    println!("=== Demo: Advanced Method Calls ===");
11
12    // Create Knowledge Base
13    let kb = KnowledgeBase::new("MethodCallsDemo");
14
15    // Define rule with simpler condition first
16    let speedup_rule = r#"rule "SpeedUp" salience 10 { 
17        when TestCar.speedUp == true 
18        then TestCar.Speed = 70; 
19    }"#;
20
21    // Parse and add rule
22    let rules = GRLParser::parse_rules(speedup_rule)?;
23    let rule = rules.into_iter().next().unwrap();
24    let _ = kb.add_rule(rule);
25
26    // Create engine with debug mode
27    let config = EngineConfig {
28        max_cycles: 10,
29        timeout: None,
30        enable_stats: true,
31        debug_mode: true,
32    };
33    let engine = RustRuleEngine::with_config(kb, config);
34
35    // Create facts
36    let facts = Facts::new();
37
38    // Create TestCar object using helper
39    let test_car = FactHelper::create_test_car(
40        true,  // speedUp
41        50.0,  // speed
42        100.0, // maxSpeed
43        10.0,  // speedIncrement
44    );
45
46    // Create DistanceRecord object using helper
47    let distance_record = FactHelper::create_distance_record(0.0);
48
49    // Add facts
50    facts.add_value("TestCar", test_car)?;
51    facts.add_value("DistanceRecord", distance_record)?;
52
53    println!("\n🏁 Initial state:");
54    if let Some(car) = facts.get("TestCar") {
55        if let Some(speed) = car.get_property("Speed") {
56            println!("   TestCar.Speed = {:?}", speed);
57        }
58        if let Some(speed_up) = car.get_property("speedUp") {
59            println!("   TestCar.speedUp = {:?}", speed_up);
60        }
61    }
62
63    // Execute rules multiple cycles to see progression
64    println!("\nπŸš€ Executing SpeedUp rule multiple times...");
65    for i in 1..=3 {
66        println!("\n--- Cycle {} ---", i);
67        let result = engine.execute(&facts)?;
68
69        println!("Rules fired: {}", result.rules_fired);
70
71        if let Some(car) = facts.get("TestCar") {
72            if let Some(speed) = car.get_property("Speed") {
73                println!("TestCar.Speed after cycle {}: {:?}", i, speed);
74            }
75        }
76
77        // Check if we reached max speed
78        if let Some(car) = facts.get("TestCar") {
79            if let Some(speed) = car.get_property("speed") {
80                if let Some(max_speed) = car.get_property("maxSpeed") {
81                    if speed.to_number() >= max_speed.to_number() {
82                        println!("🏁 Max speed reached!");
83                        break;
84                    }
85                }
86            }
87        }
88    }
89
90    println!("\nπŸ“Š Final Results:");
91    if let Some(car) = facts.get("TestCar") {
92        if let Some(speed) = car.get_property("Speed") {
93            println!("   Final TestCar.Speed = {:?}", speed);
94        }
95    }
96
97    Ok(())
98}
examples/generic_method_calls.rs (line 37)
8fn main() -> Result<(), Box<dyn std::error::Error>> {
9    println!("=== Demo: Generic Method Calls ===\n");
10
11    // Create objects with various properties
12    let mut car_props = HashMap::new();
13    car_props.insert("Speed".to_string(), Value::Number(50.0));
14    car_props.insert("Fuel".to_string(), Value::Number(80.0));
15    car_props.insert("Brand".to_string(), Value::String("Toyota".to_string()));
16
17    let mut account_props = HashMap::new();
18    account_props.insert("Balance".to_string(), Value::Number(1000.0));
19    account_props.insert("Owner".to_string(), Value::String("John Doe".to_string()));
20    account_props.insert("Active".to_string(), Value::Boolean(true));
21
22    // Create facts
23    let facts = Facts::new();
24    facts.add_value("Car", Value::Object(car_props))?;
25    facts.add_value("Account", Value::Object(account_props))?;
26
27    println!("🏁 Initial state:");
28    if let Some(car) = facts.get("Car") {
29        println!("   Car = {car:?}");
30    }
31    if let Some(account) = facts.get("Account") {
32        println!("   Account = {account:?}");
33    }
34    println!();
35
36    // Create knowledge base
37    let mut kb = KnowledgeBase::new("GenericMethodDemo");
38
39    // Rule 1: Speed up car if speed < 60
40    let speed_rule = Rule::new(
41        "SpeedUpCar".to_string(),
42        ConditionGroup::single(Condition::new(
43            "Car.Speed".to_string(),
44            Operator::LessThan,
45            Value::Number(60.0),
46        )),
47        vec![ActionType::MethodCall {
48            object: "Car".to_string(),
49            method: "setSpeed".to_string(), // Generic setter
50            args: vec![Value::Number(75.0)],
51        }],
52    )
53    .with_salience(10);
54
55    // Rule 2: Withdraw from account if balance > 500
56    let withdraw_rule = Rule::new(
57        "WithdrawMoney".to_string(),
58        ConditionGroup::single(Condition::new(
59            "Account.Balance".to_string(),
60            Operator::GreaterThan,
61            Value::Number(500.0),
62        )),
63        vec![ActionType::MethodCall {
64            object: "Account".to_string(),
65            method: "setBalance".to_string(), // Generic setter
66            args: vec![Value::Number(800.0)],
67        }],
68    )
69    .with_salience(5);
70
71    // Rule 3: Update car brand using generic setter
72    let brand_rule = Rule::new(
73        "UpdateBrand".to_string(),
74        ConditionGroup::single(Condition::new(
75            "Car.Brand".to_string(),
76            Operator::Equal,
77            Value::String("Toyota".to_string()),
78        )),
79        vec![ActionType::MethodCall {
80            object: "Car".to_string(),
81            method: "setBrand".to_string(), // Generic setter
82            args: vec![Value::String("Honda".to_string())],
83        }],
84    )
85    .with_salience(3);
86
87    // Add rules to knowledge base
88    let _ = kb.add_rule(speed_rule);
89    let _ = kb.add_rule(withdraw_rule);
90    let _ = kb.add_rule(brand_rule);
91
92    // Create engine with debug mode
93    let config = EngineConfig {
94        debug_mode: true,
95        max_cycles: 10,
96        ..Default::default()
97    };
98    let engine = RustRuleEngine::with_config(kb, config);
99
100    // Execute rules
101    println!("πŸš€ Executing rules with generic method calls...");
102    let result = engine.execute(&facts)?;
103
104    println!("\nπŸ“Š Execution Results:");
105    println!("   Cycles: {}", result.cycle_count);
106    println!("   Rules evaluated: {}", result.rules_evaluated);
107    println!("   Rules fired: {}", result.rules_fired);
108    println!("   Execution time: {:?}", result.execution_time);
109
110    println!("\n🏁 Final state:");
111    if let Some(car) = facts.get("Car") {
112        println!("   Car = {car:?}");
113    }
114    if let Some(account) = facts.get("Account") {
115        println!("   Account = {account:?}");
116    }
117
118    // Demonstrate generic getters
119    println!("\nπŸ” Testing generic getters:");
120    if let Some(car_value) = facts.get("Car") {
121        if let Value::Object(car_obj) = car_value {
122            println!(
123                "   Car.Speed via getter would return: {:?}",
124                car_obj.get("Speed")
125            );
126            println!(
127                "   Car.Brand via getter would return: {:?}",
128                car_obj.get("Brand")
129            );
130            println!(
131                "   Car.Fuel via getter would return: {:?}",
132                car_obj.get("Fuel")
133            );
134        }
135    }
136
137    Ok(())
138}
examples/method_calls_demo.rs (line 44)
9fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
10    println!("🎯 Method Calls Demo with Rule File");
11    println!("===================================\n");
12
13    // Read rules from file
14    let rule_file_path = "examples/rules/method_calls.grl";
15    println!("πŸ“„ Reading rules from file: {}", rule_file_path);
16
17    let rule_content = fs::read_to_string(rule_file_path)
18        .map_err(|e| format!("Failed to read rule file: {}", e))?;
19
20    println!("πŸ“‹ Rule file content:");
21    println!("---");
22    println!("{}", rule_content);
23    println!("---\n");
24
25    // Create facts
26    let facts = Facts::new();
27
28    // TestCar data
29    let mut test_car_props = HashMap::new();
30    test_car_props.insert("Speed".to_string(), Value::Number(30.0));
31    test_car_props.insert("MaxSpeed".to_string(), Value::Number(100.0));
32    test_car_props.insert("SpeedIncrement".to_string(), Value::Number(10.0));
33    test_car_props.insert("SpeedUp".to_string(), Value::Boolean(true));
34
35    facts.add_value("TestCar", Value::Object(test_car_props))?;
36
37    println!("🏁 Initial state:");
38    if let Some(car) = facts.get("TestCar") {
39        println!("   TestCar = {car:?}");
40    }
41    println!();
42
43    // Create knowledge base and add rules from GRL file
44    let kb = KnowledgeBase::new("MethodCallsDemo");
45
46    // Parse rules from GRL file
47    println!("πŸ”§ Parsing GRL file content...");
48    let rules = GRLParser::parse_rules(&rule_content)
49        .map_err(|e| format!("Failed to parse GRL file: {:?}", e))?;
50
51    println!("βœ… Successfully parsed {} rules from file", rules.len());
52    for rule in &rules {
53        println!("   πŸ“‹ Rule: {} (salience: {})", rule.name, rule.salience);
54        let _ = kb.add_rule(rule.clone());
55    }
56    println!();
57
58    // Create engine
59    let config = EngineConfig {
60        debug_mode: true,
61        max_cycles: 5,
62        ..Default::default()
63    };
64    let mut engine = RustRuleEngine::with_config(kb, config);
65
66    // Register custom functions for speed control
67    engine.register_function("increaseSpeed", |_args, facts| {
68        if let Some(car) = facts.get("TestCar") {
69            if let Value::Object(obj) = car {
70                let current_speed = obj.get("Speed").cloned().unwrap_or(Value::Number(0.0));
71                let increment = obj
72                    .get("SpeedIncrement")
73                    .cloned()
74                    .unwrap_or(Value::Number(10.0));
75
76                if let (Value::Number(speed), Value::Number(inc)) = (current_speed, increment) {
77                    let new_speed = speed + inc;
78                    println!("πŸš— Increasing speed: {} -> {}", speed, new_speed);
79                    // In real implementation, this would update the fact
80                    return Ok(Value::Number(new_speed));
81                }
82            }
83        }
84        Ok(Value::String("Speed increase attempted".to_string()))
85    });
86
87    engine.register_function("decreaseSpeed", |_args, facts| {
88        if let Some(car) = facts.get("TestCar") {
89            if let Value::Object(obj) = car {
90                let current_speed = obj.get("Speed").cloned().unwrap_or(Value::Number(0.0));
91                let increment = obj
92                    .get("SpeedIncrement")
93                    .cloned()
94                    .unwrap_or(Value::Number(10.0));
95
96                if let (Value::Number(speed), Value::Number(inc)) = (current_speed, increment) {
97                    let new_speed = (speed - inc).max(0.0);
98                    println!("πŸš— Decreasing speed: {} -> {}", speed, new_speed);
99                    // In real implementation, this would update the fact
100                    return Ok(Value::Number(new_speed));
101                }
102            }
103        }
104        Ok(Value::String("Speed decrease attempted".to_string()))
105    });
106
107    // Execute rules
108    println!("πŸš€ Executing method calls rules from file...");
109    let result = engine.execute(&facts)?;
110
111    println!("\nπŸ“Š Method Calls Execution Results:");
112    println!("   Cycles: {}", result.cycle_count);
113    println!("   Rules evaluated: {}", result.rules_evaluated);
114    println!("   Rules fired: {}", result.rules_fired);
115    println!("   Execution time: {:?}", result.execution_time);
116
117    println!("\n🏁 Final state:");
118    if let Some(car) = facts.get("TestCar") {
119        println!("   TestCar = {car:?}");
120    }
121
122    println!("\n🎯 Method Calls from Rule File Demonstrated:");
123    println!("   πŸ“„ Rules defined in external .grl file");
124    println!("   πŸ”§ Method calls: setSpeed(), setSpeedUp()");
125    println!("   πŸ“ž Custom functions: increaseSpeed(), decreaseSpeed()");
126    println!("   πŸš— Speed control simulation");
127    println!("   ⚑ Salience-based rule execution order");
128
129    Ok(())
130}
examples/complete_speedup_demo.rs (line 24)
9fn demo_complete_speedup_rule() -> std::result::Result<(), Box<dyn Error>> {
10    println!("=== Demo: Complete SpeedUp Rule with Method Calls ===");
11    println!("Implementing the exact rule from the requirement:");
12    println!("rule \"SpeedUp\" salience 10");
13    println!("when");
14    println!("    $TestCar : TestCarClass( speedUp == true && speed < maxSpeed )");
15    println!("    $DistanceRecord : DistanceRecordClass()");
16    println!("then");
17    println!("    $TestCar.setSpeed($TestCar.Speed + $TestCar.SpeedIncrement);");
18    println!("    update($TestCar);");
19    println!("    $DistanceRecord.setTotalDistance($DistanceRecord.getTotalDistance() + $TestCar.Speed);");
20    println!("    update($DistanceRecord);");
21    println!("end\n");
22
23    // Create Knowledge Base
24    let kb = KnowledgeBase::new("SpeedUpDemo");
25
26    // For now, we'll use a simplified version that works with our current parser
27    let speedup_rule = r#"rule "SpeedUp" salience 10 { 
28        when TestCar.speedUp == true && TestCar.speed < TestCar.maxSpeed 
29        then $TestCar.setSpeed($TestCar.Speed + $TestCar.SpeedIncrement); update($TestCar); $DistanceRecord.setTotalDistance($DistanceRecord.getTotalDistance() + $TestCar.Speed); update($DistanceRecord); 
30    }"#;
31
32    // Parse and add rule
33    let rules = GRLParser::parse_rules(speedup_rule)?;
34    let rule = rules.into_iter().next().unwrap();
35    let _ = kb.add_rule(rule);
36
37    // Create engine with debug mode
38    let config = EngineConfig {
39        max_cycles: 10,
40        timeout: None,
41        enable_stats: true,
42        debug_mode: true,
43    };
44    let engine = RustRuleEngine::with_config(kb, config);
45
46    // Create facts
47    let facts = Facts::new();
48
49    // Create TestCar object - initial speed less than max
50    let test_car = FactHelper::create_test_car(
51        true,  // speedUp
52        30.0,  // speed (less than maxSpeed)
53        100.0, // maxSpeed
54        15.0,  // speedIncrement
55    );
56
57    // Create DistanceRecord object
58    let distance_record = FactHelper::create_distance_record(0.0);
59
60    // Add facts
61    facts.add_value("TestCar", test_car)?;
62    facts.add_value("DistanceRecord", distance_record)?;
63
64    println!("🏁 Initial state:");
65    if let Some(car) = facts.get("TestCar") {
66        println!(
67            "   TestCar.speed = {:?}",
68            car.get_property("speed").unwrap_or(Value::Null)
69        );
70        println!(
71            "   TestCar.Speed = {:?}",
72            car.get_property("Speed").unwrap_or(Value::Null)
73        );
74        println!(
75            "   TestCar.maxSpeed = {:?}",
76            car.get_property("maxSpeed").unwrap_or(Value::Null)
77        );
78        println!(
79            "   TestCar.speedUp = {:?}",
80            car.get_property("speedUp").unwrap_or(Value::Null)
81        );
82        println!(
83            "   TestCar.SpeedIncrement = {:?}",
84            car.get_property("SpeedIncrement").unwrap_or(Value::Null)
85        );
86    }
87    if let Some(record) = facts.get("DistanceRecord") {
88        println!(
89            "   DistanceRecord.TotalDistance = {:?}",
90            record.get_property("TotalDistance").unwrap_or(Value::Null)
91        );
92    }
93
94    // Execute rules multiple cycles
95    println!("\nπŸš€ Executing SpeedUp rule...");
96    for i in 1..=5 {
97        println!("\n--- Cycle {} ---", i);
98        let result = engine.execute(&facts)?;
99
100        println!("Rules fired: {}", result.rules_fired);
101
102        if let Some(car) = facts.get("TestCar") {
103            println!(
104                "TestCar.Speed = {:?}",
105                car.get_property("Speed").unwrap_or(Value::Null)
106            );
107            println!(
108                "TestCar.speed = {:?}",
109                car.get_property("speed").unwrap_or(Value::Null)
110            );
111        }
112        if let Some(record) = facts.get("DistanceRecord") {
113            println!(
114                "DistanceRecord.TotalDistance = {:?}",
115                record.get_property("TotalDistance").unwrap_or(Value::Null)
116            );
117        }
118
119        // Check if we reached max speed
120        if let Some(car) = facts.get("TestCar") {
121            if let Some(speed) = car.get_property("speed") {
122                if let Some(max_speed) = car.get_property("maxSpeed") {
123                    if speed.to_number() >= max_speed.to_number() {
124                        println!("🏁 Max speed reached! Rule will no longer fire.");
125                        break;
126                    }
127                }
128            }
129        }
130
131        if result.rules_fired == 0 {
132            println!("ℹ️ No rules fired this cycle.");
133            break;
134        }
135    }
136
137    println!("\nπŸ“Š Final Summary:");
138    println!("βœ… Successfully demonstrated method calls in GRL:");
139    println!("   β€’ Method calls: $Object.method(args)");
140    println!("   β€’ Property access: $Object.Property");
141    println!("   β€’ Arithmetic expressions: $A.prop + $B.prop");
142    println!("   β€’ update() function calls");
143    println!("   β€’ Complex conditions with && operator");
144
145    Ok(())
146}
Source

pub fn name(&self) -> &str

Get the knowledge base name

Source

pub fn version(&self) -> u64

Get the current version of the knowledge base

Source

pub fn add_rule(&self, rule: Rule) -> Result<()>

Add a rule to the knowledge base

Examples found in repository?
examples/debug_conditions.rs (line 25)
9fn test_simple_conditions() -> std::result::Result<(), Box<dyn Error>> {
10    println!("=== Testing Simple Conditions ===");
11
12    // Create Knowledge Base
13    let kb = KnowledgeBase::new("TestConditions");
14
15    // Test compound condition with &&
16    let compound_rule = r#"rule "CompoundRule" { when TestCar.speedUp == true && TestCar.speed < TestCar.maxSpeed then TestCar.result = "compound_fired"; }"#;
17
18    println!("Testing rule: {}", compound_rule);
19
20    // Parse and add rule
21    let rules = GRLParser::parse_rules(compound_rule)?;
22    let rule = rules.into_iter().next().unwrap();
23    println!("Parsed rule: {:?}", rule);
24
25    let _ = kb.add_rule(rule);
26
27    // Create engine with debug mode
28    let config = EngineConfig {
29        max_cycles: 10,
30        timeout: None,
31        enable_stats: true,
32        debug_mode: true,
33    };
34    let engine = RustRuleEngine::with_config(kb, config);
35
36    // Create facts
37    let facts = Facts::new();
38
39    // Create simple TestCar object with all needed properties
40    let test_car = FactHelper::create_object(vec![
41        ("speedUp", Value::Boolean(true)),
42        ("speed", Value::Number(30.0)),
43        ("maxSpeed", Value::Number(100.0)),
44        ("result", Value::String("not_fired".to_string())),
45    ]);
46
47    facts.add_value("TestCar", test_car)?;
48
49    println!("\n🏁 Before execution:");
50    if let Some(car) = facts.get("TestCar") {
51        println!("   TestCar.speedUp = {:?}", car.get_property("speedUp"));
52        println!("   TestCar.speed = {:?}", car.get_property("speed"));
53        println!("   TestCar.maxSpeed = {:?}", car.get_property("maxSpeed"));
54        println!("   TestCar.result = {:?}", car.get_property("result"));
55    }
56
57    // Execute rules
58    println!("\nπŸš€ Executing rule...");
59    let result = engine.execute(&facts)?;
60
61    println!("Rules fired: {}", result.rules_fired);
62
63    println!("\n🏁 After execution:");
64    if let Some(car) = facts.get("TestCar") {
65        println!("   TestCar.speedUp = {:?}", car.get_property("speedUp"));
66        println!("   TestCar.result = {:?}", car.get_property("result"));
67    }
68
69    Ok(())
70}
More examples
Hide additional examples
examples/advanced_method_calls.rs (line 24)
9fn demo_method_calls() -> std::result::Result<(), Box<dyn Error>> {
10    println!("=== Demo: Advanced Method Calls ===");
11
12    // Create Knowledge Base
13    let kb = KnowledgeBase::new("MethodCallsDemo");
14
15    // Define rule with simpler condition first
16    let speedup_rule = r#"rule "SpeedUp" salience 10 { 
17        when TestCar.speedUp == true 
18        then TestCar.Speed = 70; 
19    }"#;
20
21    // Parse and add rule
22    let rules = GRLParser::parse_rules(speedup_rule)?;
23    let rule = rules.into_iter().next().unwrap();
24    let _ = kb.add_rule(rule);
25
26    // Create engine with debug mode
27    let config = EngineConfig {
28        max_cycles: 10,
29        timeout: None,
30        enable_stats: true,
31        debug_mode: true,
32    };
33    let engine = RustRuleEngine::with_config(kb, config);
34
35    // Create facts
36    let facts = Facts::new();
37
38    // Create TestCar object using helper
39    let test_car = FactHelper::create_test_car(
40        true,  // speedUp
41        50.0,  // speed
42        100.0, // maxSpeed
43        10.0,  // speedIncrement
44    );
45
46    // Create DistanceRecord object using helper
47    let distance_record = FactHelper::create_distance_record(0.0);
48
49    // Add facts
50    facts.add_value("TestCar", test_car)?;
51    facts.add_value("DistanceRecord", distance_record)?;
52
53    println!("\n🏁 Initial state:");
54    if let Some(car) = facts.get("TestCar") {
55        if let Some(speed) = car.get_property("Speed") {
56            println!("   TestCar.Speed = {:?}", speed);
57        }
58        if let Some(speed_up) = car.get_property("speedUp") {
59            println!("   TestCar.speedUp = {:?}", speed_up);
60        }
61    }
62
63    // Execute rules multiple cycles to see progression
64    println!("\nπŸš€ Executing SpeedUp rule multiple times...");
65    for i in 1..=3 {
66        println!("\n--- Cycle {} ---", i);
67        let result = engine.execute(&facts)?;
68
69        println!("Rules fired: {}", result.rules_fired);
70
71        if let Some(car) = facts.get("TestCar") {
72            if let Some(speed) = car.get_property("Speed") {
73                println!("TestCar.Speed after cycle {}: {:?}", i, speed);
74            }
75        }
76
77        // Check if we reached max speed
78        if let Some(car) = facts.get("TestCar") {
79            if let Some(speed) = car.get_property("speed") {
80                if let Some(max_speed) = car.get_property("maxSpeed") {
81                    if speed.to_number() >= max_speed.to_number() {
82                        println!("🏁 Max speed reached!");
83                        break;
84                    }
85                }
86            }
87        }
88    }
89
90    println!("\nπŸ“Š Final Results:");
91    if let Some(car) = facts.get("TestCar") {
92        if let Some(speed) = car.get_property("Speed") {
93            println!("   Final TestCar.Speed = {:?}", speed);
94        }
95    }
96
97    Ok(())
98}
examples/generic_method_calls.rs (line 88)
8fn main() -> Result<(), Box<dyn std::error::Error>> {
9    println!("=== Demo: Generic Method Calls ===\n");
10
11    // Create objects with various properties
12    let mut car_props = HashMap::new();
13    car_props.insert("Speed".to_string(), Value::Number(50.0));
14    car_props.insert("Fuel".to_string(), Value::Number(80.0));
15    car_props.insert("Brand".to_string(), Value::String("Toyota".to_string()));
16
17    let mut account_props = HashMap::new();
18    account_props.insert("Balance".to_string(), Value::Number(1000.0));
19    account_props.insert("Owner".to_string(), Value::String("John Doe".to_string()));
20    account_props.insert("Active".to_string(), Value::Boolean(true));
21
22    // Create facts
23    let facts = Facts::new();
24    facts.add_value("Car", Value::Object(car_props))?;
25    facts.add_value("Account", Value::Object(account_props))?;
26
27    println!("🏁 Initial state:");
28    if let Some(car) = facts.get("Car") {
29        println!("   Car = {car:?}");
30    }
31    if let Some(account) = facts.get("Account") {
32        println!("   Account = {account:?}");
33    }
34    println!();
35
36    // Create knowledge base
37    let mut kb = KnowledgeBase::new("GenericMethodDemo");
38
39    // Rule 1: Speed up car if speed < 60
40    let speed_rule = Rule::new(
41        "SpeedUpCar".to_string(),
42        ConditionGroup::single(Condition::new(
43            "Car.Speed".to_string(),
44            Operator::LessThan,
45            Value::Number(60.0),
46        )),
47        vec![ActionType::MethodCall {
48            object: "Car".to_string(),
49            method: "setSpeed".to_string(), // Generic setter
50            args: vec![Value::Number(75.0)],
51        }],
52    )
53    .with_salience(10);
54
55    // Rule 2: Withdraw from account if balance > 500
56    let withdraw_rule = Rule::new(
57        "WithdrawMoney".to_string(),
58        ConditionGroup::single(Condition::new(
59            "Account.Balance".to_string(),
60            Operator::GreaterThan,
61            Value::Number(500.0),
62        )),
63        vec![ActionType::MethodCall {
64            object: "Account".to_string(),
65            method: "setBalance".to_string(), // Generic setter
66            args: vec![Value::Number(800.0)],
67        }],
68    )
69    .with_salience(5);
70
71    // Rule 3: Update car brand using generic setter
72    let brand_rule = Rule::new(
73        "UpdateBrand".to_string(),
74        ConditionGroup::single(Condition::new(
75            "Car.Brand".to_string(),
76            Operator::Equal,
77            Value::String("Toyota".to_string()),
78        )),
79        vec![ActionType::MethodCall {
80            object: "Car".to_string(),
81            method: "setBrand".to_string(), // Generic setter
82            args: vec![Value::String("Honda".to_string())],
83        }],
84    )
85    .with_salience(3);
86
87    // Add rules to knowledge base
88    let _ = kb.add_rule(speed_rule);
89    let _ = kb.add_rule(withdraw_rule);
90    let _ = kb.add_rule(brand_rule);
91
92    // Create engine with debug mode
93    let config = EngineConfig {
94        debug_mode: true,
95        max_cycles: 10,
96        ..Default::default()
97    };
98    let engine = RustRuleEngine::with_config(kb, config);
99
100    // Execute rules
101    println!("πŸš€ Executing rules with generic method calls...");
102    let result = engine.execute(&facts)?;
103
104    println!("\nπŸ“Š Execution Results:");
105    println!("   Cycles: {}", result.cycle_count);
106    println!("   Rules evaluated: {}", result.rules_evaluated);
107    println!("   Rules fired: {}", result.rules_fired);
108    println!("   Execution time: {:?}", result.execution_time);
109
110    println!("\n🏁 Final state:");
111    if let Some(car) = facts.get("Car") {
112        println!("   Car = {car:?}");
113    }
114    if let Some(account) = facts.get("Account") {
115        println!("   Account = {account:?}");
116    }
117
118    // Demonstrate generic getters
119    println!("\nπŸ” Testing generic getters:");
120    if let Some(car_value) = facts.get("Car") {
121        if let Value::Object(car_obj) = car_value {
122            println!(
123                "   Car.Speed via getter would return: {:?}",
124                car_obj.get("Speed")
125            );
126            println!(
127                "   Car.Brand via getter would return: {:?}",
128                car_obj.get("Brand")
129            );
130            println!(
131                "   Car.Fuel via getter would return: {:?}",
132                car_obj.get("Fuel")
133            );
134        }
135    }
136
137    Ok(())
138}
examples/method_calls_demo.rs (line 54)
9fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
10    println!("🎯 Method Calls Demo with Rule File");
11    println!("===================================\n");
12
13    // Read rules from file
14    let rule_file_path = "examples/rules/method_calls.grl";
15    println!("πŸ“„ Reading rules from file: {}", rule_file_path);
16
17    let rule_content = fs::read_to_string(rule_file_path)
18        .map_err(|e| format!("Failed to read rule file: {}", e))?;
19
20    println!("πŸ“‹ Rule file content:");
21    println!("---");
22    println!("{}", rule_content);
23    println!("---\n");
24
25    // Create facts
26    let facts = Facts::new();
27
28    // TestCar data
29    let mut test_car_props = HashMap::new();
30    test_car_props.insert("Speed".to_string(), Value::Number(30.0));
31    test_car_props.insert("MaxSpeed".to_string(), Value::Number(100.0));
32    test_car_props.insert("SpeedIncrement".to_string(), Value::Number(10.0));
33    test_car_props.insert("SpeedUp".to_string(), Value::Boolean(true));
34
35    facts.add_value("TestCar", Value::Object(test_car_props))?;
36
37    println!("🏁 Initial state:");
38    if let Some(car) = facts.get("TestCar") {
39        println!("   TestCar = {car:?}");
40    }
41    println!();
42
43    // Create knowledge base and add rules from GRL file
44    let kb = KnowledgeBase::new("MethodCallsDemo");
45
46    // Parse rules from GRL file
47    println!("πŸ”§ Parsing GRL file content...");
48    let rules = GRLParser::parse_rules(&rule_content)
49        .map_err(|e| format!("Failed to parse GRL file: {:?}", e))?;
50
51    println!("βœ… Successfully parsed {} rules from file", rules.len());
52    for rule in &rules {
53        println!("   πŸ“‹ Rule: {} (salience: {})", rule.name, rule.salience);
54        let _ = kb.add_rule(rule.clone());
55    }
56    println!();
57
58    // Create engine
59    let config = EngineConfig {
60        debug_mode: true,
61        max_cycles: 5,
62        ..Default::default()
63    };
64    let mut engine = RustRuleEngine::with_config(kb, config);
65
66    // Register custom functions for speed control
67    engine.register_function("increaseSpeed", |_args, facts| {
68        if let Some(car) = facts.get("TestCar") {
69            if let Value::Object(obj) = car {
70                let current_speed = obj.get("Speed").cloned().unwrap_or(Value::Number(0.0));
71                let increment = obj
72                    .get("SpeedIncrement")
73                    .cloned()
74                    .unwrap_or(Value::Number(10.0));
75
76                if let (Value::Number(speed), Value::Number(inc)) = (current_speed, increment) {
77                    let new_speed = speed + inc;
78                    println!("πŸš— Increasing speed: {} -> {}", speed, new_speed);
79                    // In real implementation, this would update the fact
80                    return Ok(Value::Number(new_speed));
81                }
82            }
83        }
84        Ok(Value::String("Speed increase attempted".to_string()))
85    });
86
87    engine.register_function("decreaseSpeed", |_args, facts| {
88        if let Some(car) = facts.get("TestCar") {
89            if let Value::Object(obj) = car {
90                let current_speed = obj.get("Speed").cloned().unwrap_or(Value::Number(0.0));
91                let increment = obj
92                    .get("SpeedIncrement")
93                    .cloned()
94                    .unwrap_or(Value::Number(10.0));
95
96                if let (Value::Number(speed), Value::Number(inc)) = (current_speed, increment) {
97                    let new_speed = (speed - inc).max(0.0);
98                    println!("πŸš— Decreasing speed: {} -> {}", speed, new_speed);
99                    // In real implementation, this would update the fact
100                    return Ok(Value::Number(new_speed));
101                }
102            }
103        }
104        Ok(Value::String("Speed decrease attempted".to_string()))
105    });
106
107    // Execute rules
108    println!("πŸš€ Executing method calls rules from file...");
109    let result = engine.execute(&facts)?;
110
111    println!("\nπŸ“Š Method Calls Execution Results:");
112    println!("   Cycles: {}", result.cycle_count);
113    println!("   Rules evaluated: {}", result.rules_evaluated);
114    println!("   Rules fired: {}", result.rules_fired);
115    println!("   Execution time: {:?}", result.execution_time);
116
117    println!("\n🏁 Final state:");
118    if let Some(car) = facts.get("TestCar") {
119        println!("   TestCar = {car:?}");
120    }
121
122    println!("\n🎯 Method Calls from Rule File Demonstrated:");
123    println!("   πŸ“„ Rules defined in external .grl file");
124    println!("   πŸ”§ Method calls: setSpeed(), setSpeedUp()");
125    println!("   πŸ“ž Custom functions: increaseSpeed(), decreaseSpeed()");
126    println!("   πŸš— Speed control simulation");
127    println!("   ⚑ Salience-based rule execution order");
128
129    Ok(())
130}
examples/complete_speedup_demo.rs (line 35)
9fn demo_complete_speedup_rule() -> std::result::Result<(), Box<dyn Error>> {
10    println!("=== Demo: Complete SpeedUp Rule with Method Calls ===");
11    println!("Implementing the exact rule from the requirement:");
12    println!("rule \"SpeedUp\" salience 10");
13    println!("when");
14    println!("    $TestCar : TestCarClass( speedUp == true && speed < maxSpeed )");
15    println!("    $DistanceRecord : DistanceRecordClass()");
16    println!("then");
17    println!("    $TestCar.setSpeed($TestCar.Speed + $TestCar.SpeedIncrement);");
18    println!("    update($TestCar);");
19    println!("    $DistanceRecord.setTotalDistance($DistanceRecord.getTotalDistance() + $TestCar.Speed);");
20    println!("    update($DistanceRecord);");
21    println!("end\n");
22
23    // Create Knowledge Base
24    let kb = KnowledgeBase::new("SpeedUpDemo");
25
26    // For now, we'll use a simplified version that works with our current parser
27    let speedup_rule = r#"rule "SpeedUp" salience 10 { 
28        when TestCar.speedUp == true && TestCar.speed < TestCar.maxSpeed 
29        then $TestCar.setSpeed($TestCar.Speed + $TestCar.SpeedIncrement); update($TestCar); $DistanceRecord.setTotalDistance($DistanceRecord.getTotalDistance() + $TestCar.Speed); update($DistanceRecord); 
30    }"#;
31
32    // Parse and add rule
33    let rules = GRLParser::parse_rules(speedup_rule)?;
34    let rule = rules.into_iter().next().unwrap();
35    let _ = kb.add_rule(rule);
36
37    // Create engine with debug mode
38    let config = EngineConfig {
39        max_cycles: 10,
40        timeout: None,
41        enable_stats: true,
42        debug_mode: true,
43    };
44    let engine = RustRuleEngine::with_config(kb, config);
45
46    // Create facts
47    let facts = Facts::new();
48
49    // Create TestCar object - initial speed less than max
50    let test_car = FactHelper::create_test_car(
51        true,  // speedUp
52        30.0,  // speed (less than maxSpeed)
53        100.0, // maxSpeed
54        15.0,  // speedIncrement
55    );
56
57    // Create DistanceRecord object
58    let distance_record = FactHelper::create_distance_record(0.0);
59
60    // Add facts
61    facts.add_value("TestCar", test_car)?;
62    facts.add_value("DistanceRecord", distance_record)?;
63
64    println!("🏁 Initial state:");
65    if let Some(car) = facts.get("TestCar") {
66        println!(
67            "   TestCar.speed = {:?}",
68            car.get_property("speed").unwrap_or(Value::Null)
69        );
70        println!(
71            "   TestCar.Speed = {:?}",
72            car.get_property("Speed").unwrap_or(Value::Null)
73        );
74        println!(
75            "   TestCar.maxSpeed = {:?}",
76            car.get_property("maxSpeed").unwrap_or(Value::Null)
77        );
78        println!(
79            "   TestCar.speedUp = {:?}",
80            car.get_property("speedUp").unwrap_or(Value::Null)
81        );
82        println!(
83            "   TestCar.SpeedIncrement = {:?}",
84            car.get_property("SpeedIncrement").unwrap_or(Value::Null)
85        );
86    }
87    if let Some(record) = facts.get("DistanceRecord") {
88        println!(
89            "   DistanceRecord.TotalDistance = {:?}",
90            record.get_property("TotalDistance").unwrap_or(Value::Null)
91        );
92    }
93
94    // Execute rules multiple cycles
95    println!("\nπŸš€ Executing SpeedUp rule...");
96    for i in 1..=5 {
97        println!("\n--- Cycle {} ---", i);
98        let result = engine.execute(&facts)?;
99
100        println!("Rules fired: {}", result.rules_fired);
101
102        if let Some(car) = facts.get("TestCar") {
103            println!(
104                "TestCar.Speed = {:?}",
105                car.get_property("Speed").unwrap_or(Value::Null)
106            );
107            println!(
108                "TestCar.speed = {:?}",
109                car.get_property("speed").unwrap_or(Value::Null)
110            );
111        }
112        if let Some(record) = facts.get("DistanceRecord") {
113            println!(
114                "DistanceRecord.TotalDistance = {:?}",
115                record.get_property("TotalDistance").unwrap_or(Value::Null)
116            );
117        }
118
119        // Check if we reached max speed
120        if let Some(car) = facts.get("TestCar") {
121            if let Some(speed) = car.get_property("speed") {
122                if let Some(max_speed) = car.get_property("maxSpeed") {
123                    if speed.to_number() >= max_speed.to_number() {
124                        println!("🏁 Max speed reached! Rule will no longer fire.");
125                        break;
126                    }
127                }
128            }
129        }
130
131        if result.rules_fired == 0 {
132            println!("ℹ️ No rules fired this cycle.");
133            break;
134        }
135    }
136
137    println!("\nπŸ“Š Final Summary:");
138    println!("βœ… Successfully demonstrated method calls in GRL:");
139    println!("   β€’ Method calls: $Object.method(args)");
140    println!("   β€’ Property access: $Object.Property");
141    println!("   β€’ Arithmetic expressions: $A.prop + $B.prop");
142    println!("   β€’ update() function calls");
143    println!("   β€’ Complex conditions with && operator");
144
145    Ok(())
146}
examples/grule_demo.rs (line 191)
68fn demo_engine_execution() -> std::result::Result<(), Box<dyn std::error::Error>> {
69    println!("πŸš€ Demo 3: Engine Execution");
70    println!("---------------------------");
71
72    // Create facts
73    let facts = Facts::new();
74    let mut user_props = HashMap::new();
75    user_props.insert("Age".to_string(), Value::Integer(25));
76    user_props.insert("Country".to_string(), Value::String("US".to_string()));
77    user_props.insert("SpendingTotal".to_string(), Value::Number(1500.0));
78    user_props.insert("IsAdult".to_string(), Value::Boolean(false));
79    user_props.insert("IsVIP".to_string(), Value::Boolean(false));
80    user_props.insert("Category".to_string(), Value::String("unknown".to_string()));
81    user_props.insert("DiscountRate".to_string(), Value::Number(0.0));
82
83    facts.add_value("User", Value::Object(user_props))?;
84
85    // Create knowledge base
86    let mut kb = KnowledgeBase::new("UserRules");
87
88    // Rule 1: Adult Check (salience 10)
89    let adult_rule = Rule::new(
90        "AdultCheck".to_string(),
91        ConditionGroup::and(
92            ConditionGroup::single(Condition::new(
93                "User.Age".to_string(),
94                Operator::GreaterThanOrEqual,
95                Value::Integer(18),
96            )),
97            ConditionGroup::single(Condition::new(
98                "User.Country".to_string(),
99                Operator::Equal,
100                Value::String("US".to_string()),
101            )),
102        ),
103        vec![
104            ActionType::MethodCall {
105                object: "User".to_string(),
106                method: "setIsAdult".to_string(),
107                args: vec![Value::Boolean(true)],
108            },
109            ActionType::MethodCall {
110                object: "User".to_string(),
111                method: "setCategory".to_string(),
112                args: vec![Value::String("Adult".to_string())],
113            },
114            ActionType::Call {
115                function: "log".to_string(),
116                args: vec![Value::String("User qualified as adult".to_string())],
117            },
118        ],
119    )
120    .with_salience(10);
121
122    // Rule 2: VIP Check (salience 20)
123    let vip_rule = Rule::new(
124        "VIPCheck".to_string(),
125        ConditionGroup::and(
126            ConditionGroup::and(
127                ConditionGroup::single(Condition::new(
128                    "User.Age".to_string(),
129                    Operator::GreaterThanOrEqual,
130                    Value::Integer(21),
131                )),
132                ConditionGroup::single(Condition::new(
133                    "User.IsAdult".to_string(),
134                    Operator::Equal,
135                    Value::Boolean(true),
136                )),
137            ),
138            ConditionGroup::single(Condition::new(
139                "User.SpendingTotal".to_string(),
140                Operator::GreaterThan,
141                Value::Number(1000.0),
142            )),
143        ),
144        vec![
145            ActionType::MethodCall {
146                object: "User".to_string(),
147                method: "setIsVIP".to_string(),
148                args: vec![Value::Boolean(true)],
149            },
150            ActionType::MethodCall {
151                object: "User".to_string(),
152                method: "setDiscountRate".to_string(),
153                args: vec![Value::Number(0.15)],
154            },
155            ActionType::Call {
156                function: "log".to_string(),
157                args: vec![Value::String("User upgraded to VIP".to_string())],
158            },
159        ],
160    )
161    .with_salience(20);
162
163    // Rule 3: Senior Discount (salience 15)
164    let senior_rule = Rule::new(
165        "SeniorDiscount".to_string(),
166        ConditionGroup::single(Condition::new(
167            "User.Age".to_string(),
168            Operator::GreaterThanOrEqual,
169            Value::Integer(65),
170        )),
171        vec![
172            ActionType::MethodCall {
173                object: "User".to_string(),
174                method: "setDiscountRate".to_string(),
175                args: vec![Value::Number(0.20)],
176            },
177            ActionType::MethodCall {
178                object: "User".to_string(),
179                method: "setCategory".to_string(),
180                args: vec![Value::String("Senior".to_string())],
181            },
182            ActionType::Call {
183                function: "log".to_string(),
184                args: vec![Value::String("Senior discount applied".to_string())],
185            },
186        ],
187    )
188    .with_salience(15);
189
190    // Add rules to knowledge base
191    let _ = kb.add_rule(adult_rule);
192    let _ = kb.add_rule(vip_rule);
193    let _ = kb.add_rule(senior_rule);
194
195    // Create engine
196    let config = EngineConfig {
197        debug_mode: true,
198        max_cycles: 3,
199        ..Default::default()
200    };
201    let engine = RustRuleEngine::with_config(kb, config);
202
203    println!("🏁 Initial state:");
204    if let Some(user) = facts.get("User") {
205        println!("   User = {user:?}");
206    }
207    println!();
208
209    // Execute rules
210    println!("πŸš€ Executing rules...");
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🏁 Final state:");
220    if let Some(user) = facts.get("User") {
221        println!("   User = {user:?}");
222    }
223    println!();
224
225    Ok(())
226}
227
228fn demo_ecommerce_scenario() -> std::result::Result<(), Box<dyn std::error::Error>> {
229    println!("πŸ›’ Demo 4: E-commerce Scenario");
230    println!("------------------------------");
231
232    // Create facts
233    let facts = Facts::new();
234
235    // Customer data
236    let mut customer_props = HashMap::new();
237    customer_props.insert(
238        "Email".to_string(),
239        Value::String("customer@example.com".to_string()),
240    );
241    customer_props.insert("Age".to_string(), Value::Integer(28));
242    customer_props.insert("IsNew".to_string(), Value::Boolean(true));
243    customer_props.insert("LoyaltyPoints".to_string(), Value::Integer(0));
244    customer_props.insert("TotalSpent".to_string(), Value::Number(0.0));
245
246    // Order data
247    let mut order_props = HashMap::new();
248    order_props.insert("Id".to_string(), Value::String("ORD-12345".to_string()));
249    order_props.insert("Amount".to_string(), Value::Number(150.0));
250    order_props.insert(
251        "Category".to_string(),
252        Value::String("electronics".to_string()),
253    );
254    order_props.insert("DiscountPercent".to_string(), Value::Number(0.0));
255    order_props.insert("FinalAmount".to_string(), Value::Number(150.0));
256
257    facts.add_value("Customer", Value::Object(customer_props))?;
258    facts.add_value("Order", Value::Object(order_props))?;
259
260    // Create knowledge base
261    let mut kb = KnowledgeBase::new("EcommerceRules");
262
263    // Rule 1: New Customer Discount
264    let new_customer_rule = Rule::new(
265        "NewCustomerDiscount".to_string(),
266        ConditionGroup::and(
267            ConditionGroup::single(Condition::new(
268                "Customer.IsNew".to_string(),
269                Operator::Equal,
270                Value::Boolean(true),
271            )),
272            ConditionGroup::single(Condition::new(
273                "Order.Amount".to_string(),
274                Operator::GreaterThan,
275                Value::Number(100.0),
276            )),
277        ),
278        vec![
279            ActionType::MethodCall {
280                object: "Order".to_string(),
281                method: "setDiscountPercent".to_string(),
282                args: vec![Value::Number(10.0)],
283            },
284            ActionType::MethodCall {
285                object: "Customer".to_string(),
286                method: "setLoyaltyPoints".to_string(),
287                args: vec![Value::Integer(100)],
288            },
289            ActionType::Call {
290                function: "log".to_string(),
291                args: vec![Value::String("New customer discount applied".to_string())],
292            },
293        ],
294    )
295    .with_salience(10);
296
297    // Rule 2: Calculate Final Amount
298    let calculate_final_rule = Rule::new(
299        "CalculateFinalAmount".to_string(),
300        ConditionGroup::single(Condition::new(
301            "Order.DiscountPercent".to_string(),
302            Operator::GreaterThan,
303            Value::Number(0.0),
304        )),
305        vec![ActionType::Call {
306            function: "log".to_string(),
307            args: vec![Value::String(
308                "Calculating final amount with discount".to_string(),
309            )],
310        }],
311    )
312    .with_salience(5);
313
314    // Add rules
315    let _ = kb.add_rule(new_customer_rule);
316    let _ = kb.add_rule(calculate_final_rule);
317
318    // Create engine
319    let config = EngineConfig {
320        debug_mode: true,
321        max_cycles: 3,
322        ..Default::default()
323    };
324    let engine = RustRuleEngine::with_config(kb, config);
325
326    println!("🏁 Initial e-commerce state:");
327    if let Some(customer) = facts.get("Customer") {
328        println!("   Customer = {customer:?}");
329    }
330    if let Some(order) = facts.get("Order") {
331        println!("   Order = {order:?}");
332    }
333    println!();
334
335    // Execute rules
336    println!("πŸš€ Executing e-commerce rules...");
337    let result = engine.execute(&facts)?;
338
339    println!("\nπŸ“Š E-commerce Results:");
340    println!("   Cycles: {}", result.cycle_count);
341    println!("   Rules evaluated: {}", result.rules_evaluated);
342    println!("   Rules fired: {}", result.rules_fired);
343    println!("   Execution time: {:?}", result.execution_time);
344
345    println!("\n🏁 Final e-commerce state:");
346    if let Some(customer) = facts.get("Customer") {
347        println!("   Customer = {customer:?}");
348    }
349    if let Some(order) = facts.get("Order") {
350        println!("   Order = {order:?}");
351    }
352
353    println!("\n🎯 Demo Completed Successfully!");
354    println!("   βœ… Knowledge Base management");
355    println!("   βœ… Facts manipulation");
356    println!("   βœ… Rule execution engine");
357    println!("   βœ… E-commerce scenario");
358    println!("   βœ… Method calls and function calls");
359    println!("   βœ… Salience-based rule ordering");
360
361    Ok(())
362}
Source

pub fn add_rules_from_grl(&self, grl_text: &str) -> Result<usize>

Add multiple rules from GRL text

Source

pub fn remove_rule(&self, rule_name: &str) -> Result<bool>

Remove a rule by name

Source

pub fn get_rule(&self, rule_name: &str) -> Option<Rule>

Get a rule by name

Source

pub fn get_rules(&self) -> Vec<Rule>

Get all rules

Source

pub fn get_rule_names(&self) -> Vec<String>

Get all rule names

Examples found in repository?
examples/ecommerce.rs (line 266)
8fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
9    println!("=== E-commerce Rules Demo ===");
10    println!("==============================\n");
11
12    // Create customer data
13    let mut customer_props = HashMap::new();
14    customer_props.insert("IsNew".to_string(), Value::Boolean(true));
15    customer_props.insert(
16        "Membership".to_string(),
17        Value::String("standard".to_string()),
18    );
19    customer_props.insert("TotalSpent".to_string(), Value::Number(750.0));
20    customer_props.insert("WelcomeEmailSent".to_string(), Value::Boolean(false));
21
22    // Create order data
23    let mut order_props = HashMap::new();
24    order_props.insert("Total".to_string(), Value::Number(75.0));
25    order_props.insert("ItemCount".to_string(), Value::Integer(2));
26    order_props.insert(
27        "Category".to_string(),
28        Value::String("clothing".to_string()),
29    );
30    order_props.insert("DiscountRate".to_string(), Value::Number(0.0));
31    order_props.insert("FreeShipping".to_string(), Value::Boolean(false));
32    order_props.insert(
33        "DiscountType".to_string(),
34        Value::String("none".to_string()),
35    );
36
37    // Create promotion data
38    let mut promotion_props = HashMap::new();
39    promotion_props.insert("SeasonalDiscount".to_string(), Value::Number(0.05));
40    promotion_props.insert("BulkDiscount".to_string(), Value::Number(0.10));
41    promotion_props.insert("Active".to_string(), Value::Boolean(true));
42
43    // Create facts
44    let facts = Facts::new();
45    facts.add_value("Customer", Value::Object(customer_props))?;
46    facts.add_value("Order", Value::Object(order_props))?;
47    facts.add_value("Promotion", Value::Object(promotion_props))?;
48
49    println!("🏁 Initial e-commerce data:");
50    if let Some(customer) = facts.get("Customer") {
51        println!("   Customer = {customer:?}");
52    }
53    if let Some(order) = facts.get("Order") {
54        println!("   Order = {order:?}");
55    }
56    if let Some(promotion) = facts.get("Promotion") {
57        println!("   Promotion = {promotion:?}");
58    }
59    println!();
60
61    // Create knowledge base
62    let mut kb = KnowledgeBase::new("EcommerceRules");
63
64    // Rule 1: New Customer Discount (salience 25)
65    let new_customer_rule = Rule::new(
66        "NewCustomerDiscount".to_string(),
67        ConditionGroup::and(
68            ConditionGroup::single(Condition::new(
69                "Customer.IsNew".to_string(),
70                Operator::Equal,
71                Value::Boolean(true),
72            )),
73            ConditionGroup::single(Condition::new(
74                "Order.Total".to_string(),
75                Operator::GreaterThan,
76                Value::Number(50.0),
77            )),
78        ),
79        vec![
80            ActionType::MethodCall {
81                object: "Order".to_string(),
82                method: "setDiscountRate".to_string(),
83                args: vec![Value::Number(0.10)],
84            },
85            ActionType::MethodCall {
86                object: "Order".to_string(),
87                method: "setDiscountType".to_string(),
88                args: vec![Value::String("welcome".to_string())],
89            },
90            ActionType::MethodCall {
91                object: "Customer".to_string(),
92                method: "setWelcomeEmailSent".to_string(),
93                args: vec![Value::Boolean(true)],
94            },
95            ActionType::Call {
96                function: "log".to_string(),
97                args: vec![Value::String(
98                    "New customer welcome discount applied".to_string(),
99                )],
100            },
101        ],
102    )
103    .with_salience(25);
104
105    // Rule 2: Premium Member Benefits (salience 20)
106    let premium_member_rule = Rule::new(
107        "PremiumMemberBenefits".to_string(),
108        ConditionGroup::and(
109            ConditionGroup::single(Condition::new(
110                "Customer.Membership".to_string(),
111                Operator::Equal,
112                Value::String("premium".to_string()),
113            )),
114            ConditionGroup::single(Condition::new(
115                "Order.Total".to_string(),
116                Operator::GreaterThan,
117                Value::Number(100.0),
118            )),
119        ),
120        vec![
121            ActionType::MethodCall {
122                object: "Order".to_string(),
123                method: "setDiscountRate".to_string(),
124                args: vec![Value::Number(0.15)],
125            },
126            ActionType::MethodCall {
127                object: "Order".to_string(),
128                method: "setFreeShipping".to_string(),
129                args: vec![Value::Boolean(true)],
130            },
131            ActionType::Call {
132                function: "log".to_string(),
133                args: vec![Value::String("Premium member benefits applied".to_string())],
134            },
135        ],
136    )
137    .with_salience(20);
138
139    // Rule 3: VIP Upgrade (salience 30)
140    let vip_upgrade_rule = Rule::new(
141        "VIPUpgrade".to_string(),
142        ConditionGroup::and(
143            ConditionGroup::single(Condition::new(
144                "Customer.TotalSpent".to_string(),
145                Operator::GreaterThan,
146                Value::Number(1000.0),
147            )),
148            ConditionGroup::single(Condition::new(
149                "Customer.Membership".to_string(),
150                Operator::NotEqual,
151                Value::String("VIP".to_string()),
152            )),
153        ),
154        vec![
155            ActionType::MethodCall {
156                object: "Customer".to_string(),
157                method: "setMembership".to_string(),
158                args: vec![Value::String("VIP".to_string())],
159            },
160            ActionType::MethodCall {
161                object: "Order".to_string(),
162                method: "setDiscountRate".to_string(),
163                args: vec![Value::Number(0.25)],
164            },
165            ActionType::Call {
166                function: "log".to_string(),
167                args: vec![Value::String(
168                    "Customer upgraded to VIP membership".to_string(),
169                )],
170            },
171        ],
172    )
173    .with_salience(30);
174
175    // Rule 4: Free Shipping for Large Orders (salience 15)
176    let free_shipping_rule = Rule::new(
177        "FreeShippingLargeOrders".to_string(),
178        ConditionGroup::single(Condition::new(
179            "Order.Total".to_string(),
180            Operator::GreaterThanOrEqual,
181            Value::Number(100.0),
182        )),
183        vec![
184            ActionType::MethodCall {
185                object: "Order".to_string(),
186                method: "setFreeShipping".to_string(),
187                args: vec![Value::Boolean(true)],
188            },
189            ActionType::Call {
190                function: "log".to_string(),
191                args: vec![Value::String(
192                    "Free shipping applied for large order".to_string(),
193                )],
194            },
195        ],
196    )
197    .with_salience(15);
198
199    // Rule 5: Bulk Discount (salience 12)
200    let bulk_discount_rule = Rule::new(
201        "BulkDiscount".to_string(),
202        ConditionGroup::single(Condition::new(
203            "Order.ItemCount".to_string(),
204            Operator::GreaterThanOrEqual,
205            Value::Integer(5),
206        )),
207        vec![
208            ActionType::Call {
209                function: "max".to_string(),
210                args: vec![
211                    Value::String("Order.DiscountRate".to_string()),
212                    Value::Number(0.10),
213                ],
214            },
215            ActionType::Call {
216                function: "log".to_string(),
217                args: vec![Value::String("Bulk discount applied".to_string())],
218            },
219        ],
220    )
221    .with_salience(12);
222
223    // Rule 6: Seasonal Promotion (salience 10)
224    let seasonal_promotion_rule = Rule::new(
225        "SeasonalPromotion".to_string(),
226        ConditionGroup::and(
227            ConditionGroup::single(Condition::new(
228                "Promotion.Active".to_string(),
229                Operator::Equal,
230                Value::Boolean(true),
231            )),
232            ConditionGroup::single(Condition::new(
233                "Order.Category".to_string(),
234                Operator::Equal,
235                Value::String("clothing".to_string()),
236            )),
237        ),
238        vec![
239            ActionType::Call {
240                function: "max".to_string(),
241                args: vec![
242                    Value::String("Order.DiscountRate".to_string()),
243                    Value::String("Promotion.SeasonalDiscount".to_string()),
244                ],
245            },
246            ActionType::Call {
247                function: "log".to_string(),
248                args: vec![Value::String("Seasonal promotion applied".to_string())],
249            },
250        ],
251    )
252    .with_salience(10);
253
254    // Add rules to knowledge base
255    let _ = kb.add_rule(new_customer_rule);
256    let _ = kb.add_rule(premium_member_rule);
257    let _ = kb.add_rule(vip_upgrade_rule);
258    let _ = kb.add_rule(free_shipping_rule);
259    let _ = kb.add_rule(bulk_discount_rule);
260    let _ = kb.add_rule(seasonal_promotion_rule);
261
262    println!(
263        "πŸ“š Knowledge Base loaded with {} rules",
264        kb.get_statistics().total_rules
265    );
266    println!("πŸ”₯ Rules: {:?}\n", kb.get_rule_names());
267
268    // Create engine with debug mode
269    let config = EngineConfig {
270        debug_mode: true,
271        max_cycles: 5,
272        ..Default::default()
273    };
274    let engine = RustRuleEngine::with_config(kb, config);
275
276    // Execute rules
277    println!("πŸš€ Executing e-commerce rules...");
278    let result = engine.execute(&facts)?;
279
280    println!("\nπŸ“Š E-commerce Execution Results:");
281    println!("   Cycles: {}", result.cycle_count);
282    println!("   Rules evaluated: {}", result.rules_evaluated);
283    println!("   Rules fired: {}", result.rules_fired);
284    println!("   Execution time: {:?}", result.execution_time);
285
286    println!("\n🏁 Final e-commerce state:");
287    if let Some(customer) = facts.get("Customer") {
288        println!("   Customer = {customer:?}");
289    }
290    if let Some(order) = facts.get("Order") {
291        println!("   Order = {order:?}");
292    }
293    if let Some(promotion) = facts.get("Promotion") {
294        println!("   Promotion = {promotion:?}");
295    }
296
297    println!("\n🎯 E-commerce Rules Demonstrated:");
298    println!("   🎁 New Customer Welcome Discount");
299    println!("   πŸ’Ž Premium Member Benefits");
300    println!("   🌟 VIP Membership Upgrades");
301    println!("   🚚 Free Shipping Rules");
302    println!("   πŸ“¦ Bulk Purchase Discounts");
303    println!("   🏷️ Seasonal Promotions");
304
305    Ok(())
306}
Source

pub fn rule_count(&self) -> usize

Get rule count

Source

pub fn set_rule_enabled(&self, rule_name: &str, enabled: bool) -> Result<bool>

Enable or disable a rule

Source

pub fn clear(&self)

Clear all rules

Source

pub fn get_rules_snapshot(&self) -> Vec<Rule>

Get a snapshot of all rules (for execution)

Source

pub fn get_statistics(&self) -> KnowledgeBaseStats

Get knowledge base statistics

Examples found in repository?
examples/grule_demo.rs (line 34)
27fn demo_knowledge_base() -> std::result::Result<(), Box<dyn std::error::Error>> {
28    println!("πŸ“š Demo 1: Knowledge Base with Code-based Rules");
29    println!("-----------------------------------------------");
30
31    // Create knowledge base
32    let kb = KnowledgeBase::new("UserRules");
33
34    println!("βœ… Knowledge Base created: {}", kb.get_statistics().name);
35    println!("   Total rules: {}", kb.get_statistics().total_rules);
36    println!("   Version: {}\n", kb.get_statistics().version);
37
38    Ok(())
39}
More examples
Hide additional examples
examples/ecommerce.rs (line 264)
8fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
9    println!("=== E-commerce Rules Demo ===");
10    println!("==============================\n");
11
12    // Create customer data
13    let mut customer_props = HashMap::new();
14    customer_props.insert("IsNew".to_string(), Value::Boolean(true));
15    customer_props.insert(
16        "Membership".to_string(),
17        Value::String("standard".to_string()),
18    );
19    customer_props.insert("TotalSpent".to_string(), Value::Number(750.0));
20    customer_props.insert("WelcomeEmailSent".to_string(), Value::Boolean(false));
21
22    // Create order data
23    let mut order_props = HashMap::new();
24    order_props.insert("Total".to_string(), Value::Number(75.0));
25    order_props.insert("ItemCount".to_string(), Value::Integer(2));
26    order_props.insert(
27        "Category".to_string(),
28        Value::String("clothing".to_string()),
29    );
30    order_props.insert("DiscountRate".to_string(), Value::Number(0.0));
31    order_props.insert("FreeShipping".to_string(), Value::Boolean(false));
32    order_props.insert(
33        "DiscountType".to_string(),
34        Value::String("none".to_string()),
35    );
36
37    // Create promotion data
38    let mut promotion_props = HashMap::new();
39    promotion_props.insert("SeasonalDiscount".to_string(), Value::Number(0.05));
40    promotion_props.insert("BulkDiscount".to_string(), Value::Number(0.10));
41    promotion_props.insert("Active".to_string(), Value::Boolean(true));
42
43    // Create facts
44    let facts = Facts::new();
45    facts.add_value("Customer", Value::Object(customer_props))?;
46    facts.add_value("Order", Value::Object(order_props))?;
47    facts.add_value("Promotion", Value::Object(promotion_props))?;
48
49    println!("🏁 Initial e-commerce data:");
50    if let Some(customer) = facts.get("Customer") {
51        println!("   Customer = {customer:?}");
52    }
53    if let Some(order) = facts.get("Order") {
54        println!("   Order = {order:?}");
55    }
56    if let Some(promotion) = facts.get("Promotion") {
57        println!("   Promotion = {promotion:?}");
58    }
59    println!();
60
61    // Create knowledge base
62    let mut kb = KnowledgeBase::new("EcommerceRules");
63
64    // Rule 1: New Customer Discount (salience 25)
65    let new_customer_rule = Rule::new(
66        "NewCustomerDiscount".to_string(),
67        ConditionGroup::and(
68            ConditionGroup::single(Condition::new(
69                "Customer.IsNew".to_string(),
70                Operator::Equal,
71                Value::Boolean(true),
72            )),
73            ConditionGroup::single(Condition::new(
74                "Order.Total".to_string(),
75                Operator::GreaterThan,
76                Value::Number(50.0),
77            )),
78        ),
79        vec![
80            ActionType::MethodCall {
81                object: "Order".to_string(),
82                method: "setDiscountRate".to_string(),
83                args: vec![Value::Number(0.10)],
84            },
85            ActionType::MethodCall {
86                object: "Order".to_string(),
87                method: "setDiscountType".to_string(),
88                args: vec![Value::String("welcome".to_string())],
89            },
90            ActionType::MethodCall {
91                object: "Customer".to_string(),
92                method: "setWelcomeEmailSent".to_string(),
93                args: vec![Value::Boolean(true)],
94            },
95            ActionType::Call {
96                function: "log".to_string(),
97                args: vec![Value::String(
98                    "New customer welcome discount applied".to_string(),
99                )],
100            },
101        ],
102    )
103    .with_salience(25);
104
105    // Rule 2: Premium Member Benefits (salience 20)
106    let premium_member_rule = Rule::new(
107        "PremiumMemberBenefits".to_string(),
108        ConditionGroup::and(
109            ConditionGroup::single(Condition::new(
110                "Customer.Membership".to_string(),
111                Operator::Equal,
112                Value::String("premium".to_string()),
113            )),
114            ConditionGroup::single(Condition::new(
115                "Order.Total".to_string(),
116                Operator::GreaterThan,
117                Value::Number(100.0),
118            )),
119        ),
120        vec![
121            ActionType::MethodCall {
122                object: "Order".to_string(),
123                method: "setDiscountRate".to_string(),
124                args: vec![Value::Number(0.15)],
125            },
126            ActionType::MethodCall {
127                object: "Order".to_string(),
128                method: "setFreeShipping".to_string(),
129                args: vec![Value::Boolean(true)],
130            },
131            ActionType::Call {
132                function: "log".to_string(),
133                args: vec![Value::String("Premium member benefits applied".to_string())],
134            },
135        ],
136    )
137    .with_salience(20);
138
139    // Rule 3: VIP Upgrade (salience 30)
140    let vip_upgrade_rule = Rule::new(
141        "VIPUpgrade".to_string(),
142        ConditionGroup::and(
143            ConditionGroup::single(Condition::new(
144                "Customer.TotalSpent".to_string(),
145                Operator::GreaterThan,
146                Value::Number(1000.0),
147            )),
148            ConditionGroup::single(Condition::new(
149                "Customer.Membership".to_string(),
150                Operator::NotEqual,
151                Value::String("VIP".to_string()),
152            )),
153        ),
154        vec![
155            ActionType::MethodCall {
156                object: "Customer".to_string(),
157                method: "setMembership".to_string(),
158                args: vec![Value::String("VIP".to_string())],
159            },
160            ActionType::MethodCall {
161                object: "Order".to_string(),
162                method: "setDiscountRate".to_string(),
163                args: vec![Value::Number(0.25)],
164            },
165            ActionType::Call {
166                function: "log".to_string(),
167                args: vec![Value::String(
168                    "Customer upgraded to VIP membership".to_string(),
169                )],
170            },
171        ],
172    )
173    .with_salience(30);
174
175    // Rule 4: Free Shipping for Large Orders (salience 15)
176    let free_shipping_rule = Rule::new(
177        "FreeShippingLargeOrders".to_string(),
178        ConditionGroup::single(Condition::new(
179            "Order.Total".to_string(),
180            Operator::GreaterThanOrEqual,
181            Value::Number(100.0),
182        )),
183        vec![
184            ActionType::MethodCall {
185                object: "Order".to_string(),
186                method: "setFreeShipping".to_string(),
187                args: vec![Value::Boolean(true)],
188            },
189            ActionType::Call {
190                function: "log".to_string(),
191                args: vec![Value::String(
192                    "Free shipping applied for large order".to_string(),
193                )],
194            },
195        ],
196    )
197    .with_salience(15);
198
199    // Rule 5: Bulk Discount (salience 12)
200    let bulk_discount_rule = Rule::new(
201        "BulkDiscount".to_string(),
202        ConditionGroup::single(Condition::new(
203            "Order.ItemCount".to_string(),
204            Operator::GreaterThanOrEqual,
205            Value::Integer(5),
206        )),
207        vec![
208            ActionType::Call {
209                function: "max".to_string(),
210                args: vec![
211                    Value::String("Order.DiscountRate".to_string()),
212                    Value::Number(0.10),
213                ],
214            },
215            ActionType::Call {
216                function: "log".to_string(),
217                args: vec![Value::String("Bulk discount applied".to_string())],
218            },
219        ],
220    )
221    .with_salience(12);
222
223    // Rule 6: Seasonal Promotion (salience 10)
224    let seasonal_promotion_rule = Rule::new(
225        "SeasonalPromotion".to_string(),
226        ConditionGroup::and(
227            ConditionGroup::single(Condition::new(
228                "Promotion.Active".to_string(),
229                Operator::Equal,
230                Value::Boolean(true),
231            )),
232            ConditionGroup::single(Condition::new(
233                "Order.Category".to_string(),
234                Operator::Equal,
235                Value::String("clothing".to_string()),
236            )),
237        ),
238        vec![
239            ActionType::Call {
240                function: "max".to_string(),
241                args: vec![
242                    Value::String("Order.DiscountRate".to_string()),
243                    Value::String("Promotion.SeasonalDiscount".to_string()),
244                ],
245            },
246            ActionType::Call {
247                function: "log".to_string(),
248                args: vec![Value::String("Seasonal promotion applied".to_string())],
249            },
250        ],
251    )
252    .with_salience(10);
253
254    // Add rules to knowledge base
255    let _ = kb.add_rule(new_customer_rule);
256    let _ = kb.add_rule(premium_member_rule);
257    let _ = kb.add_rule(vip_upgrade_rule);
258    let _ = kb.add_rule(free_shipping_rule);
259    let _ = kb.add_rule(bulk_discount_rule);
260    let _ = kb.add_rule(seasonal_promotion_rule);
261
262    println!(
263        "πŸ“š Knowledge Base loaded with {} rules",
264        kb.get_statistics().total_rules
265    );
266    println!("πŸ”₯ Rules: {:?}\n", kb.get_rule_names());
267
268    // Create engine with debug mode
269    let config = EngineConfig {
270        debug_mode: true,
271        max_cycles: 5,
272        ..Default::default()
273    };
274    let engine = RustRuleEngine::with_config(kb, config);
275
276    // Execute rules
277    println!("πŸš€ Executing e-commerce rules...");
278    let result = engine.execute(&facts)?;
279
280    println!("\nπŸ“Š E-commerce Execution Results:");
281    println!("   Cycles: {}", result.cycle_count);
282    println!("   Rules evaluated: {}", result.rules_evaluated);
283    println!("   Rules fired: {}", result.rules_fired);
284    println!("   Execution time: {:?}", result.execution_time);
285
286    println!("\n🏁 Final e-commerce state:");
287    if let Some(customer) = facts.get("Customer") {
288        println!("   Customer = {customer:?}");
289    }
290    if let Some(order) = facts.get("Order") {
291        println!("   Order = {order:?}");
292    }
293    if let Some(promotion) = facts.get("Promotion") {
294        println!("   Promotion = {promotion:?}");
295    }
296
297    println!("\n🎯 E-commerce Rules Demonstrated:");
298    println!("   🎁 New Customer Welcome Discount");
299    println!("   πŸ’Ž Premium Member Benefits");
300    println!("   🌟 VIP Membership Upgrades");
301    println!("   🚚 Free Shipping Rules");
302    println!("   πŸ“¦ Bulk Purchase Discounts");
303    println!("   🏷️ Seasonal Promotions");
304
305    Ok(())
306}
Source

pub fn export_to_grl(&self) -> String

Export rules to GRL format

Trait ImplementationsΒ§

SourceΒ§

impl Clone for KnowledgeBase

SourceΒ§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 Β· SourceΒ§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
SourceΒ§

impl Debug for KnowledgeBase

SourceΒ§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait ImplementationsΒ§

Blanket ImplementationsΒ§

SourceΒ§

impl<T> Any for T
where T: 'static + ?Sized,

SourceΒ§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
SourceΒ§

impl<T> Borrow<T> for T
where T: ?Sized,

SourceΒ§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
SourceΒ§

impl<T> BorrowMut<T> for T
where T: ?Sized,

SourceΒ§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
SourceΒ§

impl<T> CloneToUninit for T
where T: Clone,

SourceΒ§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

πŸ”¬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
SourceΒ§

impl<T> From<T> for T

SourceΒ§

fn from(t: T) -> T

Returns the argument unchanged.

SourceΒ§

impl<T, U> Into<U> for T
where U: From<T>,

SourceΒ§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

SourceΒ§

impl<T> ToOwned for T
where T: Clone,

SourceΒ§

type Owned = T

The resulting type after obtaining ownership.
SourceΒ§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
SourceΒ§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
SourceΒ§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

SourceΒ§

type Error = Infallible

The type returned in the event of a conversion error.
SourceΒ§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
SourceΒ§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

SourceΒ§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
SourceΒ§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.