Skip to content

Commit 98bde7b

Browse files
committed
primitives - eval - Div + test and fix Function::If
1 parent 5b6fd97 commit 98bde7b

File tree

1 file changed

+87
-24
lines changed

1 file changed

+87
-24
lines changed

primitives/src/targeting/eval.rs

Lines changed: 87 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::BigNum;
22
use serde::{Deserialize, Serialize};
33
use serde_json::{value::Value as SerdeValue, Number};
4-
use std::{convert::TryFrom, fmt, str::FromStr};
4+
use std::{convert::TryFrom, fmt, ops::Div, str::FromStr};
55

66
pub type Map = serde_json::value::Map<String, SerdeValue>;
77

@@ -77,6 +77,8 @@ impl TryFrom<SerdeValue> for Value {
7777
#[serde(rename_all = "camelCase")]
7878
// TODO: https://github.com/AdExNetwork/adex-validator-stack-rust/issues/296
7979
pub enum Function {
80+
/// Math `div`
81+
Div(Box<Rule>, Box<Rule>),
8082
If(Box<Rule>, Box<Rule>),
8183
And(Box<Rule>, Box<Rule>),
8284
Intersects(Box<Rule>, Box<Rule>),
@@ -98,8 +100,8 @@ impl From<Value> for Rule {
98100
}
99101

100102
impl Function {
101-
pub fn new_if(lhs: impl Into<Rule>, rhs: impl Into<Rule>) -> Self {
102-
Self::If(Box::new(lhs.into()), Box::new(rhs.into()))
103+
pub fn new_if(condition: impl Into<Rule>, then: impl Into<Rule>) -> Self {
104+
Self::If(Box::new(condition.into()), Box::new(then.into()))
103105
}
104106

105107
pub fn new_and(lhs: impl Into<Rule>, rhs: impl Into<Rule>) -> Self {
@@ -129,6 +131,24 @@ impl Value {
129131
_ => Err(Error::TypeError),
130132
}
131133
}
134+
135+
pub fn try_bignum(self) -> Result<BigNum, Error> {
136+
BigNum::try_from(self)
137+
}
138+
}
139+
140+
impl TryFrom<Value> for BigNum {
141+
type Error = Error;
142+
fn try_from(value: Value) -> Result<Self, Self::Error> {
143+
match value {
144+
Value::String(string) => BigNum::from_str(&string).map_err(|_| Error::TypeError),
145+
Value::BigNum(big_num) => Ok(big_num),
146+
Value::Number(number) => {
147+
BigNum::from_str(&number.to_string()).map_err(|_| Error::TypeError)
148+
}
149+
_ => Err(Error::TypeError),
150+
}
151+
}
132152
}
133153

134154
/// Evaluates a Rule to be applied and has 3 outcomes:
@@ -149,16 +169,53 @@ fn eval(input: &Input, output: &mut Output, rule: &Rule) -> Result<Option<Value>
149169

150170
// basic operators
151171
let value = match function {
172+
Function::Div(first_rule, second_rule) => {
173+
let value = match first_rule.eval(input, output)?.ok_or(Error::TypeError)? {
174+
Value::Number(first_number) => {
175+
match second_rule.eval(input, output)?.ok_or(Error::TypeError)? {
176+
Value::Number(second_number) => {
177+
if let Some(num) = first_number.as_f64() {
178+
let divided =
179+
num.div(second_number.as_f64().ok_or(Error::TypeError)?);
180+
181+
Value::Number(Number::from_f64(divided).ok_or(Error::TypeError)?)
182+
} else if let Some(num) = first_number.as_i64() {
183+
let rhs = second_number.as_i64().ok_or(Error::TypeError)?;
184+
let divided = num.checked_div(rhs).ok_or(Error::TypeError)?;
185+
186+
Value::Number(divided.into())
187+
} else if let Some(num) = first_number.as_u64() {
188+
let rhs = second_number.as_u64().ok_or(Error::TypeError)?;
189+
let divided = num.checked_div(rhs).ok_or(Error::TypeError)?;
190+
191+
Value::Number(divided.into())
192+
} else {
193+
return Err(Error::TypeError);
194+
}
195+
}
196+
_ => return Err(Error::TypeError),
197+
}
198+
}
199+
Value::BigNum(first_bignum) => {
200+
let second_bignum = second_rule
201+
.eval(input, output)?
202+
.ok_or(Error::TypeError)?
203+
.try_bignum()?;
204+
205+
Value::BigNum(first_bignum.div(second_bignum))
206+
}
207+
_ => return Err(Error::TypeError),
208+
};
209+
210+
Some(value)
211+
}
152212
Function::If(first_rule, second_rule) => {
153213
let eval_if = eval(input, output, first_rule)?
154214
.ok_or(Error::TypeError)?
155215
.try_bool()?;
156216

157217
if eval_if {
158-
let bool = eval(input, output, second_rule)?
159-
.ok_or(Error::TypeError)?
160-
.try_bool()?;
161-
Some(Value::Bool(bool))
218+
eval(input, output, second_rule)?
162219
} else {
163220
None
164221
}
@@ -185,24 +242,9 @@ fn eval(input: &Input, output: &mut Output, rule: &Rule) -> Result<Option<Value>
185242
}
186243
Function::Get(key) => Some(input.try_get(key)?),
187244
Function::Bn(value) => {
188-
let big_num = match value {
189-
Value::String(string) => {
190-
let big_num =
191-
BigNum::from_str(string.as_str()).map_err(|_| Error::TypeError)?;
192-
193-
Value::BigNum(big_num)
194-
}
195-
Value::BigNum(big_num) => Value::BigNum(big_num.clone()),
196-
Value::Number(number) => {
197-
let big_num =
198-
BigNum::from_str(&number.to_string()).map_err(|_| Error::TypeError)?;
245+
let big_num = value.clone().try_bignum()?;
199246

200-
Value::BigNum(big_num)
201-
}
202-
_ => return Err(Error::TypeError),
203-
};
204-
205-
Some(big_num)
247+
Some(Value::BigNum(big_num))
206248
}
207249
};
208250

@@ -293,4 +335,25 @@ mod test {
293335
result.expect("Sould return Non-NULL result!")
294336
);
295337
}
338+
339+
#[test]
340+
fn test_if_eval() {
341+
let input = Input::default();
342+
let mut output = Output {
343+
show: true,
344+
boost: 1.0,
345+
price: Default::default(),
346+
};
347+
348+
let then = Value::String("yes".to_string());
349+
350+
let rule = Rule::Function(Function::new_if(Value::Bool(true), then.clone()));
351+
352+
assert_eq!(Ok(Some(then.clone())), rule.eval(&input, &mut output));
353+
354+
let rule = Rule::Function(Function::new_if(Value::Bool(false), then));
355+
356+
assert_eq!(Ok(None), rule.eval(&input, &mut output));
357+
358+
}
296359
}

0 commit comments

Comments
 (0)