//! A database instance is a set of ground atoms (facts). use std::collections::HashSet; use std::fmt; use super::atom::Atom; /// A database instance containing ground atoms. #[derive(Debug, Clone, Default)] pub struct Instance { facts: HashSet, } impl Instance { /// Create an empty instance. pub fn new() -> Self { Instance { facts: HashSet::new(), } } /// Add a fact to the instance. Returns true if the fact was new. pub fn add(&mut self, fact: Atom) -> bool { debug_assert!(fact.is_ground(), "Facts must be ground atoms"); self.facts.insert(fact) } /// Check if the instance contains a fact. pub fn contains(&self, fact: &Atom) -> bool { self.facts.contains(fact) } /// Get the number of facts. pub fn len(&self) -> usize { self.facts.len() } /// Check if the instance is empty. pub fn is_empty(&self) -> bool { self.facts.is_empty() } /// Iterate over all facts. pub fn iter(&self) -> impl Iterator { self.facts.iter() } /// Get all facts with a given predicate. pub fn facts_for_predicate(&self, predicate: &str) -> Vec<&Atom> { self.facts .iter() .filter(|a| a.predicate == predicate) .collect() } } impl fmt::Display for Instance { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { writeln!(f, "Instance {{")?; for fact in &self.facts { writeln!(f, " {}", fact)?; } write!(f, "}}") } } impl FromIterator for Instance { fn from_iter>(iter: T) -> Self { let mut instance = Instance::new(); for atom in iter { instance.add(atom); } instance } } #[cfg(test)] mod tests { use super::*; use crate::chase::term::Term; #[test] fn test_instance_operations() { let mut instance = Instance::new(); let fact1 = Atom::new( "Parent", vec![Term::constant("alice"), Term::constant("bob")], ); let fact2 = Atom::new( "Parent", vec![Term::constant("bob"), Term::constant("carol")], ); assert!(instance.add(fact1.clone())); assert!(instance.add(fact2.clone())); assert!(!instance.add(fact1.clone())); // Duplicate assert_eq!(instance.len(), 2); assert!(instance.contains(&fact1)); } #[test] fn test_facts_for_predicate() { let instance: Instance = vec![ Atom::new( "Parent", vec![Term::constant("alice"), Term::constant("bob")], ), Atom::new( "Person", vec![Term::constant("alice")], ), ] .into_iter() .collect(); assert_eq!(instance.facts_for_predicate("Parent").len(), 1); assert_eq!(instance.facts_for_predicate("Person").len(), 1); assert_eq!(instance.facts_for_predicate("Other").len(), 0); } }