materialized-view 0.1.0

Simple incremental materialized views for the masses.
Documentation
use std::any::Any;
use identity_hash::BuildIdentityHasher;
use indexmap::{IndexMap, IndexSet};
use crate::builders::fact::Fact;
use crate::builders::goal::Goal;
use crate::builders::rule::{Atom, Rule};
use crate::engine::storage::{RelationIdentifier};
use crate::rewriting::atom::{encode_goal, EncodedGoal};

const CONSTANT_MAXIMUM_LEN: usize = (1 << 23) - 1;
const VARIABLE_MAXIMUM_LEN: usize = (1 << 7) - 1;

type ConstantInterner = IndexMap<u64, Box<dyn Any>, BuildIdentityHasher<u64>>;
type VariableInterner = IndexSet<u64, BuildIdentityHasher<u64>>;
#[derive(Default)]
pub struct InternmentLayer {
    constant_interner: ConstantInterner,
    variable_interner: VariableInterner,
}

pub type InternedTerm = usize;
pub type InternedTerms = [(bool, InternedTerm); 3];
pub type InternedAtom = (RelationIdentifier, InternedTerms);
pub type RuleIdentifier = u64;
pub type InternedRule = (RuleIdentifier, InternedAtom, Vec<InternedAtom>);
pub type InternedConstantTerms = [usize; 3];

impl InternmentLayer {
    pub fn resolve_interned_constant<T: 'static>(&self, interned_constant: usize) -> Option<&T> {
        if let Some(actual_value) = self.constant_interner.get_index(interned_constant - 1) {
            return Some(actual_value.1.downcast_ref::<T>().unwrap())
        }

        None
    }
    pub fn push_constant(&mut self, hash: u64, data: Box<dyn Any>) -> usize {
        if self.constant_interner.len() == CONSTANT_MAXIMUM_LEN {
            panic!("There can not be more than {} unique constant values", CONSTANT_MAXIMUM_LEN)
        }

        self.constant_interner.insert_full(hash, data).0 + 1
    }
    pub fn push_variable(&mut self, hash: u64) -> usize {
        if self.constant_interner.len() == VARIABLE_MAXIMUM_LEN {
            panic!("There can not be more than {} unique constant values", VARIABLE_MAXIMUM_LEN)
        }

        self.variable_interner.insert_full(hash).0 + 1
    }
    pub fn intern_fact(&mut self, fact: Fact) -> InternedConstantTerms {
        let mut interned_constant_terms = [0; 3];
        let mut fact = fact;

        let first_key = *fact.fact_ir.get(0).unwrap();
        if let Some(first_value) = fact.fact_data[0].take() {
            interned_constant_terms[0] = self.push_constant(first_key, first_value);
        }

        let second_key = *fact.fact_ir.get(1).unwrap();
        if let Some(second_value) = fact.fact_data[1].take() {
            interned_constant_terms[1] = self.push_constant(second_key, second_value);
        }
        
        let third_key = *fact.fact_ir.get(2).unwrap();
        if let Some(third_value) = fact.fact_data[2].take() {
            interned_constant_terms[2] = self.push_constant(third_key, third_value);
        }

        interned_constant_terms
    }
    pub fn intern_atom(&mut self, atom: Atom) -> InternedAtom {
        let mut interned_atom_ir = [ (false, 0); 3 ];
        let mut atom = atom;

        let first_key = atom.atom_ir[0];
        if first_key.1 != 0 {
            if !first_key.0 {
                interned_atom_ir[0] = (false, self.push_constant(first_key.1, atom.atom_data[0].take().unwrap()));
            } else {
                interned_atom_ir[0] = (true, self.push_variable(first_key.1))
            }
        }

        let second_key = atom.atom_ir[1];
        if second_key.1 != 0 {
            if !second_key.0 {
                interned_atom_ir[1] = (false, self.push_constant(second_key.1, atom.atom_data[1].take().unwrap()));
            } else {
                interned_atom_ir[1] = (true, self.push_variable(second_key.1));
            }
        }

        let third_key = atom.atom_ir[2];
        if third_key.1 != 0 {
            if !third_key.0 {
                interned_atom_ir[2] = (false, self.push_constant(third_key.1, atom.atom_data[2].take().unwrap()));
            } else {
                interned_atom_ir[2] = (true, self.push_variable(third_key.1));
            }
        }

        (atom.symbol, interned_atom_ir)
    }
    pub fn intern_rule(&mut self, rule: Rule) -> InternedRule {
        (rule.id, self.intern_atom(rule.head), rule.body.into_iter().map(|atom| self.intern_atom(atom)).collect())
    }
    pub fn resolve_fact(&self, fact: Fact) -> Option<InternedConstantTerms> {
        let mut resolved_fact = [0; 3];
        for i in 0..3usize {
            if fact.fact_ir[i] == 0 {
                break;
            }

            if let Some(resolved_constant) = self.constant_interner.get_index_of(&fact.fact_ir[i]) {
                resolved_fact[i] = resolved_constant + 1;
            } else {
                return None
            };
        }

        Some(resolved_fact)
    }
    pub fn resolve_goal(&self, goal: Goal) -> Option<EncodedGoal> {
        let mut resolved_partial_fact = [0; 3];
        for i in 0..3usize {
            if goal.goal_ir[i] != 0 {
                if let Some(resolved_constant) = self.constant_interner.get_index_of(&goal.goal_ir[i]) {
                    resolved_partial_fact[i] = resolved_constant + 1;
                } else {
                    return None
                };
            }
        }

        Some(encode_goal(&resolved_partial_fact))
    }
    pub fn resolve_atom(&self, atom: Atom) -> Option<InternedAtom> {
        let mut resolved_atom = [(false, 0); 3];
        for i in 0..3usize {
            if atom.atom_ir[i].1 != 0 {
                if !atom.atom_ir[i].0 {
                    if let Some(resolved_constant) = self.constant_interner.get_index_of(&atom.atom_ir[i].1) {
                        resolved_atom[i] = (false, resolved_constant + 1);
                    } else {
                        return None
                    }
                } else {
                    if let Some(resolved_variable) = self.variable_interner.get_index_of(&atom.atom_ir[i].1) {
                        resolved_atom[i] = (true, resolved_variable + 1);
                    } else {
                        return None
                    }
                }
            }
        }

        Some((atom.symbol, resolved_atom))
    }
    pub fn resolve_rule(&self, rule: Rule) -> Option<InternedRule> {
        if let Some(resolved_head) = self.resolve_atom(rule.head) {
            let mut resolved_body = vec![];

            for body_atom in rule.body {
                if let Some(resolved_body_atom) = self.resolve_atom(body_atom) {
                    resolved_body.push(resolved_body_atom);
                } else {
                    return None
                }
            }

            return Some((rule.id, resolved_head, resolved_body))
        }

        None
    }
}