use std::collections::{HashMap, HashSet};
use crate::kb::StoredFact;
pub trait FactStore: Send {
fn lookup_predicate(&self, relation: &str) -> Option<&HashSet<StoredFact>>;
fn contains(&self, fact: &StoredFact) -> bool;
fn insert(&mut self, fact: StoredFact);
fn clear(&mut self);
fn all_facts(&self) -> Box<dyn Iterator<Item = &StoredFact> + '_>;
fn len(&self) -> usize;
fn is_empty(&self) -> bool {
self.len() == 0
}
fn remove(&mut self, fact: &StoredFact) -> bool;
fn clone_box(&self) -> Box<dyn FactStore>;
}
#[derive(Clone)]
pub struct InMemoryFactStore {
predicate_index: HashMap<String, HashSet<StoredFact>>,
}
impl InMemoryFactStore {
pub fn new() -> Self {
Self {
predicate_index: HashMap::new(),
}
}
}
impl Default for InMemoryFactStore {
fn default() -> Self {
Self::new()
}
}
impl FactStore for InMemoryFactStore {
fn lookup_predicate(&self, relation: &str) -> Option<&HashSet<StoredFact>> {
self.predicate_index.get(relation)
}
fn contains(&self, fact: &StoredFact) -> bool {
if let Some(set) = self.predicate_index.get(fact.relation()) {
set.contains(fact)
} else {
false
}
}
fn insert(&mut self, fact: StoredFact) {
let rel = fact.relation().to_string();
self.predicate_index.entry(rel).or_default().insert(fact);
}
fn clear(&mut self) {
self.predicate_index.clear();
}
fn all_facts(&self) -> Box<dyn Iterator<Item = &StoredFact> + '_> {
Box::new(self.predicate_index.values().flatten())
}
fn len(&self) -> usize {
self.predicate_index.values().map(HashSet::len).sum()
}
fn remove(&mut self, fact: &StoredFact) -> bool {
let Some(set) = self.predicate_index.get_mut(fact.relation()) else {
return false;
};
let removed = set.remove(fact);
if removed && set.is_empty() {
self.predicate_index.remove(fact.relation());
}
removed
}
fn clone_box(&self) -> Box<dyn FactStore> {
Box::new(self.clone())
}
}