materialized_view/builders/
rule.rs

1use std::any::Any;
2use std::fmt::{Debug, Formatter};
3use std::hash::{Hash, Hasher};
4use datalog_syntax::TypedValue;
5use crate::interning::hash::{new_random_state, reproducible_hash_one};
6
7pub enum Term<T: Hash> {
8    Var(String),
9    Const(T)
10}
11
12#[allow(non_snake_case)]
13pub fn Var(name: &str) -> Term<String> {
14    return Term::Var(name.to_string())
15}
16
17#[allow(non_snake_case)]
18pub fn Const<T: Hash>(value: T) -> Term<T> {
19    return Term::Const(value)
20}
21
22type TermData = Option<Box<dyn Any>>;
23type TermIR = (bool, u64);
24
25impl<T> From<&Term<T>> for TermIR where T: Hash {
26    fn from(value: &Term<T>) -> Self {
27        match value {
28            Term::Var(name) => (true, reproducible_hash_one(name)),
29            Term::Const(value) => (false, reproducible_hash_one(value))
30        }
31    }
32}
33
34impl<T: 'static> From<Term<T>> for TermData where T: Hash {
35    fn from(value: Term<T>) -> Self {
36        match value {
37            Term::Const(value) => Some(Box::new(value)),
38            _ => None
39        }
40    }
41}
42
43type AtomData = [TermData; 3];
44type AtomIR = [(bool, u64); 3];
45
46pub struct Atom { pub(crate) atom_ir: AtomIR, pub(crate) atom_data: AtomData, pub(crate) symbol: u64 }
47
48impl PartialEq for Atom {
49    fn eq(&self, other: &Self) -> bool {
50        self.atom_ir.eq(&other.atom_ir) && self.symbol == other.symbol
51    }
52}
53
54impl Eq for Atom {}
55
56impl Debug for Atom {
57    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
58        self.atom_ir.fmt(f)
59    }
60}
61
62impl<T: 'static> From<(&str, (Term<T>,))> for Atom where T: Hash {
63    fn from(value: (&str, (Term<T>,))) -> Self {
64        let first = TermIR::from(&value.1.0);
65        let first_data = TermData::from(value.1.0);
66
67        return Self { atom_ir: [ first, (false, 0), (false, 0)], atom_data: [ first_data, None, None ], symbol: reproducible_hash_one(value.0) }
68    }
69}
70
71impl<T: 'static, R: 'static> From<(&str, (Term<T>, Term<R>))> for Atom where T: Hash, R: Hash {
72    fn from(value: (&str, (Term<T>, Term<R>))) -> Self {
73        let first = TermIR::from(&value.1.0);
74        let first_data = TermData::from(value.1.0);
75
76        let second = TermIR::from(&value.1.1);
77        let second_data = TermData::from(value.1.1);
78
79        return Self { atom_ir: [first, second, (false, 0)], atom_data: [ first_data, second_data, None ], symbol: reproducible_hash_one(value.0) }
80    }
81}
82
83impl<T: 'static, R: 'static, S: 'static> From<(&str, (Term<T>, Term<R>, Term<S>))> for Atom where T: Hash, R: Hash, S: Hash {
84    fn from(value: (&str, (Term<T>, Term<R>, Term<S>))) -> Self {
85        let first = TermIR::from(&value.1.0);
86        let first_data = TermData::from(value.1.0);
87
88        let second = TermIR::from(&value.1.1);
89        let second_data = TermData::from(value.1.1);
90
91        let third = TermIR::from(&value.1.2);
92        let third_data = TermData::from(value.1.2);
93
94        return Self { atom_ir: [first, second, third], atom_data: [ first_data, second_data, third_data ], symbol: reproducible_hash_one(value.0) }
95    }
96}
97
98pub type RuleIdentifier = u64;
99
100#[derive(PartialEq, Eq, Debug)]
101pub struct Rule { pub(crate) head: Atom, pub(crate) body: Vec<Atom>, pub(crate) id: RuleIdentifier }
102
103impl<T, R> From<(T, Vec<R>)> for Rule where T: Into<Atom>, R: Into<Atom> {
104    fn from(value: (T, Vec<R>)) -> Self {
105        let head = value.0.into();
106        let body: Vec<Atom> = value.1.into_iter().map(|body_atom| body_atom.into()).collect();
107
108        let mut rs = new_random_state();
109        head.atom_ir.hash(&mut rs);
110
111        for body_atom in &body {
112            body_atom.atom_ir.hash(&mut rs);
113        }
114
115        Self { head, body, id: rs.finish() }
116    }
117}
118
119struct PositiveDatalogTerm (datalog_syntax::Term);
120
121impl PositiveDatalogTerm {
122    pub fn to_datalog_syntax_term(self) -> datalog_syntax::Term {
123        self.0
124    }
125}
126
127impl From<PositiveDatalogTerm> for TermIR {
128    fn from(value: PositiveDatalogTerm) -> Self {
129        match value.to_datalog_syntax_term() {
130            datalog_syntax::Term::Variable(name) => {
131                (&Var(name.as_str())).into()
132            }
133            datalog_syntax::Term::Constant(typed_value) => {
134                match typed_value {
135                    TypedValue::Str(inner) => { (&Const(inner)).into() }
136                    TypedValue::Int(inner) => { (&Const(inner)).into()}
137                    TypedValue::Bool(inner) => { (&Const(inner)).into() }
138                }
139            }
140        }
141    }
142}
143
144impl From<PositiveDatalogTerm> for TermData {
145    fn from(value: PositiveDatalogTerm) -> Self {
146        match value.to_datalog_syntax_term() {
147            datalog_syntax::Term::Variable(_name) => {
148                None
149            }
150            datalog_syntax::Term::Constant(typed_value) => {
151                match typed_value {
152                    TypedValue::Str(inner) => { Some(Box::new(inner)) }
153                    TypedValue::Int(inner) => { Some(Box::new(inner)) }
154                    TypedValue::Bool(inner) => { Some(Box::new(inner)) }
155                }
156            }
157        }
158    }
159}
160
161impl From<datalog_syntax::Rule> for Rule {
162    fn from(value: datalog_syntax::Rule) -> Self {
163        let head_symbol = value.head.symbol.as_str();
164        let mut head_term_ir: AtomIR = [(false, 0); 3];
165        let mut head_term_data: AtomData = Default::default();
166
167        value
168            .head
169            .terms
170            .into_iter()
171            .map(|term| (TermIR::from(PositiveDatalogTerm(term.clone())), TermData::from(PositiveDatalogTerm(term))))
172            .enumerate()
173            .for_each(|(idx, (term_ir, term_data))| {
174                head_term_ir[idx] = term_ir;
175                head_term_data[idx] = term_data;
176            });
177
178        let head = Atom {
179            atom_ir: head_term_ir,
180            atom_data: head_term_data,
181            symbol: reproducible_hash_one(head_symbol),
182        };
183
184        let body = value
185            .body
186            .into_iter()
187            .map(|atom| {
188                let current_atom_symbol = atom.symbol.as_str();
189                let mut current_atom_term_ir: AtomIR = [(false, 0); 3];
190                let mut current_atom_term_data: AtomData = Default::default();
191
192                atom
193                    .terms
194                    .into_iter()
195                    .map(|term| (TermIR::from(PositiveDatalogTerm(term.clone())), TermData::from(PositiveDatalogTerm(term))))
196                    .enumerate()
197                    .for_each(|(idx, (term_ir, term_data))| {
198                        current_atom_term_ir[idx] = term_ir;
199                        current_atom_term_data[idx] = term_data;
200                    });
201                
202                Atom {
203                    atom_ir: current_atom_term_ir,
204                    atom_data: current_atom_term_data,
205                    symbol: reproducible_hash_one(current_atom_symbol),
206                }
207            })
208            .collect();
209
210        Rule::from((head, body))
211    }
212}