materialized_view/builders/
rule.rs1use 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}