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::rete::facts::TypedFacts;
7use crate::errors::{Result, RuleEngineError};
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.remove(name).ok_or_else(|| {
124            RuleEngineError::EvaluationError {
125                message: format!("Deffacts '{}' not found", name),
126            }
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.push(FactInstance::new(fact_type_str.clone(), data));
203        }
204        self
205    }
206
207    /// Set the description
208    pub fn with_description(mut self, description: impl Into<String>) -> Self {
209        self.description = Some(description.into());
210        self
211    }
212
213    /// Build the deffacts
214    pub fn build(self) -> Deffacts {
215        Deffacts {
216            name: self.name,
217            facts: self.facts,
218            description: self.description,
219        }
220    }
221}
222
223#[cfg(test)]
224mod tests {
225    use super::*;
226    use crate::rete::facts::FactValue;
227
228    #[test]
229    fn test_create_fact_instance() {
230        let mut data = TypedFacts::new();
231        data.set("name", FactValue::String("John".to_string()));
232        data.set("age", FactValue::Integer(30));
233
234        let fact = FactInstance::new("Person", data);
235        assert_eq!(fact.fact_type, "Person");
236        assert_eq!(fact.data.get("name"), Some(&FactValue::String("John".to_string())));
237    }
238
239    #[test]
240    fn test_deffacts_basic() {
241        let mut deffacts = Deffacts::new("initial-data");
242
243        let mut person_data = TypedFacts::new();
244        person_data.set("name", FactValue::String("Alice".to_string()));
245
246        deffacts.add_fact("Person", person_data);
247        deffacts.set_description("Initial person data");
248
249        assert_eq!(deffacts.name, "initial-data");
250        assert_eq!(deffacts.fact_count(), 1);
251        assert!(!deffacts.is_empty());
252        assert_eq!(deffacts.description, Some("Initial person data".to_string()));
253    }
254
255    #[test]
256    fn test_registry_register() {
257        let mut registry = DeffactsRegistry::new();
258
259        let mut deffacts = Deffacts::new("test");
260        let mut data = TypedFacts::new();
261        data.set("value", FactValue::Integer(42));
262        deffacts.add_fact("Config", data);
263
264        registry.register(deffacts).unwrap();
265
266        assert!(registry.exists("test"));
267        assert_eq!(registry.len(), 1);
268    }
269
270    #[test]
271    fn test_registry_duplicate_error() {
272        let mut registry = DeffactsRegistry::new();
273
274        let deffacts1 = Deffacts::new("test");
275        let deffacts2 = Deffacts::new("test");
276
277        registry.register(deffacts1).unwrap();
278        let result = registry.register(deffacts2);
279
280        assert!(result.is_err());
281    }
282
283    #[test]
284    fn test_registry_register_or_replace() {
285        let mut registry = DeffactsRegistry::new();
286
287        let mut deffacts1 = Deffacts::new("test");
288        let mut data1 = TypedFacts::new();
289        data1.set("version", FactValue::Integer(1));
290        deffacts1.add_fact("Config", data1);
291
292        let mut deffacts2 = Deffacts::new("test");
293        let mut data2 = TypedFacts::new();
294        data2.set("version", FactValue::Integer(2));
295        deffacts2.add_fact("Config", data2);
296
297        registry.register_or_replace(deffacts1);
298        registry.register_or_replace(deffacts2);
299
300        assert_eq!(registry.len(), 1);
301        let deffacts = registry.get("test").unwrap();
302        assert_eq!(deffacts.fact_count(), 1);
303    }
304
305    #[test]
306    fn test_registry_get_all_facts() {
307        let mut registry = DeffactsRegistry::new();
308
309        // First deffacts with 2 facts
310        let mut deffacts1 = Deffacts::new("set1");
311        let mut data1 = TypedFacts::new();
312        data1.set("name", FactValue::String("Alice".to_string()));
313        deffacts1.add_fact("Person", data1);
314
315        let mut data2 = TypedFacts::new();
316        data2.set("name", FactValue::String("Bob".to_string()));
317        deffacts1.add_fact("Person", data2);
318
319        // Second deffacts with 1 fact
320        let mut deffacts2 = Deffacts::new("set2");
321        let mut data3 = TypedFacts::new();
322        data3.set("debug", FactValue::Boolean(true));
323        deffacts2.add_fact("Config", data3);
324
325        registry.register(deffacts1).unwrap();
326        registry.register(deffacts2).unwrap();
327
328        let all_facts = registry.get_all_facts();
329        assert_eq!(all_facts.len(), 3);
330        assert_eq!(registry.total_fact_count(), 3);
331    }
332
333    #[test]
334    fn test_registry_remove() {
335        let mut registry = DeffactsRegistry::new();
336
337        let deffacts = Deffacts::new("temp");
338        registry.register(deffacts).unwrap();
339
340        assert!(registry.exists("temp"));
341
342        let removed = registry.remove("temp").unwrap();
343        assert_eq!(removed.name, "temp");
344        assert!(!registry.exists("temp"));
345    }
346
347    #[test]
348    fn test_registry_list_deffacts() {
349        let mut registry = DeffactsRegistry::new();
350
351        registry.register(Deffacts::new("set1")).unwrap();
352        registry.register(Deffacts::new("set2")).unwrap();
353        registry.register(Deffacts::new("set3")).unwrap();
354
355        let list = registry.list_deffacts();
356        assert_eq!(list.len(), 3);
357        assert!(list.contains(&"set1".to_string()));
358        assert!(list.contains(&"set2".to_string()));
359        assert!(list.contains(&"set3".to_string()));
360    }
361
362    #[test]
363    fn test_registry_clear() {
364        let mut registry = DeffactsRegistry::new();
365
366        registry.register(Deffacts::new("set1")).unwrap();
367        registry.register(Deffacts::new("set2")).unwrap();
368
369        assert_eq!(registry.len(), 2);
370
371        registry.clear();
372
373        assert_eq!(registry.len(), 0);
374        assert!(registry.is_empty());
375    }
376
377    #[test]
378    fn test_builder_basic() {
379        let mut data = TypedFacts::new();
380        data.set("name", FactValue::String("Charlie".to_string()));
381        data.set("age", FactValue::Integer(25));
382
383        let deffacts = DeffactsBuilder::new("people")
384            .add_fact("Person", data)
385            .with_description("Initial people data")
386            .build();
387
388        assert_eq!(deffacts.name, "people");
389        assert_eq!(deffacts.fact_count(), 1);
390        assert_eq!(deffacts.description, Some("Initial people data".to_string()));
391    }
392
393    #[test]
394    fn test_builder_multiple_facts() {
395        let mut person1 = TypedFacts::new();
396        person1.set("name", FactValue::String("Alice".to_string()));
397
398        let mut person2 = TypedFacts::new();
399        person2.set("name", FactValue::String("Bob".to_string()));
400
401        let mut config = TypedFacts::new();
402        config.set("debug", FactValue::Boolean(true));
403
404        let deffacts = DeffactsBuilder::new("startup")
405            .add_fact("Person", person1)
406            .add_fact("Person", person2)
407            .add_fact("Config", config)
408            .build();
409
410        assert_eq!(deffacts.fact_count(), 3);
411    }
412
413    #[test]
414    fn test_builder_add_facts_batch() {
415        let mut person1 = TypedFacts::new();
416        person1.set("name", FactValue::String("Alice".to_string()));
417
418        let mut person2 = TypedFacts::new();
419        person2.set("name", FactValue::String("Bob".to_string()));
420
421        let people = vec![person1, person2];
422
423        let deffacts = DeffactsBuilder::new("batch-people")
424            .add_facts("Person", people)
425            .build();
426
427        assert_eq!(deffacts.fact_count(), 2);
428        assert_eq!(deffacts.facts[0].fact_type, "Person");
429        assert_eq!(deffacts.facts[1].fact_type, "Person");
430    }
431
432    #[test]
433    fn test_integration_with_registry() {
434        let mut registry = DeffactsRegistry::new();
435
436        // Create deffacts using builder
437        let mut person_data = TypedFacts::new();
438        person_data.set("name", FactValue::String("Admin".to_string()));
439        person_data.set("role", FactValue::String("administrator".to_string()));
440
441        let mut config_data = TypedFacts::new();
442        config_data.set("max_users", FactValue::Integer(1000));
443        config_data.set("debug_mode", FactValue::Boolean(false));
444
445        let deffacts = DeffactsBuilder::new("system-startup")
446            .add_fact("User", person_data)
447            .add_fact("SystemConfig", config_data)
448            .with_description("System initialization facts")
449            .build();
450
451        // Register it
452        registry.register(deffacts).unwrap();
453
454        // Verify
455        assert!(registry.exists("system-startup"));
456        let retrieved = registry.get("system-startup").unwrap();
457        assert_eq!(retrieved.fact_count(), 2);
458        assert_eq!(retrieved.description, Some("System initialization facts".to_string()));
459    }
460}