diff --git a/examples/testcases.rs b/examples/testcases.rs index a6025165..21403369 100644 --- a/examples/testcases.rs +++ b/examples/testcases.rs @@ -1541,9 +1541,6 @@ fn expressions( //date equal builder.add_authority_check("check if 2020-12-04T09:46:41+00:00 == 2020-12-04T09:46:41+00:00"); - //symbol equal - builder.add_authority_check("check if #abc == #abc"); - //bytes equal builder.add_authority_check("check if hex:12ab == hex:12ab"); @@ -1553,7 +1550,6 @@ fn expressions( builder.add_authority_check("check if [true, false, true].contains(true)"); builder.add_authority_check("check if [\"abc\", \"def\"].contains(\"abc\")"); builder.add_authority_check("check if [hex:12ab, hex:34de].contains(hex:34de)"); - builder.add_authority_check("check if [#hello, #world].contains(#hello)"); let biscuit = builder.build_with_rng(rng).unwrap(); token = print_blocks(&biscuit); diff --git a/src/datalog/expression.rs b/src/datalog/expression.rs index b615d238..6bf097fb 100644 --- a/src/datalog/expression.rs +++ b/src/datalog/expression.rs @@ -23,11 +23,11 @@ pub enum Unary { } impl Unary { - fn evaluate(&self, value: ID) -> Option { + fn evaluate(&self, value: ID, symbols: &SymbolTable) -> Option { match (self, value) { (Unary::Negate, ID::Bool(b)) => Some(ID::Bool(!b)), (Unary::Parens, i) => Some(i), - (Unary::Length, ID::Str(s)) => Some(ID::Integer(s.len() as i64)), + (Unary::Length, ID::Str(i)) => symbols.get_s(i).map(|s| ID::Integer(s.len() as i64)), (Unary::Length, ID::Bytes(s)) => Some(ID::Integer(s.len() as i64)), (Unary::Length, ID::Set(s)) => Some(ID::Integer(s.len() as i64)), _ => { @@ -68,7 +68,7 @@ pub enum Binary { } impl Binary { - fn evaluate(&self, left: ID, right: ID) -> Option { + fn evaluate(&self, left: ID, right: ID, symbols: &SymbolTable) -> Option { match (self, left, right) { // integer (Binary::LessThan, ID::Integer(i), ID::Integer(j)) => Some(ID::Bool(i < j)), @@ -83,14 +83,23 @@ impl Binary { // string (Binary::Prefix, ID::Str(s), ID::Str(pref)) => { - Some(ID::Bool(s.as_str().starts_with(pref.as_str()))) + match (symbols.get_s(s), symbols.get_s(pref)) { + (Some(s), Some(pref)) => Some(ID::Bool(s.starts_with(pref))), + _ => None, + } } (Binary::Suffix, ID::Str(s), ID::Str(suff)) => { - Some(ID::Bool(s.as_str().ends_with(suff.as_str()))) + match (symbols.get_s(s), symbols.get_s(suff)) { + (Some(s), Some(suff)) => Some(ID::Bool(s.ends_with(suff))), + _ => None, + } } - (Binary::Regex, ID::Str(s), ID::Str(r)) => Some(ID::Bool( - Regex::new(&r).map(|re| re.is_match(&s)).unwrap_or(false), - )), + (Binary::Regex, ID::Str(s), ID::Str(r)) => match (symbols.get_s(s), symbols.get_s(r)) { + (Some(s), Some(r)) => Some(ID::Bool( + Regex::new(&r).map(|re| re.is_match(&s)).unwrap_or(false), + )), + _ => None, + }, (Binary::Equal, ID::Str(i), ID::Str(j)) => Some(ID::Bool(i == j)), // date @@ -101,7 +110,6 @@ impl Binary { (Binary::Equal, ID::Date(i), ID::Date(j)) => Some(ID::Bool(i == j)), // symbol - (Binary::Equal, ID::Symbol(i), ID::Symbol(j)) => Some(ID::Bool(i == j)), // byte array (Binary::Equal, ID::Bytes(i), ID::Bytes(j)) => Some(ID::Bool(i == j)), @@ -130,9 +138,6 @@ impl Binary { (Binary::Contains, ID::Set(set), ID::Bytes(i)) => { Some(ID::Bool(set.contains(&ID::Bytes(i)))) } - (Binary::Contains, ID::Set(set), ID::Symbol(i)) => { - Some(ID::Bool(set.contains(&ID::Symbol(i)))) - } // boolean (Binary::And, ID::Bool(i), ID::Bool(j)) => Some(ID::Bool(i & j)), @@ -168,7 +173,7 @@ impl Binary { } impl Expression { - pub fn evaluate(&self, values: &HashMap) -> Option { + pub fn evaluate(&self, values: &HashMap, symbols: &SymbolTable) -> Option { let mut stack: Vec = Vec::new(); for op in self.ops.iter() { @@ -187,16 +192,18 @@ impl Expression { //println!("expected a value on the stack"); return None; } - Some(id) => match unary.evaluate(id) { + Some(id) => match unary.evaluate(id, symbols) { Some(res) => stack.push(res), None => return None, }, }, Op::Binary(binary) => match (stack.pop(), stack.pop()) { - (Some(right_id), Some(left_id)) => match binary.evaluate(left_id, right_id) { - Some(res) => stack.push(res), - None => return None, - }, + (Some(right_id), Some(left_id)) => { + match binary.evaluate(left_id, right_id, symbols) { + Some(res) => stack.push(res), + None => return None, + } + } _ => { //println!("expected two values on the stack"); return None; @@ -264,12 +271,13 @@ mod tests { let e = Expression { ops }; println!("print: {}", e.print(&symbols).unwrap()); - let res = e.evaluate(&values); + let res = e.evaluate(&values, &symbols); assert_eq!(res, Some(ID::Bool(true))); } #[test] fn checked() { + let symbols = SymbolTable::new(); let ops = vec![ Op::Value(ID::Integer(1)), Op::Value(ID::Integer(0)), @@ -278,7 +286,7 @@ mod tests { let values = HashMap::new(); let e = Expression { ops }; - let res = e.evaluate(&values); + let res = e.evaluate(&values, &symbols); assert_eq!(res, None); let ops = vec![ @@ -289,7 +297,7 @@ mod tests { let values = HashMap::new(); let e = Expression { ops }; - let res = e.evaluate(&values); + let res = e.evaluate(&values, &symbols); assert_eq!(res, None); let ops = vec![ @@ -300,7 +308,7 @@ mod tests { let values = HashMap::new(); let e = Expression { ops }; - let res = e.evaluate(&values); + let res = e.evaluate(&values, &symbols); assert_eq!(res, None); let ops = vec![ @@ -311,7 +319,7 @@ mod tests { let values = HashMap::new(); let e = Expression { ops }; - let res = e.evaluate(&values); + let res = e.evaluate(&values, &symbols); assert_eq!(res, None); } diff --git a/src/datalog/mod.rs b/src/datalog/mod.rs index e2dbc233..26841fc1 100644 --- a/src/datalog/mod.rs +++ b/src/datalog/mod.rs @@ -13,10 +13,9 @@ pub use symbol::*; #[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)] pub enum ID { - Symbol(Symbol), Variable(u32), Integer(i64), - Str(String), + Str(Symbol), Date(u64), Bytes(Vec), Bool(bool), @@ -26,10 +25,9 @@ pub enum ID { impl From<&ID> for ID { fn from(i: &ID) -> Self { match i { - ID::Symbol(ref s) => ID::Symbol(*s), ID::Variable(ref v) => ID::Variable(*v), ID::Integer(ref i) => ID::Integer(*i), - ID::Str(ref s) => ID::Str(s.clone()), + ID::Str(ref s) => ID::Str(*s), ID::Date(ref d) => ID::Date(*d), ID::Bytes(ref b) => ID::Bytes(b.clone()), ID::Bool(ref b) => ID::Bool(*b), @@ -103,7 +101,11 @@ impl fmt::Display for Fact { } impl Rule { - pub fn apply<'a>(&'a self, facts: &'a HashSet) -> impl Iterator + 'a { + pub fn apply<'a>( + &'a self, + facts: &'a HashSet, + symbols: &'a SymbolTable, + ) -> impl Iterator + 'a { // gather all of the variables used in that rule let variables_set = self .body @@ -118,7 +120,7 @@ impl Rule { let head = self.head.clone(); let variables = MatchedVariables::new(variables_set); - CombineIt::new(variables, &self.body, &self.expressions, facts).filter_map(move |h| { + CombineIt::new(variables, &self.body, &self.expressions, facts, symbols).filter_map(move |h| { let mut p = head.clone(); for index in 0..p.ids.len() { let value = match &p.ids[index] { @@ -139,7 +141,7 @@ impl Rule { }) } - pub fn find_match(&self, facts: &HashSet) -> bool { + pub fn find_match(&self, facts: &HashSet, symbols: &SymbolTable) -> bool { // gather all of the variables used in that rule let variables_set = self .body @@ -154,7 +156,7 @@ impl Rule { let variables = MatchedVariables::new(variables_set); - let mut it = CombineIt::new(variables, &self.body, &self.expressions, facts).filter_map(|h| { + let mut it = CombineIt::new(variables, &self.body, &self.expressions, facts, symbols).filter_map(|h| { let mut p = self.head.clone(); for index in 0..p.ids.len() { let value = match &p.ids[index] { @@ -185,6 +187,7 @@ pub struct CombineIt<'a> { predicates: &'a [Predicate], expressions: &'a [Expression], all_facts: &'a HashSet, + symbols: &'a SymbolTable, current_facts: Box + 'a>, current_it: Option>>, } @@ -195,6 +198,7 @@ impl<'a> CombineIt<'a> { predicates: &'a [Predicate], expressions: &'a [Expression], facts: &'a HashSet, + symbols: &'a SymbolTable, ) -> Self { let current_facts: Box + 'a> = if predicates.is_empty() { Box::new(facts.iter()) @@ -212,6 +216,7 @@ impl<'a> CombineIt<'a> { predicates, expressions, all_facts: facts, + symbols, current_facts, current_it: None, } @@ -233,7 +238,7 @@ impl<'a> Iterator for CombineIt<'a> { //println!("predicates empty, will test variables: {:?}", variables); let mut valid = true; for e in self.expressions.iter() { - match e.evaluate(&variables) { + match e.evaluate(&variables, self.symbols) { Some(ID::Bool(true)) => {} _res => { //println!("expr returned {:?}", res); @@ -290,7 +295,7 @@ impl<'a> Iterator for CombineIt<'a> { //println!("will test with variables: {:?}", variables); let mut valid = true; for e in self.expressions.iter() { - match e.evaluate(&variables) { + match e.evaluate(&variables, self.symbols) { Some(ID::Bool(true)) => { //println!("expression returned true"); } @@ -317,6 +322,7 @@ impl<'a> Iterator for CombineIt<'a> { &self.predicates[1..], self.expressions, &self.all_facts, + &self.symbols, ))); } break; @@ -419,9 +425,9 @@ pub fn int(i: i64) -> ID { ID::Integer(i) } -pub fn string(s: &str) -> ID { +/*pub fn string(s: &str) -> ID { ID::Str(s.to_string()) -} +}*/ pub fn date(t: &SystemTime) -> ID { let dur = t.duration_since(UNIX_EPOCH).unwrap(); @@ -444,7 +450,6 @@ pub fn match_preds(rule_pred: &Predicate, fact_pred: &Predicate) -> bool { // the fact should not contain variables (_, ID::Variable(_)) => false, (ID::Variable(_), _) => true, - (ID::Symbol(i), ID::Symbol(ref j)) => i == j, (ID::Integer(i), ID::Integer(j)) => i == j, (ID::Str(i), ID::Str(j)) => i == j, (ID::Date(i), ID::Date(j)) => i == j, @@ -474,11 +479,15 @@ impl World { self.rules.push(rule); } - pub fn run(&mut self) -> Result<(), crate::error::RunLimit> { - self.run_with_limits(RunLimits::default()) + pub fn run(&mut self, symbols: &SymbolTable) -> Result<(), crate::error::RunLimit> { + self.run_with_limits(symbols, RunLimits::default()) } - pub fn run_with_limits(&mut self, limits: RunLimits) -> Result<(), crate::error::RunLimit> { + pub fn run_with_limits( + &mut self, + symbols: &SymbolTable, + limits: RunLimits, + ) -> Result<(), crate::error::RunLimit> { let start = Instant::now(); let time_limit = start + limits.max_time; let mut index = 0; @@ -487,7 +496,7 @@ impl World { let mut new_facts: Vec = Vec::new(); for rule in self.rules.iter() { - new_facts.extend(rule.apply(&self.facts)); + new_facts.extend(rule.apply(&self.facts, symbols)); //println!("new_facts after applying {:?}:\n{:#?}", rule, new_facts); } @@ -520,13 +529,11 @@ impl World { .iter() .filter(|f| { f.predicate.name == pred.name - && f.predicate - .ids - .iter() - .zip(&pred.ids) - .all(|(fid, pid)| match (fid, pid) { - (ID::Symbol(_), ID::Variable(_)) => true, - (ID::Symbol(i), ID::Symbol(ref j)) => i == j, + && f.predicate.ids.iter().zip(&pred.ids).all(|(fid, pid)| { + let res = match (fid, pid) { + //(ID::Symbol(_), ID::Variable(_)) => true, + //(ID::Symbol(i), ID::Symbol(ref j)) => i == j, + (_, ID::Variable(_)) => true, (ID::Integer(i), ID::Integer(ref j)) => i == j, (ID::Str(i), ID::Str(ref j)) => i == j, (ID::Date(i), ID::Date(ref j)) => i == j, @@ -534,27 +541,24 @@ impl World { (ID::Bool(i), ID::Bool(ref j)) => i == j, (ID::Set(i), ID::Set(ref j)) => i == j, _ => false, - }) + }; + res + }) }) .collect::>() } - pub fn query_rule(&self, rule: Rule) -> Vec { + pub fn query_rule(&self, rule: Rule, symbols: &SymbolTable) -> Vec { let mut new_facts: Vec = Vec::new(); - new_facts.extend(rule.apply(&self.facts)); + new_facts.extend(rule.apply(&self.facts, symbols)); new_facts } - pub fn query_match(&self, rule: Rule) -> bool { - rule.find_match(&self.facts) + pub fn query_match(&self, rule: Rule, symbols: &SymbolTable) -> bool { + rule.find_match(&self.facts, symbols) } } -pub fn sym(syms: &mut SymbolTable, name: &str) -> ID { - let id = syms.insert(name); - ID::Symbol(id) -} - pub struct RunLimits { pub max_facts: u32, pub max_iterations: u32, @@ -609,7 +613,7 @@ mod tests { println!("symbols: {:?}", syms); println!("testing r1: {}", syms.print_rule(&r1)); - let query_rule_result = w.query_rule(r1); + let query_rule_result = w.query_rule(r1, &syms); println!("grandparents query_rules: {:?}", query_rule_result); println!("current facts: {:?}", w.facts); @@ -631,7 +635,7 @@ mod tests { println!("adding r2: {}", syms.print_rule(&r2)); w.add_rule(r2); - w.run().unwrap(); + w.run(&syms).unwrap(); println!("parents:"); let res = w.query(pred( @@ -654,7 +658,7 @@ mod tests { )) ); w.add_fact(fact(parent, &[&c, &e])); - w.run().unwrap(); + w.run(&syms).unwrap(); let mut res = w.query(pred( grandparent, &[var(&mut syms, "grandparent"), var(&mut syms, "grandchild")], @@ -708,21 +712,24 @@ mod tests { w.add_fact(fact(t2, &[&int(1), &bbb, &int(0)])); w.add_fact(fact(t2, &[&int(2), &ccc, &int(1)])); - let res = w.query_rule(rule( - join, - &[var(&mut syms, "left"), var(&mut syms, "right")], - &[ - pred(t1, &[var(&mut syms, "id"), var(&mut syms, "left")]), - pred( - t2, - &[ - var(&mut syms, "t2_id"), - var(&mut syms, "right"), - var(&mut syms, "id"), - ], - ), - ], - )); + let res = w.query_rule( + rule( + join, + &[var(&mut syms, "left"), var(&mut syms, "right")], + &[ + pred(t1, &[var(&mut syms, "id"), var(&mut syms, "left")]), + pred( + t2, + &[ + var(&mut syms, "t2_id"), + var(&mut syms, "right"), + var(&mut syms, "id"), + ], + ), + ], + ), + &syms, + ); for fact in &res { println!("\t{}", syms.print_fact(fact)); } @@ -738,28 +745,31 @@ mod tests { assert_eq!(res2, compared); // test constraints - let res = w.query_rule(expressed_rule( - join, - &[var(&mut syms, "left"), var(&mut syms, "right")], - &[ - pred(t1, &[var(&mut syms, "id"), var(&mut syms, "left")]), - pred( - t2, - &[ - var(&mut syms, "t2_id"), - var(&mut syms, "right"), - var(&mut syms, "id"), - ], - ), - ], - &[Expression { - ops: vec![ - Op::Value(var(&mut syms, "id")), - Op::Value(ID::Integer(1)), - Op::Binary(Binary::LessThan), + let res = w.query_rule( + expressed_rule( + join, + &[var(&mut syms, "left"), var(&mut syms, "right")], + &[ + pred(t1, &[var(&mut syms, "id"), var(&mut syms, "left")]), + pred( + t2, + &[ + var(&mut syms, "t2_id"), + var(&mut syms, "right"), + var(&mut syms, "id"), + ], + ), ], - }], - )); + &[Expression { + ops: vec![ + Op::Value(var(&mut syms, "id")), + Op::Value(ID::Integer(1)), + Op::Binary(Binary::LessThan), + ], + }], + ), + &syms, + ); for fact in &res { println!("\t{}", syms.print_fact(fact)); } @@ -781,12 +791,17 @@ mod tests { let app_2 = syms.add("app_2"); let route = syms.insert("route"); let suff = syms.insert("route suffix"); - - w.add_fact(fact(route, &[&int(0), &app_0, &string("example.com")])); - w.add_fact(fact(route, &[&int(1), &app_1, &string("test.com")])); - w.add_fact(fact(route, &[&int(2), &app_2, &string("test.fr")])); - w.add_fact(fact(route, &[&int(3), &app_0, &string("www.example.com")])); - w.add_fact(fact(route, &[&int(4), &app_1, &string("mx.example.com")])); + let example = syms.add("example.com"); + let test_com = syms.add("test.com"); + let test_fr = syms.add("test.fr"); + let www_example = syms.add("www.example.com"); + let mx_example = syms.add("mx.example.com"); + + w.add_fact(fact(route, &[&int(0), &app_0, &example])); + w.add_fact(fact(route, &[&int(1), &app_1, &test_com])); + w.add_fact(fact(route, &[&int(2), &app_2, &test_fr])); + w.add_fact(fact(route, &[&int(3), &app_0, &www_example])); + w.add_fact(fact(route, &[&int(4), &app_1, &mx_example])); fn test_suffix( w: &World, @@ -795,25 +810,29 @@ mod tests { route: Symbol, suffix: &str, ) -> Vec { - w.query_rule(expressed_rule( - suff, - &[var(syms, "app_id"), var(syms, "domain_name")], - &[pred( - route, - &[ - var(syms, "route_id"), - var(syms, "app_id"), - var(syms, "domain_name"), - ], - )], - &[Expression { - ops: vec![ - Op::Value(var(syms, "domain_name")), - Op::Value(ID::Str(suffix.to_string())), - Op::Binary(Binary::Suffix), - ], - }], - )) + let id_suff = syms.add(suffix); + w.query_rule( + expressed_rule( + suff, + &[var(syms, "app_id"), var(syms, "domain_name")], + &[pred( + route, + &[ + var(syms, "route_id"), + var(syms, "app_id"), + var(syms, "domain_name"), + ], + )], + &[Expression { + ops: vec![ + Op::Value(var(syms, "domain_name")), + Op::Value(id_suff), + Op::Binary(Binary::Suffix), + ], + }], + ), + &syms, + ) } let res = test_suffix(&w, &mut syms, suff, route, ".fr"); @@ -822,7 +841,7 @@ mod tests { } let res2 = res.iter().cloned().collect::>(); - let compared = (vec![fact(suff, &[&app_2, &string("test.fr")])]) + let compared = (vec![fact(suff, &[&app_2, &test_fr])]) .drain(..) .collect::>(); assert_eq!(res2, compared); @@ -834,9 +853,9 @@ mod tests { let res2 = res.iter().cloned().collect::>(); let compared = (vec![ - fact(suff, &[&app_0, &string("example.com")]), - fact(suff, &[&app_0, &string("www.example.com")]), - fact(suff, &[&app_1, &string("mx.example.com")]), + fact(suff, &[&app_0, &example]), + fact(suff, &[&app_0, &www_example]), + fact(suff, &[&app_1, &mx_example]), ]) .drain(..) .collect::>(); @@ -889,7 +908,7 @@ mod tests { ); println!("testing r1: {}", syms.print_rule(&r1)); - let res = w.query_rule(r1); + let res = w.query_rule(r1, &syms); for fact in &res { println!("\t{}", syms.print_fact(fact)); } @@ -923,7 +942,7 @@ mod tests { ); println!("testing r2: {}", syms.print_rule(&r2)); - let res = w.query_rule(r2); + let res = w.query_rule(r2, &syms); for fact in &res { println!("\t{}", syms.print_fact(fact)); } @@ -946,119 +965,121 @@ mod tests { let int_set = syms.insert("int_set"); let symbol_set = syms.insert("symbol_set"); let string_set = syms.insert("string_set"); + let test = syms.add("test"); + let hello = syms.add("hello"); + let aaa = syms.add("zzz"); - w.add_fact(fact(x, &[&abc, &int(0), &string("test")])); - w.add_fact(fact(x, &[&def, &int(2), &string("hello")])); + w.add_fact(fact(x, &[&abc, &int(0), &test])); + w.add_fact(fact(x, &[&def, &int(2), &hello])); - let res = w.query_rule(expressed_rule( - int_set, - &[var(&mut syms, "sym"), var(&mut syms, "str")], - &[pred( - x, - &[ - var(&mut syms, "sym"), - var(&mut syms, "int"), - var(&mut syms, "str"), - ], - )], - &[Expression { - ops: vec![ - Op::Value(ID::Set( - [ID::Integer(0), ID::Integer(1)].iter().cloned().collect(), - )), - Op::Value(var(&mut syms, "int")), - Op::Binary(Binary::Contains), - ], - }], - )); + let res = w.query_rule( + expressed_rule( + int_set, + &[var(&mut syms, "sym"), var(&mut syms, "str")], + &[pred( + x, + &[ + var(&mut syms, "sym"), + var(&mut syms, "int"), + var(&mut syms, "str"), + ], + )], + &[Expression { + ops: vec![ + Op::Value(ID::Set( + [ID::Integer(0), ID::Integer(1)].iter().cloned().collect(), + )), + Op::Value(var(&mut syms, "int")), + Op::Binary(Binary::Contains), + ], + }], + ), + &syms, + ); for fact in &res { println!("\t{}", syms.print_fact(fact)); } let res2 = res.iter().cloned().collect::>(); - let compared = (vec![fact(int_set, &[&abc, &string("test")])]) + let compared = (vec![fact(int_set, &[&abc, &test])]) .drain(..) .collect::>(); assert_eq!(res2, compared); - let abc_sym_id = syms.insert("abc"); - let ghi_sym_id = syms.insert("ghi"); + let abc_sym_id = syms.add("abc"); + let ghi_sym_id = syms.add("ghi"); - let res = w.query_rule(expressed_rule( - symbol_set, - &[ - var(&mut syms, "symbol"), - var(&mut syms, "int"), - var(&mut syms, "str"), - ], - &[pred( - x, + let res = w.query_rule( + expressed_rule( + symbol_set, &[ var(&mut syms, "symbol"), var(&mut syms, "int"), var(&mut syms, "str"), ], - )], - &[Expression { - ops: vec![ - Op::Value(ID::Set( - [ID::Symbol(abc_sym_id), ID::Symbol(ghi_sym_id)] - .iter() - .cloned() - .collect(), - )), - Op::Value(var(&mut syms, "symbol")), - Op::Binary(Binary::Contains), - Op::Unary(Unary::Negate), - ], - }], - )); + &[pred( + x, + &[ + var(&mut syms, "symbol"), + var(&mut syms, "int"), + var(&mut syms, "str"), + ], + )], + &[Expression { + ops: vec![ + Op::Value(ID::Set([abc_sym_id, ghi_sym_id].iter().cloned().collect())), + Op::Value(var(&mut syms, "symbol")), + Op::Binary(Binary::Contains), + Op::Unary(Unary::Negate), + ], + }], + ), + &syms, + ); for fact in &res { println!("\t{}", syms.print_fact(fact)); } let res2 = res.iter().cloned().collect::>(); - let compared = (vec![fact(symbol_set, &[&def, &int(2), &string("hello")])]) + let compared = (vec![fact(symbol_set, &[&def, &int(2), &hello])]) .drain(..) .collect::>(); assert_eq!(res2, compared); - let res = w.query_rule(expressed_rule( - string_set, - &[ - var(&mut syms, "sym"), - var(&mut syms, "int"), - var(&mut syms, "str"), - ], - &[pred( - x, + let res = w.query_rule( + expressed_rule( + string_set, &[ var(&mut syms, "sym"), var(&mut syms, "int"), var(&mut syms, "str"), ], - )], - &[Expression { - ops: vec![ - Op::Value(ID::Set( - [ID::Str("test".to_string()), ID::Str("aaa".to_string())] - .iter() - .cloned() - .collect(), - )), - Op::Value(var(&mut syms, "str")), - Op::Binary(Binary::Contains), - ], - }], - )); + &[pred( + x, + &[ + var(&mut syms, "sym"), + var(&mut syms, "int"), + var(&mut syms, "str"), + ], + )], + &[Expression { + ops: vec![ + Op::Value(ID::Set([test.clone(), aaa].iter().cloned().collect())), + Op::Value(var(&mut syms, "str")), + Op::Binary(Binary::Contains), + ], + }], + ), + &syms, + ); for fact in &res { println!("\t{}", syms.print_fact(fact)); } let res2 = res.iter().cloned().collect::>(); - let compared = (vec![fact(string_set, &[&abc, &int(0), &string("test")])]) + let compared = (vec![fact(string_set, &[&abc, &int(0), &test])]) .drain(..) .collect::>(); assert_eq!(res2, compared); @@ -1087,7 +1108,7 @@ mod tests { w.add_fact(fact(right, &[&file2, &read])); w.add_fact(fact(right, &[&file1, &write])); - let res = w.query_rule(rule(check1, &[&file1], &[pred(resource, &[&file1])])); + let res = w.query_rule(rule(check1, &[&file1], &[pred(resource, &[&file1])]), &syms); for fact in &res { println!("\t{}", syms.print_fact(fact)); @@ -1095,15 +1116,18 @@ mod tests { assert!(res.is_empty()); - let res = w.query_rule(rule( - check2, - &[ID::Variable(0)], - &[ - pred(resource, &[&ID::Variable(0)]), - pred(operation, &[&read]), - pred(right, &[&ID::Variable(0), &read]), - ], - )); + let res = w.query_rule( + rule( + check2, + &[ID::Variable(0)], + &[ + pred(resource, &[&ID::Variable(0)]), + pred(operation, &[&read]), + pred(right, &[&ID::Variable(0), &read]), + ], + ), + &syms, + ); for fact in &res { println!("\t{}", syms.print_fact(fact)); @@ -1144,7 +1168,7 @@ mod tests { println!("world:\n{}\n", syms.print_world(&w)); println!("\ntesting r1: {}\n", syms.print_rule(&r1)); - let res = w.query_rule(r1); + let res = w.query_rule(r1, &syms); for fact in &res { println!("\t{}", syms.print_fact(fact)); } @@ -1181,7 +1205,7 @@ mod tests { ); println!("world:\n{}\n", syms.print_world(&w)); println!("\ntesting r1: {}\n", syms.print_rule(&r1)); - let res = w.query_rule(r1); + let res = w.query_rule(r1, &syms); println!("generated facts:"); for fact in &res { @@ -1197,7 +1221,7 @@ mod tests { let r2 = rule(check, &[&read], &[pred(operation, &[&read])]); println!("world:\n{}\n", syms.print_world(&w)); println!("\ntesting r2: {}\n", syms.print_rule(&r2)); - let res = w.query_rule(r2); + let res = w.query_rule(r2, &syms); println!("generated facts:"); for fact in &res { diff --git a/src/datalog/symbol.rs b/src/datalog/symbol.rs index 32c5fab4..ac99fa8f 100644 --- a/src/datalog/symbol.rs +++ b/src/datalog/symbol.rs @@ -26,7 +26,7 @@ impl SymbolTable { pub fn add(&mut self, s: &str) -> ID { let id = self.insert(s); - ID::Symbol(id) + ID::Str(id) } pub fn get(&self, s: &str) -> Option { @@ -36,6 +36,10 @@ impl SymbolTable { .map(|i| i as u64) } + pub fn get_s(&self, s: Symbol) -> Option<&str> { + self.symbols.get(s as usize).map(|s| s.as_str()) + } + pub fn print_symbol(&self, s: Symbol) -> String { self.symbols .get(s as usize) @@ -61,8 +65,7 @@ impl SymbolTable { match id { ID::Variable(i) => format!("${}", self.print_symbol(*i as u64)), ID::Integer(i) => i.to_string(), - ID::Str(s) => format!("\"{}\"", s), - ID::Symbol(index) => format!("#{}", self.print_symbol(*index as u64)), + ID::Str(index) => format!("\"{}\"", self.print_symbol(*index as u64)), ID::Date(d) => { let date = DateTime::::from_utc(NaiveDateTime::from_timestamp(*d as i64, 0), Utc); diff --git a/src/format/convert.rs b/src/format/convert.rs index 04127329..7035b3e9 100644 --- a/src/format/convert.rs +++ b/src/format/convert.rs @@ -287,9 +287,6 @@ pub mod v2 { use schema::idv2::Content; match input { - ID::Symbol(s) => schema::Idv2 { - content: Some(Content::Symbol(*s)), - }, ID::Variable(v) => schema::Idv2 { content: Some(Content::Variable(*v)), }, @@ -297,7 +294,7 @@ pub mod v2 { content: Some(Content::Integer(*i)), }, ID::Str(s) => schema::Idv2 { - content: Some(Content::String(s.clone())), + content: Some(Content::String(*s)), }, ID::Date(d) => schema::Idv2 { content: Some(Content::Date(*d)), @@ -323,10 +320,9 @@ pub mod v2 { None => Err(error::Format::DeserializationError( "deserialization error: ID content enum is empty".to_string(), )), - Some(Content::Symbol(i)) => Ok(ID::Symbol(*i)), Some(Content::Variable(i)) => Ok(ID::Variable(*i)), Some(Content::Integer(i)) => Ok(ID::Integer(*i)), - Some(Content::String(s)) => Ok(ID::Str(s.clone())), + Some(Content::String(s)) => Ok(ID::Str(*s)), Some(Content::Date(i)) => Ok(ID::Date(*i)), Some(Content::Bytes(s)) => Ok(ID::Bytes(s.clone())), Some(Content::Bool(b)) => Ok(ID::Bool(*b)), @@ -336,7 +332,6 @@ pub mod v2 { for i in s.set.iter() { let index = match i.content { - Some(Content::Symbol(_)) => 0, Some(Content::Variable(_)) => { return Err(error::Format::DeserializationError( "deserialization error: sets cannot contain variables".to_string(), diff --git a/src/format/schema.proto b/src/format/schema.proto index 08bb7012..3a368dca 100644 --- a/src/format/schema.proto +++ b/src/format/schema.proto @@ -52,14 +52,13 @@ message PredicateV2 { message IDV2 { oneof Content { - uint64 symbol = 1; - uint32 variable = 2; - int64 integer = 3; - string string = 4; - uint64 date = 5; - bytes bytes = 6; - bool bool = 7; - IDSet set = 8; + uint32 variable = 1; + int64 integer = 2; + uint64 string = 3; + uint64 date = 4; + bytes bytes = 5; + bool bool = 6; + IDSet set = 7; } } @@ -74,8 +73,7 @@ message ConstraintV2 { IntConstraintV2 int = 2; StringConstraintV2 string = 3; DateConstraintV2 date = 4; - SymbolConstraintV2 symbol = 5; - BytesConstraintV2 bytes = 6; + BytesConstraintV2 bytes = 5; } } @@ -107,7 +105,7 @@ message StringConstraintV2 { } message StringSet { - repeated string set = 1; + repeated uint64 set = 1 [packed=true]; } message DateConstraintV2 { @@ -117,17 +115,6 @@ message DateConstraintV2 { } } -message SymbolConstraintV2 { - oneof Constraint { - SymbolSet in_set = 1; - SymbolSet not_in_set = 2; - } -} - -message SymbolSet { - repeated uint64 set = 1 [packed=true]; -} - message BytesConstraintV2 { oneof Constraint { bytes equal = 1; diff --git a/src/format/schema.rs b/src/format/schema.rs index 7faa71e8..1a4da53c 100644 --- a/src/format/schema.rs +++ b/src/format/schema.rs @@ -76,28 +76,26 @@ pub struct PredicateV2 { } #[derive(Clone, PartialEq, ::prost::Message)] pub struct Idv2 { - #[prost(oneof="idv2::Content", tags="1, 2, 3, 4, 5, 6, 7, 8")] + #[prost(oneof="idv2::Content", tags="1, 2, 3, 4, 5, 6, 7")] pub content: ::core::option::Option, } /// Nested message and enum types in `IDV2`. pub mod idv2 { #[derive(Clone, PartialEq, ::prost::Oneof)] pub enum Content { - #[prost(uint64, tag="1")] - Symbol(u64), - #[prost(uint32, tag="2")] + #[prost(uint32, tag="1")] Variable(u32), - #[prost(int64, tag="3")] + #[prost(int64, tag="2")] Integer(i64), - #[prost(string, tag="4")] - String(::prost::alloc::string::String), - #[prost(uint64, tag="5")] + #[prost(uint64, tag="3")] + String(u64), + #[prost(uint64, tag="4")] Date(u64), - #[prost(bytes, tag="6")] + #[prost(bytes, tag="5")] Bytes(::prost::alloc::vec::Vec), - #[prost(bool, tag="7")] + #[prost(bool, tag="6")] Bool(bool), - #[prost(message, tag="8")] + #[prost(message, tag="7")] Set(super::IdSet), } } @@ -110,7 +108,7 @@ pub struct IdSet { pub struct ConstraintV2 { #[prost(uint32, required, tag="1")] pub id: u32, - #[prost(oneof="constraint_v2::Constraint", tags="2, 3, 4, 5, 6")] + #[prost(oneof="constraint_v2::Constraint", tags="2, 3, 4, 5")] pub constraint: ::core::option::Option, } /// Nested message and enum types in `ConstraintV2`. @@ -124,8 +122,6 @@ pub mod constraint_v2 { #[prost(message, tag="4")] Date(super::DateConstraintV2), #[prost(message, tag="5")] - Symbol(super::SymbolConstraintV2), - #[prost(message, tag="6")] Bytes(super::BytesConstraintV2), } } @@ -184,8 +180,8 @@ pub mod string_constraint_v2 { } #[derive(Clone, PartialEq, ::prost::Message)] pub struct StringSet { - #[prost(string, repeated, tag="1")] - pub set: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, + #[prost(uint64, repeated, tag="1")] + pub set: ::prost::alloc::vec::Vec, } #[derive(Clone, PartialEq, ::prost::Message)] pub struct DateConstraintV2 { @@ -203,26 +199,6 @@ pub mod date_constraint_v2 { } } #[derive(Clone, PartialEq, ::prost::Message)] -pub struct SymbolConstraintV2 { - #[prost(oneof="symbol_constraint_v2::Constraint", tags="1, 2")] - pub constraint: ::core::option::Option, -} -/// Nested message and enum types in `SymbolConstraintV2`. -pub mod symbol_constraint_v2 { - #[derive(Clone, PartialEq, ::prost::Oneof)] - pub enum Constraint { - #[prost(message, tag="1")] - InSet(super::SymbolSet), - #[prost(message, tag="2")] - NotInSet(super::SymbolSet), - } -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct SymbolSet { - #[prost(uint64, repeated, tag="1")] - pub set: ::prost::alloc::vec::Vec, -} -#[derive(Clone, PartialEq, ::prost::Message)] pub struct BytesConstraintV2 { #[prost(oneof="bytes_constraint_v2::Constraint", tags="1, 2, 3")] pub constraint: ::core::option::Option, diff --git a/src/lib.rs b/src/lib.rs index da6d3855..93e507b0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,8 +55,8 @@ //! biscuit.to_vec()? //! }; //! -//! // this token is only 260 bytes, holding the authority data and the signature -//! assert_eq!(token1.len(), 260); +//! // this token is only 254 bytes, holding the authority data and the signature +//! assert_eq!(token1.len(), 254); //! //! // now let's add some restrictions to this token //! // we want to limit access to `/a/file1.txt` and to read operations @@ -93,8 +93,8 @@ //! biscuit.to_vec()? //! }; //! -//! // this new token fits in 414 bytes -//! assert_eq!(token2.len(), 414); +//! // this new token fits in 396 bytes +//! assert_eq!(token2.len(), 396); //! //! /************** VERIFICATION ****************/ //! diff --git a/src/parser.rs b/src/parser.rs index f22438e2..c7f02897 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -663,7 +663,6 @@ fn set(i: &str) -> IResult<&str, builder::Term, Error> { let mut kind: Option = None; for term in list.drain(..) { let index = match term { - builder::Term::Symbol(_) => 0, builder::Term::Variable(_) => panic!("variables are not permitted in sets"), builder::Term::Integer(_) => 2, builder::Term::Str(_) => 3, @@ -1061,7 +1060,7 @@ mod tests { #[test] fn constraint() { - use builder::{date, int, set, string, symbol, var, Binary, Op, Unary}; + use builder::{date, int, set, string, var, Binary, Op, Unary}; use std::collections::BTreeSet; use std::time::{Duration, SystemTime}; @@ -1256,12 +1255,12 @@ mod tests { )) ); - let h = [symbol("abc"), symbol("def")] + let h = [string("abc"), string("def")] .iter() .cloned() .collect::>(); assert_eq!( - super::expr("[#abc, #def].contains($0)").map(|(i, o)| (i, o.opcodes())), + super::expr("[\"abc\", \"def\"].contains($0)").map(|(i, o)| (i, o.opcodes())), Ok(( "", vec![ @@ -1273,7 +1272,7 @@ mod tests { ); assert_eq!( - super::expr("![#abc, #def].contains($0)").map(|(i, o)| (i, o.opcodes())), + super::expr("![\"abc\", \"def\"].contains($0)").map(|(i, o)| (i, o.opcodes())), Ok(( "", vec![ @@ -1614,7 +1613,7 @@ mod tests { let printed = e.print(&syms).unwrap(); println!("print: {}", e.print(&syms).unwrap()); let h = HashMap::new(); - let result = e.evaluate(&h).unwrap(); + let result = e.evaluate(&h, &syms).unwrap(); println!("evaluates to: {:?}", result); assert_eq!( @@ -1641,7 +1640,7 @@ mod tests { let printed = e.print(&syms).unwrap(); println!("print: {}", e.print(&syms).unwrap()); let h = HashMap::new(); - let result = e.evaluate(&h).unwrap(); + let result = e.evaluate(&h, &syms).unwrap(); println!("evaluates to: {:?}", result); assert_eq!( diff --git a/src/token/builder.rs b/src/token/builder.rs index 7c2a87ee..95d9fc52 100644 --- a/src/token/builder.rs +++ b/src/token/builder.rs @@ -3,8 +3,8 @@ use super::{Biscuit, Block}; use crate::crypto::KeyPair; use crate::datalog::{self, SymbolTable, ID}; use crate::error; -use rand_core::{CryptoRng, RngCore}; use chrono::{DateTime, NaiveDateTime, Utc}; +use rand_core::{CryptoRng, RngCore}; use std::{ collections::BTreeSet, convert::{TryFrom, TryInto}, @@ -269,7 +269,6 @@ impl<'a> BiscuitBuilder<'a> { #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Term { - Symbol(String), Variable(String), Integer(i64), Str(String), @@ -282,10 +281,9 @@ pub enum Term { impl Term { pub fn convert(&self, symbols: &mut SymbolTable) -> ID { match self { - Term::Symbol(s) => ID::Symbol(symbols.insert(s)), Term::Variable(s) => ID::Variable(symbols.insert(s) as u32), Term::Integer(i) => ID::Integer(*i), - Term::Str(s) => ID::Str(s.clone()), + Term::Str(s) => ID::Str(symbols.insert(s)), Term::Date(d) => ID::Date(*d), Term::Bytes(s) => ID::Bytes(s.clone()), Term::Bool(b) => ID::Bool(*b), @@ -295,10 +293,9 @@ impl Term { pub fn convert_from(f: &datalog::ID, symbols: &SymbolTable) -> Self { match f { - ID::Symbol(s) => Term::Symbol(symbols.print_symbol(*s)), ID::Variable(s) => Term::Variable(symbols.print_symbol(*s as u64)), ID::Integer(i) => Term::Integer(*i), - ID::Str(s) => Term::Str(s.clone()), + ID::Str(s) => Term::Str(symbols.print_symbol(*s)), ID::Date(d) => Term::Date(*d), ID::Bytes(s) => Term::Bytes(s.clone()), ID::Bool(b) => Term::Bool(*b), @@ -310,7 +307,6 @@ impl Term { impl From<&Term> for Term { fn from(i: &Term) -> Self { match i { - Term::Symbol(ref s) => Term::Symbol(s.clone()), Term::Variable(ref v) => Term::Variable(v.clone()), Term::Integer(ref i) => Term::Integer(*i), Term::Str(ref s) => Term::Str(s.clone()), @@ -334,11 +330,10 @@ impl fmt::Display for Term { Term::Variable(i) => write!(f, "${}", i), Term::Integer(i) => write!(f, "{}", i), Term::Str(s) => write!(f, "\"{}\"", s), - Term::Symbol(s) => write!(f, "#{}", s), Term::Date(d) => { let date = DateTime::::from_utc(NaiveDateTime::from_timestamp(*d as i64, 0), Utc); - write!(f, "{}", date.to_rfc3339()) + write!(f, "{}", date.to_rfc3339()) } Term::Bytes(s) => write!(f, "hex:{}", hex::encode(s)), Term::Bool(b) => { @@ -782,18 +777,9 @@ pub fn string(s: &str) -> Term { Term::Str(s.to_string()) } -/// creates a symbol -/// -/// once the block is generated, this symbol will be added to the symbol table if needed +/// creates a string pub fn s(s: &str) -> Term { - Term::Symbol(s.to_string()) -} - -/// creates a symbol -/// -/// once the block is generated, this symbol will be added to the symbol table if needed -pub fn symbol(s: &str) -> Term { - Term::Symbol(s.to_string()) + Term::Str(s.to_string()) } /// creates a date @@ -860,7 +846,7 @@ impl TryFrom for String { fn try_from(value: Term) -> Result { println!("converting string from {:?}", value); match value { - Term::Symbol(s) | Term::Str(s) => Ok(s), + Term::Str(s) => Ok(s), _ => Err(error::Token::ConversionError(format!( "expected string or symbol, got {:?}", value diff --git a/src/token/mod.rs b/src/token/mod.rs index 7708aa31..a863157d 100644 --- a/src/token/mod.rs +++ b/src/token/mod.rs @@ -51,10 +51,10 @@ pub fn default_symbol_table() -> SymbolTable { /// // like access rights /// // data from the authority block cannot be created in any other block /// let mut builder = Biscuit::builder(&root); -/// builder.add_authority_fact(fact("right", &[s("authority"), string("/a/file1.txt"), s("read")])); +/// builder.add_authority_fact(fact("right", &[string("/a/file1.txt"), s("read")])); /// /// // facts and rules can also be parsed from a string -/// builder.add_authority_fact("right(#authority, \"/a/file1.txt\", #read)").expect("parse error"); +/// builder.add_authority_fact("right(\"/a/file1.txt\", \"read\")").expect("parse error"); /// /// let token1 = builder.build().unwrap(); /// @@ -560,9 +560,15 @@ mod tests { let serialized1 = { let mut builder = Biscuit::builder(&root); - builder.add_authority_fact("right(#file1, #read)").unwrap(); - builder.add_authority_fact("right(#file2, #read)").unwrap(); - builder.add_authority_fact("right(#file1, #write)").unwrap(); + builder + .add_authority_fact("right(\"file1\", \"read\")") + .unwrap(); + builder + .add_authority_fact("right(\"file2\", \"read\")") + .unwrap(); + builder + .add_authority_fact("right(\"file1\", \"write\")") + .unwrap(); let biscuit1 = builder.build_with_rng(&mut rng).unwrap(); @@ -701,8 +707,8 @@ mod tests { println!("res2: {:#?}", res); assert_eq!(res, Err(Token::FailedLogic(Logic::FailedChecks(vec![ - FailedCheck::Block(FailedBlockCheck { block_id: 1, check_id: 0, rule: String::from("check if resource($resource), operation(#read), right($resource, #read)") }), - FailedCheck::Block(FailedBlockCheck { block_id: 2, check_id: 0, rule: String::from("check if resource(#file1)") }) + FailedCheck::Block(FailedBlockCheck { block_id: 1, check_id: 0, rule: String::from("check if resource($resource), operation(\"read\"), right($resource, \"read\")") }), + FailedCheck::Block(FailedBlockCheck { block_id: 2, check_id: 0, rule: String::from("check if resource(\"file1\")") }) ])))); } } @@ -778,7 +784,7 @@ mod tests { assert_eq!(res, Err(Token::FailedLogic(Logic::FailedChecks(vec![ FailedCheck::Block(FailedBlockCheck { block_id: 1, check_id: 0, rule: String::from("check if resource($resource), $resource.starts_with(\"/folder1/\")") }), - FailedCheck::Block(FailedBlockCheck { block_id: 1, check_id: 1, rule: String::from("check if resource($resource_name), operation(#read), right($resource_name, #read)") }), + FailedCheck::Block(FailedBlockCheck { block_id: 1, check_id: 1, rule: String::from("check if resource($resource_name), operation(\"read\"), right($resource_name, \"read\")") }), ])))); } } @@ -935,7 +941,7 @@ mod tests { Err(Token::FailedLogic(Logic::FailedChecks(vec![ FailedCheck::Verifier(FailedVerifierCheck { check_id: 0, - rule: String::from("check if right(\"file2\", #write)") + rule: String::from("check if right(\"file2\", \"write\")") }), ]))) ); @@ -1050,7 +1056,7 @@ mod tests { FailedCheck::Block(FailedBlockCheck { block_id: 0, check_id: 0, - rule: String::from("check if resource(#hello)"), + rule: String::from("check if resource(\"hello\")"), }), ]))) ); @@ -1146,16 +1152,16 @@ mod tests { let mut builder = Biscuit::builder(&root); builder - .add_authority_fact("right(\"/folder1/file1\", #read)") + .add_authority_fact("right(\"/folder1/file1\", \"read\")") .unwrap(); builder - .add_authority_fact("right(\"/folder1/file1\", #write)") + .add_authority_fact("right(\"/folder1/file1\", \"write\")") .unwrap(); builder - .add_authority_fact("right(\"/folder2/file1\", #read)") + .add_authority_fact("right(\"/folder2/file1\", \"read\")") .unwrap(); builder - .add_authority_check("check if operation(#read)") + .add_authority_check("check if operation(\"read\")") .unwrap(); let biscuit1 = builder.build_with_rng(&mut rng).unwrap(); @@ -1175,9 +1181,9 @@ mod tests { // new check: can only have read access1 let mut block2 = biscuit1_deser.create_block(); - // Bypass `check if operation(#read)` from authority block + // Bypass `check if operation("read")` from authority block block2 - .add_rule("operation(#read) <- operation($any)") + .add_rule("operation(\"read\") <- operation($any)") .unwrap(); // Bypass `check if resource($file), $file.starts_with("/folder1/")` from block #1 diff --git a/src/token/verifier.rs b/src/token/verifier.rs index a19a5485..ce5199a0 100644 --- a/src/token/verifier.rs +++ b/src/token/verifier.rs @@ -163,9 +163,11 @@ impl<'t> Verifier<'t> { let rule = rule.try_into().map_err(|_| error::Token::ParseError)?; self.world - .run_with_limits(limits.into()) + .run_with_limits(&self.symbols, limits.into()) .map_err(error::Token::RunLimit)?; - let mut res = self.world.query_rule(rule.convert(&mut self.symbols)); + let mut res = self + .world + .query_rule(rule.convert(&mut self.symbols), &self.symbols); res.drain(..) .map(|f| Fact::convert_from(&f, &self.symbols)) @@ -284,7 +286,7 @@ impl<'t> Verifier<'t> { //FIXME: the verifier should be generated with run limits // that are "consumed" after each use self.world - .run_with_limits(RunLimits::default()) + .run_with_limits(&self.symbols, RunLimits::default()) .map_err(error::Token::RunLimit)?; self.world.rules.clear(); @@ -293,7 +295,9 @@ impl<'t> Verifier<'t> { let mut successful = false; for query in check.queries.iter() { - let res = self.world.query_match(query.convert(&mut self.symbols)); + let res = self + .world + .query_match(query.convert(&mut self.symbols), &self.symbols); let now = Instant::now(); if now >= time_limit { @@ -321,7 +325,7 @@ impl<'t> Verifier<'t> { let check = c.convert(&mut self.symbols); for query in check.queries.iter() { - let res = self.world.query_match(query.clone()); + let res = self.world.query_match(query.clone(), &self.symbols); let now = Instant::now(); if now >= time_limit { @@ -345,7 +349,9 @@ impl<'t> Verifier<'t> { for (i, policy) in self.policies.iter().enumerate() { for query in policy.queries.iter() { - let res = self.world.query_match(query.convert(&mut self.symbols)); + let res = self + .world + .query_match(query.convert(&mut self.symbols), &self.symbols); let now = Instant::now(); if now >= time_limit { @@ -384,7 +390,7 @@ impl<'t> Verifier<'t> { } self.world - .run_with_limits(RunLimits::default()) + .run_with_limits(&self.symbols, RunLimits::default()) .map_err(error::Token::RunLimit)?; self.world.rules.clear(); @@ -394,7 +400,7 @@ impl<'t> Verifier<'t> { let check = c.convert(&mut self.symbols); for query in check.queries.iter() { - let res = self.world.query_match(query.clone()); + let res = self.world.query_match(query.clone(), &self.symbols); let now = Instant::now(); if now >= time_limit {