Skip to content

Commit 1f1953f

Browse files
committed
Partially implement targeting::eval()
1 parent 74618d4 commit 1f1953f

File tree

3 files changed

+123
-15
lines changed

3 files changed

+123
-15
lines changed

Cargo.lock

Lines changed: 15 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

primitives/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ pub mod event_submission;
1414
pub mod market;
1515
pub mod merkle_tree;
1616
pub mod sentry;
17+
pub mod targeting;
1718
pub mod targeting_tag;
1819
pub mod util {
1920
pub mod tests {

primitives/src/targeting.rs

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
use crate::BigNum;
2+
use serde_json::{
3+
value::{Map as SerdeMap, Value as SerdeValue},
4+
Number,
5+
};
6+
use std::convert::TryFrom;
7+
8+
pub type Map = SerdeMap<String, SerdeValue>;
9+
pub type Rule = SerdeValue;
10+
11+
pub enum Error {
12+
TypeError,
13+
UnknownVariable,
14+
}
15+
16+
#[derive(Debug, Clone, PartialEq, Eq)]
17+
pub enum EvalValue {
18+
Null,
19+
Bool(bool),
20+
Number(Number),
21+
String(String),
22+
Array(Vec<EvalValue>),
23+
BigNum(BigNum),
24+
}
25+
26+
impl TryFrom<SerdeValue> for EvalValue {
27+
type Error = Error;
28+
29+
fn try_from(serde_value: SerdeValue) -> Result<Self, Self::Error> {
30+
match serde_value {
31+
SerdeValue::Null => Ok(Self::Null),
32+
SerdeValue::Bool(bool) => Ok(Self::Bool(bool)),
33+
SerdeValue::Number(number) => Ok(Self::Number(number)),
34+
SerdeValue::String(string) => Ok(Self::String(string)),
35+
SerdeValue::Array(serde_array) => {
36+
let array = serde_array
37+
.into_iter()
38+
.map(EvalValue::try_from)
39+
.collect::<Result<_, _>>()?;
40+
Ok(Self::Array(array))
41+
}
42+
SerdeValue::Object(_) => Err(Error::TypeError),
43+
}
44+
}
45+
}
46+
47+
impl EvalValue {
48+
pub fn try_bool(&self) -> Result<bool, Error> {
49+
match *self {
50+
Self::Bool(b) => Ok(b),
51+
_ => Err(Error::TypeError),
52+
}
53+
}
54+
55+
pub fn try_array(&self) -> Result<Vec<EvalValue>, Error> {
56+
match *self {
57+
Self::Array(ref array) => Ok(array.to_vec()),
58+
_ => Err(Error::TypeError),
59+
}
60+
}
61+
}
62+
63+
/// Evaluates a Rule to be applied and has 3 outcomes:
64+
/// - Does nothing
65+
/// Rules returned directly:
66+
/// - Bool
67+
/// - Number
68+
/// - String
69+
/// - Array
70+
/// - Mutates output
71+
/// - Throws an error
72+
// TODO: Move to own module!
73+
pub fn eval(input: &Map, output: &mut Map, rule: &Rule) -> Result<EvalValue, Error> {
74+
let rule = match rule {
75+
Rule::Null => return Err(Error::TypeError),
76+
Rule::Object(map) => map,
77+
value => return EvalValue::try_from(value.to_owned()),
78+
};
79+
80+
// basic operators
81+
if let Some(SerdeValue::Array(array)) = rule.get("if") {
82+
let (first_rule, second_rule) = match array.get(0..=1) {
83+
Some(&[ref first_rule, ref second_rule]) => (first_rule, second_rule),
84+
_ => return Err(Error::TypeError),
85+
};
86+
87+
let eval_if = eval(input, output, first_rule)?.try_bool()?;
88+
89+
if eval_if {
90+
let bool = eval(input, output, second_rule)?.try_bool()?;
91+
return Ok(EvalValue::Bool(bool));
92+
}
93+
} else if let Some(SerdeValue::Array(array)) = rule.get("intersects") {
94+
// lists
95+
let (first_rule, second_rule) = match array.get(0..=1) {
96+
Some(&[ref first_rule, ref second_rule]) => (first_rule, second_rule),
97+
_ => return Err(Error::TypeError),
98+
};
99+
100+
let a = eval(input, output, first_rule)?.try_array()?;
101+
let b = eval(input, output, second_rule)?.try_array()?;
102+
103+
return Ok(EvalValue::Bool(a.iter().any(|x| b.contains(x))));
104+
}
105+
106+
Ok(EvalValue::Null)
107+
}

0 commit comments

Comments
 (0)