rust_rule_engine/rete/
deffacts.rs

1//! Initial Facts System (inspired by CLIPS deffacts)
2//!
3//! Provides pre-defined fact sets that are automatically loaded into working memory.
4//! Similar to CLIPS deffacts and Drools declared facts.
5
6use crate::errors::{Result, RuleEngineError};
7use crate::rete::facts::TypedFacts;
8use std::collections::HashMap;
9
10/// A single fact instance with its type
11#[derive(Debug, Clone)]
12pub struct FactInstance {
13    /// The fact type (e.g., "Person", "Order", "Config")
14    pub fact_type: String,
15    /// The fact data
16    pub data: TypedFacts,
17}
18
19impl FactInstance {
20    /// Create a new fact instance
21    pub fn new(fact_type: impl Into<String>, data: TypedFacts) -> Self {
22        Self {
23            fact_type: fact_type.into(),
24            data,
25        }
26    }
27}
28
29/// A named set of initial facts (deffacts)
30#[derive(Debug, Clone)]
31pub struct Deffacts {
32    /// Name of this deffacts set
33    pub name: String,
34    /// Collection of initial facts
35    pub facts: Vec<FactInstance>,
36    /// Optional description
37    pub description: Option<String>,
38}
39
40impl Deffacts {
41    /// Create a new deffacts set
42    pub fn new(name: impl Into<String>) -> Self {
43        Self {
44            name: name.into(),
45            facts: Vec::new(),
46            description: None,
47        }
48    }
49
50    /// Add a fact to this deffacts set
51    pub fn add_fact(&mut self, fact_type: impl Into<String>, data: TypedFacts) {
52        self.facts.push(FactInstance::new(fact_type, data));
53    }
54
55    /// Set the description
56    pub fn set_description(&mut self, description: impl Into<String>) {
57        self.description = Some(description.into());
58    }
59
60    /// Get the number of facts
61    pub fn fact_count(&self) -> usize {
62        self.facts.len()
63    }
64
65    /// Check if this deffacts is empty
66    pub fn is_empty(&self) -> bool {
67        self.facts.is_empty()
68    }
69}
70
71/// Registry for managing deffacts
72/// Stores named sets of initial facts that can be loaded into working memory
73#[derive(Debug, Clone)]
74pub struct DeffactsRegistry {
75    deffacts: HashMap<String, Deffacts>,
76}
77
78impl DeffactsRegistry {
79    /// Create a new deffacts registry
80    pub fn new() -> Self {
81        Self {
82            deffacts: HashMap::new(),
83        }
84    }
85
86    /// Register a deffacts set
87    pub fn register(&mut self, deffacts: Deffacts) -> Result<()> {
88        let name = deffacts.name.clone();
89
90        if self.deffacts.contains_key(&name) {
91            return Err(RuleEngineError::EvaluationError {
92                message: format!("Deffacts '{}' already exists", name),
93            });
94        }
95
96        self.deffacts.insert(name, deffacts);
97        Ok(())
98    }
99
100    /// Register a deffacts set, replacing if it exists
101    pub fn register_or_replace(&mut self, deffacts: Deffacts) {
102        let name = deffacts.name.clone();
103        self.deffacts.insert(name, deffacts);
104    }
105
106    /// Get a deffacts set by name
107    pub fn get(&self, name: &str) -> Option<&Deffacts> {
108        self.deffacts.get(name)
109    }
110
111    /// Get a mutable reference to a deffacts set
112    pub fn get_mut(&mut self, name: &str) -> Option<&mut Deffacts> {
113        self.deffacts.get_mut(name)
114    }
115
116    /// Check if a deffacts set exists
117    pub fn exists(&self, name: &str) -> bool {
118        self.deffacts.contains_key(name)
119    }
120
121    /// Remove a deffacts set
122    pub fn remove(&mut self, name: &str) -> Result<Deffacts> {
123        self.deffacts
124            .remove(name)
125            .ok_or_else(|| RuleEngineError::EvaluationError {
126                message: format!("Deffacts '{}' not found", name),
127            })
128    }
129
130    /// List all deffacts names
131    pub fn list_deffacts(&self) -> Vec<String> {
132        self.deffacts.keys().cloned().collect()
133    }
134
135    /// Get all facts from all deffacts sets
136    pub fn get_all_facts(&self) -> Vec<(String, FactInstance)> {
137        let mut all_facts = Vec::new();
138
139        for (deffacts_name, deffacts) in &self.deffacts {
140            for fact in &deffacts.facts {
141                all_facts.push((deffacts_name.clone(), fact.clone()));
142            }
143        }
144
145        all_facts
146    }
147
148    /// Get total count of all facts across all deffacts
149    pub fn total_fact_count(&self) -> usize {
150        self.deffacts.values().map(|d| d.fact_count()).sum()
151    }
152
153    /// Clear all deffacts
154    pub fn clear(&mut self) {
155        self.deffacts.clear();
156    }
157
158    /// Get the number of deffacts sets
159    pub fn len(&self) -> usize {
160        self.deffacts.len()
161    }
162
163    /// Check if the registry is empty
164    pub fn is_empty(&self) -> bool {
165        self.deffacts.is_empty()
166    }
167}
168
169impl Default for DeffactsRegistry {
170    fn default() -> Self {
171        Self::new()
172    }
173}
174
175/// Builder for creating deffacts with a fluent API
176pub struct DeffactsBuilder {
177    name: String,
178    facts: Vec<FactInstance>,
179    description: Option<String>,
180}
181
182impl DeffactsBuilder {
183    /// Create a new deffacts builder
184    pub fn new(name: impl Into<String>) -> Self {
185        Self {
186            name: name.into(),
187            facts: Vec::new(),
188            description: None,
189        }
190    }
191
192    /// Add a fact to this deffacts
193    pub fn add_fact(mut self, fact_type: impl Into<String>, data: TypedFacts) -> Self {
194        self.facts.push(FactInstance::new(fact_type, data));
195        self
196    }
197
198    /// Add multiple facts of the same type
199    pub fn add_facts(mut self, fact_type: impl Into<String>, facts: Vec<TypedFacts>) -> Self {
200        let fact_type_str = fact_type.into();
201        for data in facts {
202            self.facts
203                .push(FactInstance::new(fact_type_str.clone(), data));
204        }
205        self
206    }
207
208    /// Set the description
209    pub fn with_description(mut self, description: impl Into<String>) -> Self {
210        self.description = Some(description.into());
211        self
212    }
213
214    /// Build the deffacts
215    pub fn build(self) -> Deffacts {
216        Deffacts {
217            name: self.name,
218            facts: self.facts,
219            description: self.description,
220        }
221    }
222}
223
224#[cfg(test)]
225mod tests {
226    use super::*;
227    use crate::rete::facts::FactValue;
228
229    #[test]
230    fn test_create_fact_instance() {
231        let mut data = TypedFacts::new();
232        data.set("name", FactValue::String("John".to_string()));
233        data.set("age", FactValue::Integer(30));
234
235        let fact = FactInstance::new("Person", data);
236        assert_eq!(fact.fact_type, "Person");
237        assert_eq!(
238            fact.data.get("name"),
239            Some(&FactValue::String("John".to_string()))
240        );
241    }
242
243    #[test]
244    fn test_deffacts_basic() {
245        let mut deffacts = Deffacts::new("initial-data");
246
247        let mut person_data = TypedFacts::new();
248        person_data.set("name", FactValue::String("Alice".to_string()));
249
250        deffacts.add_fact("Person", person_data);
251        deffacts.set_description("Initial person data");
252
253        assert_eq!(deffacts.name, "initial-data");
254        assert_eq!(deffacts.fact_count(), 1);
255        assert!(!deffacts.is_empty());
256        assert_eq!(
257            deffacts.description,
258            Some("Initial person data".to_string())
259        );
260    }
261
262    #[test]
263    fn test_registry_register() {
264        let mut registry = DeffactsRegistry::new();
265
266        let mut deffacts = Deffacts::new("test");
267        let mut data = TypedFacts::new();
268        data.set("value", FactValue::Integer(42));
269        deffacts.add_fact("Config", data);
270
271        registry.register(deffacts).unwrap();
272
273        assert!(registry.exists("test"));
274        assert_eq!(registry.len(), 1);
275    }
276
277    #[test]
278    fn test_registry_duplicate_error() {
279        let mut registry = DeffactsRegistry::new();
280
281        let deffacts1 = Deffacts::new("test");
282        let deffacts2 = Deffacts::new("test");
283
284        registry.register(deffacts1).unwrap();
285        let result = registry.register(deffacts2);
286
287        assert!(result.is_err());
288    }
289
290    #[test]
291    fn test_registry_register_or_replace() {
292        let mut registry = DeffactsRegistry::new();
293
294        let mut deffacts1 = Deffacts::new("test");
295        let mut data1 = TypedFacts::new();
296        data1.set("version", FactValue::Integer(1));
297        deffacts1.add_fact("Config", data1);
298
299        let mut deffacts2 = Deffacts::new("test");
300        let mut data2 = TypedFacts::new();
301        data2.set("version", FactValue::Integer(2));
302        deffacts2.add_fact("Config", data2);
303
304        registry.register_or_replace(deffacts1);
305        registry.register_or_replace(deffacts2);
306
307        assert_eq!(registry.len(), 1);
308        let deffacts = registry.get("test").unwrap();
309        assert_eq!(deffacts.fact_count(), 1);
310    }
311
312    #[test]
313    fn test_registry_get_all_facts() {
314        let mut registry = DeffactsRegistry::new();
315
316        // First deffacts with 2 facts
317        let mut deffacts1 = Deffacts::new("set1");
318        let mut data1 = TypedFacts::new();
319        data1.set("name", FactValue::String("Alice".to_string()));
320        deffacts1.add_fact("Person", data1);
321
322        let mut data2 = TypedFacts::new();
323        data2.set("name", FactValue::String("Bob".to_string()));
324        deffacts1.add_fact("Person", data2);
325
326        // Second deffacts with 1 fact
327        let mut deffacts2 = Deffacts::new("set2");
328        let mut data3 = TypedFacts::new();
329        data3.set("debug", FactValue::Boolean(true));
330        deffacts2.add_fact("Config", data3);
331
332        registry.register(deffacts1).unwrap();
333        registry.register(deffacts2).unwrap();
334
335        let all_facts = registry.get_all_facts();
336        assert_eq!(all_facts.len(), 3);
337        assert_eq!(registry.total_fact_count(), 3);
338    }
339
340    #[test]
341    fn test_registry_remove() {
342        let mut registry = DeffactsRegistry::new();
343
344        let deffacts = Deffacts::new("temp");
345        registry.register(deffacts).unwrap();
346
347        assert!(registry.exists("temp"));
348
349        let removed = registry.remove("temp").unwrap();
350        assert_eq!(removed.name, "temp");
351        assert!(!registry.exists("temp"));
352    }
353
354    #[test]
355    fn test_registry_list_deffacts() {
356        let mut registry = DeffactsRegistry::new();
357
358        registry.register(Deffacts::new("set1")).unwrap();
359        registry.register(Deffacts::new("set2")).unwrap();
360        registry.register(Deffacts::new("set3")).unwrap();
361
362        let list = registry.list_deffacts();
363        assert_eq!(list.len(), 3);
364        assert!(list.contains(&"set1".to_string()));
365        assert!(list.contains(&"set2".to_string()));
366        assert!(list.contains(&"set3".to_string()));
367    }
368
369    #[test]
370    fn test_registry_clear() {
371        let mut registry = DeffactsRegistry::new();
372
373        registry.register(Deffacts::new("set1")).unwrap();
374        registry.register(Deffacts::new("set2")).unwrap();
375
376        assert_eq!(registry.len(), 2);
377
378        registry.clear();
379
380        assert_eq!(registry.len(), 0);
381        assert!(registry.is_empty());
382    }
383
384    #[test]
385    fn test_builder_basic() {
386        let mut data = TypedFacts::new();
387        data.set("name", FactValue::String("Charlie".to_string()));
388        data.set("age", FactValue::Integer(25));
389
390        let deffacts = DeffactsBuilder::new("people")
391            .add_fact("Person", data)
392            .with_description("Initial people data")
393            .build();
394
395        assert_eq!(deffacts.name, "people");
396        assert_eq!(deffacts.fact_count(), 1);
397        assert_eq!(
398            deffacts.description,
399            Some("Initial people data".to_string())
400        );
401    }
402
403    #[test]
404    fn test_builder_multiple_facts() {
405        let mut person1 = TypedFacts::new();
406        person1.set("name", FactValue::String("Alice".to_string()));
407
408        let mut person2 = TypedFacts::new();
409        person2.set("name", FactValue::String("Bob".to_string()));
410
411        let mut config = TypedFacts::new();
412        config.set("debug", FactValue::Boolean(true));
413
414        let deffacts = DeffactsBuilder::new("startup")
415            .add_fact("Person", person1)
416            .add_fact("Person", person2)
417            .add_fact("Config", config)
418            .build();
419
420        assert_eq!(deffacts.fact_count(), 3);
421    }
422
423    #[test]
424    fn test_builder_add_facts_batch() {
425        let mut person1 = TypedFacts::new();
426        person1.set("name", FactValue::String("Alice".to_string()));
427
428        let mut person2 = TypedFacts::new();
429        person2.set("name", FactValue::String("Bob".to_string()));
430
431        let people = vec![person1, person2];
432
433        let deffacts = DeffactsBuilder::new("batch-people")
434            .add_facts("Person", people)
435            .build();
436
437        assert_eq!(deffacts.fact_count(), 2);
438        assert_eq!(deffacts.facts[0].fact_type, "Person");
439        assert_eq!(deffacts.facts[1].fact_type, "Person");
440    }
441
442    #[test]
443    fn test_integration_with_registry() {
444        let mut registry = DeffactsRegistry::new();
445
446        // Create deffacts using builder
447        let mut person_data = TypedFacts::new();
448        person_data.set("name", FactValue::String("Admin".to_string()));
449        person_data.set("role", FactValue::String("administrator".to_string()));
450
451        let mut config_data = TypedFacts::new();
452        config_data.set("max_users", FactValue::Integer(1000));
453        config_data.set("debug_mode", FactValue::Boolean(false));
454
455        let deffacts = DeffactsBuilder::new("system-startup")
456            .add_fact("User", person_data)
457            .add_fact("SystemConfig", config_data)
458            .with_description("System initialization facts")
459            .build();
460
461        // Register it
462        registry.register(deffacts).unwrap();
463
464        // Verify
465        assert!(registry.exists("system-startup"));
466        let retrieved = registry.get("system-startup").unwrap();
467        assert_eq!(retrieved.fact_count(), 2);
468        assert_eq!(
469            retrieved.description,
470            Some("System initialization facts".to_string())
471        );
472    }
473}