Facts

Struct Facts 

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

Facts - represents the working memory of data objects Similar to Grule’s DataContext concept

ImplementationsΒ§

SourceΒ§

impl Facts

Source

pub fn create_object(pairs: Vec<(String, Value)>) -> Value

Create a generic object from key-value pairs

Source

pub fn new() -> Self

Create a user object

Examples found in repository?
examples/builder_test.rs (line 20)
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5    println!("πŸ”§ Testing RuleEngineBuilder with inline rules");
6
7    let grl_rules = r#"
8        rule "SimpleTest" salience 10 {
9            when
10                User.Age >= 18
11            then
12                log("User is adult");
13        }
14    "#;
15
16    // Test inline rules
17    let engine = RuleEngineBuilder::new().with_inline_grl(grl_rules)?.build();
18
19    // Create facts
20    let facts = Facts::new();
21    let mut user = HashMap::new();
22    user.insert("Age".to_string(), Value::Integer(25));
23    facts.add_value("User", Value::Object(user))?;
24
25    // Execute
26    let result = engine.execute(&facts)?;
27    println!("βœ… Rules fired: {}", result.rules_fired);
28
29    Ok(())
30}
More examples
Hide additional examples
examples/grule_demo.rs (line 46)
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}
examples/debug_conditions.rs (line 37)
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 36)
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 23)
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 26)
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}
Source

pub fn add<T>(&self, name: &str, fact: T) -> Result<()>
where T: Serialize + Debug,

Add a fact object to the working memory

Source

pub fn add_value(&self, name: &str, value: Value) -> Result<()>

Add a simple value fact

Examples found in repository?
examples/builder_test.rs (line 23)
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5    println!("πŸ”§ Testing RuleEngineBuilder with inline rules");
6
7    let grl_rules = r#"
8        rule "SimpleTest" salience 10 {
9            when
10                User.Age >= 18
11            then
12                log("User is adult");
13        }
14    "#;
15
16    // Test inline rules
17    let engine = RuleEngineBuilder::new().with_inline_grl(grl_rules)?.build();
18
19    // Create facts
20    let facts = Facts::new();
21    let mut user = HashMap::new();
22    user.insert("Age".to_string(), Value::Integer(25));
23    facts.add_value("User", Value::Object(user))?;
24
25    // Execute
26    let result = engine.execute(&facts)?;
27    println!("βœ… Rules fired: {}", result.rules_fired);
28
29    Ok(())
30}
More examples
Hide additional examples
examples/grule_demo.rs (line 57)
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}
examples/debug_conditions.rs (line 47)
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 50)
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 24)
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 35)
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}
Source

pub fn get(&self, name: &str) -> Option<Value>

Get a fact by name

Examples found in repository?
examples/grule_demo.rs (line 60)
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 50)
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 54)
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 28)
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 38)
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 65)
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 get_nested(&self, path: &str) -> Option<Value>

Get a nested fact property (e.g., β€œUser.Profile.Age”)

Source

pub fn set(&self, name: &str, value: Value)

Set a fact value

Source

pub fn set_nested(&self, path: &str, value: Value) -> Result<()>

Set a nested fact property

