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
impl Facts
Sourcepub fn create_object(pairs: Vec<(String, Value)>) -> Value
pub fn create_object(pairs: Vec<(String, Value)>) -> Value
Create a generic object from key-value pairs
Sourcepub fn new() -> Self
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
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}Sourcepub fn add<T>(&self, name: &str, fact: T) -> Result<()>
pub fn add<T>(&self, name: &str, fact: T) -> Result<()>
Add a fact object to the working memory
Sourcepub fn add_value(&self, name: &str, value: Value) -> Result<()>
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
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}Sourcepub fn get(&self, name: &str) -> Option<Value>
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
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}Sourcepub fn get_nested(&self, path: &str) -> Option<Value>
pub fn get_nested(&self, path: &str) -> Option<Value>
Get a nested fact property (e.g., βUser.Profile.Ageβ)
Sourcepub fn set_nested(&self, path: &str, value: Value) -> Result<()>
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}Sourcepub fn get_fact_names(&self) -> Vec<String>
pub fn get_fact_names(&self) -> Vec<String>
Get all fact names
Sourcepub fn get_fact_type(&self, name: &str) -> Option<String>
pub fn get_fact_type(&self, name: &str) -> Option<String>
Get the type name of a fact
Sourcepub fn to_context(&self) -> Context
pub fn to_context(&self) -> Context
Convert to Context for rule evaluation
Sourcepub fn from_context(context: Context) -> Self
pub fn from_context(context: Context) -> Self
Create Facts from Context
Sourcepub fn snapshot(&self) -> FactsSnapshot
pub fn snapshot(&self) -> FactsSnapshot
Get a snapshot of all facts
Sourcepub fn restore(&self, snapshot: FactsSnapshot)
pub fn restore(&self, snapshot: FactsSnapshot)
Restore from a snapshot
Trait ImplementationsΒ§
Auto Trait ImplementationsΒ§
impl Freeze for Facts
impl RefUnwindSafe for Facts
impl Send for Facts
impl Sync for Facts
impl Unpin for Facts
impl UnwindSafe for Facts
Blanket ImplementationsΒ§
SourceΒ§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
SourceΒ§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more