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
@@ -49,6 +49,10 @@ impl Value {
49
49
pub fn new_string ( string : & str ) -> Self {
50
50
Self :: String ( string. to_string ( ) )
51
51
}
52
+
53
+ pub fn new_number ( number : impl Into < Number > ) -> Self {
54
+ Self :: Number ( number. into ( ) )
55
+ }
52
56
}
53
57
54
58
impl TryFrom < SerdeValue > for Value {
@@ -77,6 +81,8 @@ impl TryFrom<SerdeValue> for Value {
77
81
#[ serde( rename_all = "camelCase" ) ]
78
82
// TODO: https://github.com/AdExNetwork/adex-validator-stack-rust/issues/296
79
83
pub enum Function {
84
+ /// Math `div`
85
+ Div ( Box < Rule > , Box < Rule > ) ,
80
86
If ( Box < Rule > , Box < Rule > ) ,
81
87
And ( Box < Rule > , Box < Rule > ) ,
82
88
Intersects ( Box < Rule > , Box < Rule > ) ,
@@ -98,8 +104,8 @@ impl From<Value> for Rule {
98
104
}
99
105
100
106
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 ( ) ) )
107
+ pub fn new_if ( condition : impl Into < Rule > , then : impl Into < Rule > ) -> Self {
108
+ Self :: If ( Box :: new ( condition . into ( ) ) , Box :: new ( then . into ( ) ) )
103
109
}
104
110
105
111
pub fn new_and ( lhs : impl Into < Rule > , rhs : impl Into < Rule > ) -> Self {
@@ -113,6 +119,10 @@ impl Function {
113
119
pub fn new_get ( key : & str ) -> Self {
114
120
Self :: Get ( key. to_string ( ) )
115
121
}
122
+
123
+ pub fn new_bn ( value : impl Into < Value > ) -> Self {
124
+ Self :: Bn ( value. into ( ) )
125
+ }
116
126
}
117
127
118
128
impl Value {
@@ -129,6 +139,24 @@ impl Value {
129
139
_ => Err ( Error :: TypeError ) ,
130
140
}
131
141
}
142
+
143
+ pub fn try_bignum ( self ) -> Result < BigNum , Error > {
144
+ BigNum :: try_from ( self )
145
+ }
146
+ }
147
+
148
+ impl TryFrom < Value > for BigNum {
149
+ type Error = Error ;
150
+ fn try_from ( value : Value ) -> Result < Self , Self :: Error > {
151
+ match value {
152
+ Value :: String ( string) => BigNum :: from_str ( & string) . map_err ( |_| Error :: TypeError ) ,
153
+ Value :: BigNum ( big_num) => Ok ( big_num) ,
154
+ Value :: Number ( number) => {
155
+ BigNum :: from_str ( & number. to_string ( ) ) . map_err ( |_| Error :: TypeError )
156
+ }
157
+ _ => Err ( Error :: TypeError ) ,
158
+ }
159
+ }
132
160
}
133
161
134
162
/// Evaluates a Rule to be applied and has 3 outcomes:
@@ -149,16 +177,53 @@ fn eval(input: &Input, output: &mut Output, rule: &Rule) -> Result<Option<Value>
149
177
150
178
// basic operators
151
179
let value = match function {
180
+ Function :: Div ( first_rule, second_rule) => {
181
+ let value = match first_rule. eval ( input, output) ?. ok_or ( Error :: TypeError ) ? {
182
+ Value :: Number ( first_number) => {
183
+ match second_rule. eval ( input, output) ?. ok_or ( Error :: TypeError ) ? {
184
+ Value :: Number ( second_number) => {
185
+ if let Some ( num) = first_number. as_f64 ( ) {
186
+ let divided =
187
+ num. div ( second_number. as_f64 ( ) . ok_or ( Error :: TypeError ) ?) ;
188
+
189
+ Value :: Number ( Number :: from_f64 ( divided) . ok_or ( Error :: TypeError ) ?)
190
+ } else if let Some ( num) = first_number. as_i64 ( ) {
191
+ let rhs = second_number. as_i64 ( ) . ok_or ( Error :: TypeError ) ?;
192
+ let divided = num. checked_div ( rhs) . ok_or ( Error :: TypeError ) ?;
193
+
194
+ Value :: Number ( divided. into ( ) )
195
+ } else if let Some ( num) = first_number. as_u64 ( ) {
196
+ let rhs = second_number. as_u64 ( ) . ok_or ( Error :: TypeError ) ?;
197
+ let divided = num. checked_div ( rhs) . ok_or ( Error :: TypeError ) ?;
198
+
199
+ Value :: Number ( divided. into ( ) )
200
+ } else {
201
+ return Err ( Error :: TypeError ) ;
202
+ }
203
+ }
204
+ _ => return Err ( Error :: TypeError ) ,
205
+ }
206
+ }
207
+ Value :: BigNum ( first_bignum) => {
208
+ let second_bignum = second_rule
209
+ . eval ( input, output) ?
210
+ . ok_or ( Error :: TypeError ) ?
211
+ . try_bignum ( ) ?;
212
+
213
+ Value :: BigNum ( first_bignum. div ( second_bignum) )
214
+ }
215
+ _ => return Err ( Error :: TypeError ) ,
216
+ } ;
217
+
218
+ Some ( value)
219
+ }
152
220
Function :: If ( first_rule, second_rule) => {
153
221
let eval_if = eval ( input, output, first_rule) ?
154
222
. ok_or ( Error :: TypeError ) ?
155
223
. try_bool ( ) ?;
156
224
157
225
if eval_if {
158
- let bool = eval ( input, output, second_rule) ?
159
- . ok_or ( Error :: TypeError ) ?
160
- . try_bool ( ) ?;
161
- Some ( Value :: Bool ( bool) )
226
+ eval ( input, output, second_rule) ?
162
227
} else {
163
228
None
164
229
}
@@ -185,24 +250,9 @@ fn eval(input: &Input, output: &mut Output, rule: &Rule) -> Result<Option<Value>
185
250
}
186
251
Function :: Get ( key) => Some ( input. try_get ( key) ?) ,
187
252
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 ) ?;
253
+ let big_num = value. clone ( ) . try_bignum ( ) ?;
199
254
200
- Value :: BigNum ( big_num)
201
- }
202
- _ => return Err ( Error :: TypeError ) ,
203
- } ;
204
-
205
- Some ( big_num)
255
+ Some ( Value :: BigNum ( big_num) )
206
256
}
207
257
} ;
208
258
@@ -293,4 +343,100 @@ mod test {
293
343
result. expect( "Sould return Non-NULL result!" )
294
344
) ;
295
345
}
346
+
347
+ #[ test]
348
+ fn test_and_eval ( ) {
349
+ let input = Input :: default ( ) ;
350
+ let mut output = Output {
351
+ show : true ,
352
+ boost : 1.0 ,
353
+ price : Default :: default ( ) ,
354
+ } ;
355
+
356
+ let cases = [
357
+ ( true , true , true ) ,
358
+ ( false , false , false ) ,
359
+ ( false , true , false ) ,
360
+ ( true , false , false ) ,
361
+ ] ;
362
+
363
+ for ( lhs, rhs, expected) in cases. iter ( ) {
364
+ let rule = Rule :: Function ( Function :: new_and ( Value :: Bool ( * lhs) , Value :: Bool ( * rhs) ) ) ;
365
+ let expected = Some ( Value :: Bool ( * expected) ) ;
366
+
367
+ assert_eq ! ( Ok ( expected) , rule. eval( & input, & mut output) ) ;
368
+ }
369
+ }
370
+
371
+ #[ test]
372
+ fn test_if_eval ( ) {
373
+ let input = Input :: default ( ) ;
374
+ let mut output = Output {
375
+ show : true ,
376
+ boost : 1.0 ,
377
+ price : Default :: default ( ) ,
378
+ } ;
379
+
380
+ let then = Value :: String ( "yes" . to_string ( ) ) ;
381
+
382
+ let rule = Rule :: Function ( Function :: new_if ( Value :: Bool ( true ) , then. clone ( ) ) ) ;
383
+
384
+ assert_eq ! ( Ok ( Some ( then. clone( ) ) ) , rule. eval( & input, & mut output) ) ;
385
+
386
+ let rule = Rule :: Function ( Function :: new_if ( Value :: Bool ( false ) , then) ) ;
387
+
388
+ assert_eq ! ( Ok ( None ) , rule. eval( & input, & mut output) ) ;
389
+ }
390
+
391
+ #[ test]
392
+ fn test_bn_eval_from_actual_number_value_string_bignum_or_number ( ) {
393
+ let input = Input :: default ( ) ;
394
+ let mut output = Output {
395
+ show : true ,
396
+ boost : 1.0 ,
397
+ price : Default :: default ( ) ,
398
+ } ;
399
+
400
+ let cases = vec ! [
401
+ ( Value :: new_string( "1000" ) , Value :: BigNum ( 1000 . into( ) ) ) ,
402
+ ( Value :: new_number( 5000 ) , Value :: BigNum ( 5000 . into( ) ) ) ,
403
+ ( Value :: BigNum ( 2 . into( ) ) , Value :: BigNum ( 2 . into( ) ) ) ,
404
+ // rounded floats should work!
405
+ (
406
+ Value :: Number ( Number :: from_f64( 2.0 ) . expect( "should create float number" ) ) ,
407
+ Value :: BigNum ( 2 . into( ) ) ,
408
+ ) ,
409
+ ] ;
410
+
411
+ for ( from, expected) in cases. into_iter ( ) {
412
+ let rule = Rule :: Function ( Function :: new_bn ( from) ) ;
413
+
414
+ assert_eq ! ( Ok ( Some ( expected) ) , rule. eval( & input, & mut output) ) ;
415
+ }
416
+ }
417
+
418
+ #[ test]
419
+ fn test_bn_eval_from_actual_incorrect_value ( ) {
420
+ let input = Input :: default ( ) ;
421
+ let mut output = Output {
422
+ show : true ,
423
+ boost : 1.0 ,
424
+ price : Default :: default ( ) ,
425
+ } ;
426
+
427
+ let error_cases = vec ! [
428
+ Value :: new_string( "text" ) ,
429
+ // BigNums can only be possitive
430
+ Value :: new_number( -100 ) ,
431
+ Value :: Bool ( true ) ,
432
+ Value :: Array ( vec![ Value :: Bool ( false ) ] ) ,
433
+ Value :: Number ( Number :: from_f64( 2.5 ) . expect( "should create float number" ) ) ,
434
+ ] ;
435
+
436
+ for error_case in error_cases. into_iter ( ) {
437
+ let rule = Rule :: Function ( Function :: new_bn ( error_case) ) ;
438
+
439
+ assert_eq ! ( Err ( Error :: TypeError ) , rule. eval( & input, & mut output) ) ;
440
+ }
441
+ }
296
442
}
0 commit comments