Examples found in repository?
examples/inline_rules_demo.rs (line 127)
8fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
9    println!("🎯 Inline GRL Rules Demo");
10    println!("========================\n");
11
12    // Define rules directly in code as strings
13    let grl_rules = r#"
14        rule "HighValueCustomer" salience 20 {
15            when
16                Customer.TotalSpent > 1000.0
17            then
18                sendWelcomeEmail(Customer.Email, "GOLD");
19                Customer.setTier("GOLD");
20                log("Customer upgraded to GOLD tier");
21        }
22
23        rule "LoyaltyBonus" salience 15 {
24            when
25                Customer.OrderCount >= 10
26            then
27                applyLoyaltyBonus(Customer.Id, 50.0);
28                Customer.setLoyaltyBonusApplied(true);
29                log("Loyalty bonus applied");
30        }
31
32        rule "NewCustomerWelcome" salience 10 {
33            when
34                Customer.IsNew == false && Customer.WelcomeEmailSent == false
35            then
36                sendWelcomeEmail(Customer.Email, "EXISTING");
37                Customer.setWelcomeEmailSent(true);
38                log("Welcome email sent to existing customer");
39        }
40
41        rule "LowRiskTransaction" salience 5 {
42            when
43                Transaction.Amount < 1000.0 && Transaction.RiskProcessed == false
44            then
45                Transaction.setRiskProcessed(true);
46                log("Low-risk transaction processed");
47        }
48    "#;
49
50    println!("πŸ“‹ Inline GRL Rules:");
51    println!("---");
52    println!("{}", grl_rules.trim());
53    println!("---\n");
54
55    // Create facts
56    let facts = Facts::new();
57
58    // Customer data
59    let mut customer_props = HashMap::new();
60    customer_props.insert("Id".to_string(), Value::String("CUST001".to_string()));
61    customer_props.insert(
62        "Email".to_string(),
63        Value::String("john.doe@example.com".to_string()),
64    );
65    customer_props.insert("TotalSpent".to_string(), Value::Number(1250.0)); // Qualifies for GOLD
66    customer_props.insert("YearsActive".to_string(), Value::Integer(4)); // Long-time customer
67    customer_props.insert("OrderCount".to_string(), Value::Integer(12)); // Qualifies for loyalty
68    customer_props.insert("Tier".to_string(), Value::String("SILVER".to_string()));
69    customer_props.insert("IsNew".to_string(), Value::Boolean(false));
70    customer_props.insert("RiskScore".to_string(), Value::Integer(35)); // Low risk
71    customer_props.insert("WelcomeEmailSent".to_string(), Value::Boolean(false));
72    customer_props.insert("LoyaltyBonusApplied".to_string(), Value::Boolean(false));
73
74    // Transaction data
75    let mut transaction_props = HashMap::new();
76    transaction_props.insert("Id".to_string(), Value::String("TXN001".to_string()));
77    transaction_props.insert("Amount".to_string(), Value::Number(750.0)); // Normal amount
78    transaction_props.insert("Currency".to_string(), Value::String("USD".to_string()));
79    transaction_props.insert("RiskProcessed".to_string(), Value::Boolean(false));
80
81    facts.add_value("Customer", Value::Object(customer_props))?;
82    facts.add_value("Transaction", Value::Object(transaction_props))?;
83
84    println!("🏁 Initial state:");
85    if let Some(customer) = facts.get("Customer") {
86        println!("   Customer = {customer:?}");
87    }
88    if let Some(transaction) = facts.get("Transaction") {
89        println!("   Transaction = {transaction:?}");
90    }
91    println!();
92
93    // Create knowledge base and parse inline rules
94    let kb = KnowledgeBase::new("InlineRulesDemo");
95
96    println!("πŸ”§ Parsing inline GRL rules...");
97    let parsed_rules = GRLParser::parse_rules(grl_rules)
98        .map_err(|e| format!("Failed to parse inline GRL rules: {:?}", e))?;
99
100    println!(
101        "βœ… Successfully parsed {} rules from inline strings",
102        parsed_rules.len()
103    );
104    for rule in parsed_rules {
105        println!("   πŸ“‹ Rule: {} (salience: {})", rule.name, rule.salience);
106        let _ = kb.add_rule(rule);
107    }
108    println!();
109
110    // Create engine with configuration
111    let config = EngineConfig {
112        debug_mode: true,
113        max_cycles: 1, // PREVENT INFINITE LOOPS by limiting to 1 cycle
114        ..Default::default()
115    };
116    let mut engine = RustRuleEngine::with_config(kb, config);
117
118    // Register custom functions called from the inline rules
119    println!("πŸ“ Registering custom functions for inline rules...");
120
121    // Customer tier management
122    engine.register_function("Customer.setTier", |args, facts| {
123        let new_tier = args.get(0).unwrap().to_string();
124
125        // ACTUALLY UPDATE THE FACTS in memory
126        facts
127            .set_nested("Customer.Tier", Value::String(new_tier.clone()))
128            .unwrap();
129
130        let result = format!("πŸ† Customer tier updated to: {}", new_tier);
131        println!("  {}", result);
132        Ok(Value::String(result))
133    });
134
135    // Loyalty bonus management
136    engine.register_function("Customer.setLoyaltyBonusApplied", |args, facts| {
137        let applied = args.get(0).unwrap();
138
139        // ACTUALLY UPDATE THE FACTS in memory
140        facts
141            .set_nested("Customer.LoyaltyBonusApplied", applied.clone())
142            .unwrap();
143
144        let result = format!("🎯 Loyalty bonus status updated: {:?}", applied);
145        println!("  {}", result);
146        Ok(Value::String(result))
147    });
148
149    // Email service
150    engine.register_function("sendWelcomeEmail", |args, _facts| {
151        let email = args.get(0).unwrap().to_string();
152        let tier = args.get(1).unwrap().to_string();
153
154        let result = format!("πŸ“§ Welcome email sent to {} for {} tier", email, tier);
155        println!("  {}", result);
156        Ok(Value::String(result))
157    });
158
159    // Loyalty system
160    engine.register_function("applyLoyaltyBonus", |args, _facts| {
161        let customer_id = args.get(0).unwrap().to_string();
162        let bonus_amount = args.get(1).unwrap();
163
164        let result = format!(
165            "πŸ’° Loyalty bonus of {:?} applied to customer {}",
166            bonus_amount, customer_id
167        );
168        println!("  {}", result);
169        Ok(Value::String(result))
170    });
171
172    // Security functions
173    engine.register_function("flagForReview", |args, _facts| {
174        let transaction_id = args.get(0).unwrap().to_string();
175
176        let result = format!(
177            "🚨 Transaction {} flagged for manual review",
178            transaction_id
179        );
180        println!("  {}", result);
181        Ok(Value::String(result))
182    });
183
184    engine.register_function("notifySecurityTeam", |args, _facts| {
185        let customer_id = args.get(0).unwrap().to_string();
186        let amount = args.get(1).unwrap();
187
188        let result = format!(
189            "πŸ”’ Security team notified: Customer {} - Amount {:?}",
190            customer_id, amount
191        );
192        println!("  {}", result);
193        Ok(Value::String(result))
194    });
195
196    // Customer status updates
197    engine.register_function("Customer.setWelcomeEmailSent", |args, facts| {
198        let sent = args.get(0).unwrap();
199
200        // ACTUALLY UPDATE THE FACTS in memory
201        facts
202            .set_nested("Customer.WelcomeEmailSent", sent.clone())
203            .unwrap();
204
205        let result = format!("βœ… Welcome email status updated: {:?}", sent);
206        println!("  {}", result);
207        Ok(Value::String(result))
208    });
209
210    // Transaction status updates
211    engine.register_function("Transaction.setRiskProcessed", |args, facts| {
212        let processed = args.get(0).unwrap();
213
214        // ACTUALLY UPDATE THE FACTS in memory
215        facts
216            .set_nested("Transaction.RiskProcessed", processed.clone())
217            .unwrap();
218
219        let result = format!("βœ… Transaction risk processing completed: {:?}", processed);
220        println!("  {}", result);
221        Ok(Value::String(result))
222    });
223
224    println!("βœ… Registered 8 custom functions for inline rules:");
225    println!("   πŸ† Customer.setTier");
226    println!("   🎯 Customer.setLoyaltyBonusApplied");
227    println!("   πŸ“§ sendWelcomeEmail");
228    println!("   πŸ’° applyLoyaltyBonus");
229    println!("   🚨 flagForReview");
230    println!("   πŸ”’ notifySecurityTeam");
231    println!("   βœ… Customer.setWelcomeEmailSent");
232    println!("   βœ… Transaction.setRiskProcessed");
233    println!();
234
235    // Execute the inline rules
236    println!("πŸš€ Executing inline GRL rules...");
237    let result = engine.execute(&facts)?;
238
239    println!("\nπŸ“Š Inline Rules Execution Results:");
240    println!("   Cycles: {}", result.cycle_count);
241    println!("   Rules evaluated: {}", result.rules_evaluated);
242    println!("   Rules fired: {}", result.rules_fired);
243    println!("   Execution time: {:?}", result.execution_time);
244
245    println!("\n🏁 Final state:");
246    if let Some(customer) = facts.get("Customer") {
247        println!("   Customer = {customer:?}");
248    }
249    if let Some(transaction) = facts.get("Transaction") {
250        println!("   Transaction = {transaction:?}");
251    }
252
253    println!("\n🎯 Inline GRL Rules Demonstrated:");
254    println!("   πŸ“ Rules defined as strings directly in code");
255    println!("   πŸ”§ No external files needed");
256    println!("   ⚑ Quick prototyping and testing");
257    println!("   πŸ† Customer tier management");
258    println!("   πŸ’° Loyalty bonus system");
259    println!("   πŸ”’ Security and fraud detection");
260    println!("   πŸ“§ Email notification system");
261
262    Ok(())
263}
Source

pub fn remove(&self, name: &str) -> Option<Value>

Remove a fact

Source

pub fn clear(&self)

Clear all facts

Source

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

Get all fact names

Source

pub fn count(&self) -> usize

Get fact count

Source

pub fn contains(&self, name: &str) -> bool

Check if a fact exists

Source

pub fn get_fact_type(&self, name: &str) -> Option<String>

Get the type name of a fact

Source

pub fn to_context(&self) -> Context

Convert to Context for rule evaluation

Source

pub fn from_context(context: Context) -> Self

Create Facts from Context

Source

pub fn merge(&self, other: &Facts)

Merge another Facts instance into this one

Source

pub fn snapshot(&self) -> FactsSnapshot

Get a snapshot of all facts

Source

pub fn restore(&self, snapshot: FactsSnapshot)

Restore from a snapshot

Trait ImplementationsΒ§

SourceΒ§

impl Clone for Facts

SourceΒ§

fn clone(&self) -> Facts

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 Facts

SourceΒ§

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

Formats the value using the given formatter. Read more
SourceΒ§

impl Default for Facts

SourceΒ§

fn default() -> Self

Returns the β€œdefault value” for a type. 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.