1
1
use crate :: BigNum ;
2
2
use serde:: { Deserialize , Serialize } ;
3
3
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 } ;
5
5
6
6
pub type Map = serde_json:: value:: Map < String , SerdeValue > ;
7
7
@@ -77,6 +77,8 @@ impl TryFrom<SerdeValue> for Value {
77
77
#[ serde( rename_all = "camelCase" ) ]
78
78
// TODO: https://github.com/AdExNetwork/adex-validator-stack-rust/issues/296
79
79
pub enum Function {
80
+ /// Math `div`
81
+ Div ( Box < Rule > , Box < Rule > ) ,
80
82
If ( Box < Rule > , Box < Rule > ) ,
81
83
And ( Box < Rule > , Box < Rule > ) ,
82
84
Intersects ( Box < Rule > , Box < Rule > ) ,
@@ -98,8 +100,8 @@ impl From<Value> for Rule {
98
100
}
99
101
100
102
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 ( ) ) )
103
105
}
104
106
105
107
pub fn new_and ( lhs : impl Into < Rule > , rhs : impl Into < Rule > ) -> Self {
@@ -129,6 +131,24 @@ impl Value {
129
131
_ => Err ( Error :: TypeError ) ,
130
132
}
131
133
}
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
+ }
132
152
}
133
153
134
154
/// 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>
149
169
150
170
// basic operators
151
171
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
+ }
152
212
Function :: If ( first_rule, second_rule) => {
153
213
let eval_if = eval ( input, output, first_rule) ?
154
214
. ok_or ( Error :: TypeError ) ?
155
215
. try_bool ( ) ?;
156
216
157
217
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) ?
162
219
} else {
163
220
None
164
221
}
@@ -185,24 +242,9 @@ fn eval(input: &Input, output: &mut Output, rule: &Rule) -> Result<Option<Value>
185
242
}
186
243
Function :: Get ( key) => Some ( input. try_get ( key) ?) ,
187
244
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 ( ) ?;
199
246
200
- Value :: BigNum ( big_num)
201
- }
202
- _ => return Err ( Error :: TypeError ) ,
203
- } ;
204
-
205
- Some ( big_num)
247
+ Some ( Value :: BigNum ( big_num) )
206
248
}
207
249
} ;
208
250
@@ -293,4 +335,25 @@ mod test {
293
335
result. expect( "Sould return Non-NULL result!" )
294
336
) ;
295
337
}
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
+ }
296
359
}
0 commit comments