materialized-view 0.1.0

Simple incremental materialized views for the masses.
Documentation
use std::hash::Hash;
use byteorder::ByteOrder;
use crate::interning::hash::reproducible_hash_one;
use crate::rewriting::atom::{EncodedFact, EncodedGoal};
use crate::rewriting::rewrite::get_ith_term;

#[allow(dead_code)]
pub const ANY_VALUE: Option<()> = None;

type GoalIR = [u64; 3];

pub struct Goal { pub(crate) goal_ir: GoalIR }

impl<T> From<(Option<T>,)> for Goal where T: Hash {
    fn from(value: (Option<T>,)) -> Self {
        let first = if value.0.is_none() { 0 } else { reproducible_hash_one(&value.0.unwrap()) };

        return Self { goal_ir: [first, 0, 0] }
    }
}

impl<T, R> From<(Option<T>, Option<R>)> for Goal where T: Hash, R: Hash {
    fn from(value: (Option<T>, Option<R>)) -> Self {
        let first = if value.0.is_none() { 0 } else { reproducible_hash_one(&value.0.unwrap()) };
        let second = if value.1.is_none() { 0 } else { reproducible_hash_one(&value.1.unwrap()) };

        return Self { goal_ir: [first, second, 0] }
    }
}

impl<T, R, S> From<(Option<T>, Option<R>, Option<S>)> for Goal where T: Hash, R: Hash, S: Hash {
    fn from(value: (Option<T>, Option<R>, Option<S>)) -> Self {
        let first = if value.0.is_none() { 0 } else { reproducible_hash_one(&value.0.unwrap()) };
        let second = if value.1.is_none() { 0 } else { reproducible_hash_one(&value.1.unwrap()) };
        let third = if value.2.is_none() { 0 } else { reproducible_hash_one(&value.2.unwrap()) };

        return Self { goal_ir: [first, second, third] }
    }
}

pub(crate) fn pattern_match(goal: &EncodedGoal, fact: &EncodedFact) -> bool {
    let first_goal_constant = byteorder::NativeEndian::read_u24(get_ith_term(goal, 0).1);
    let first_fact_constant = byteorder::NativeEndian::read_u24(get_ith_term(fact, 0).1) >> 1;
    if first_goal_constant != 0 && first_goal_constant != first_fact_constant {
        return false
    }

    let second_goal_constant = byteorder::NativeEndian::read_u24(get_ith_term(goal, 1).1);
    let second_fact_constant = byteorder::NativeEndian::read_u24(get_ith_term(fact, 1).1) >> 1;
    if second_goal_constant != 0 && second_goal_constant != second_fact_constant {
        return false
    }

    let third_goal_constant = byteorder::NativeEndian::read_u24(get_ith_term(goal, 2).1);
    let third_fact_constant = byteorder::NativeEndian::read_u24(get_ith_term(fact, 2).1) >> 1;
    if third_goal_constant != 0 && third_goal_constant != third_fact_constant {
        return false
    }

    true
}

#[cfg(test)]
mod tests {
    use crate::builders::goal::pattern_match;
    use crate::rewriting::atom::{encode_fact, encode_goal};

    #[test]
    fn test_pattern_match() {
        let goal_one = encode_goal(&[1usize, 0, 0]);
        let goal_two = encode_goal(&[0usize, 0, 0]);
        let goal_three = encode_goal(&[467000usize, 510000, 511000]);

        let fact_one = encode_fact(&[1usize, 4, 0]);
        let fact_two = encode_fact(&[3usize, 4, 0]);
        let fact_three = encode_fact(&[467000usize, 510000, 511000]);

        assert!(pattern_match(&goal_one, &fact_one));
        assert!(!pattern_match(&goal_one, &fact_two));
        assert!(!pattern_match(&goal_one, &fact_three));

        assert!(pattern_match(&goal_two, &fact_one));
        assert!(pattern_match(&goal_two, &fact_two));
        assert!(pattern_match(&goal_two, &fact_three));

        assert!(!pattern_match(&goal_three, &fact_one));
        assert!(!pattern_match(&goal_three, &fact_two));
        assert!(pattern_match(&goal_three, &fact_three));
    }
}