1
1
//! Helpers for boolean operations
2
+
3
+ use std:: cmp:: Ordering ;
4
+ use std:: str:: FromStr ;
5
+
6
+ use num_order:: NumOrd ;
2
7
use serde_json:: Value as Json ;
3
8
4
9
use crate :: json:: value:: JsonTruthy ;
5
- use std:: cmp:: Ordering ;
6
10
7
11
handlebars_helper ! ( eq: |x: Json , y: Json | x == y) ;
8
12
handlebars_helper ! ( ne: |x: Json , y: Json | x != y) ;
@@ -24,13 +28,48 @@ handlebars_helper!(len: |x: Json| {
24
28
25
29
fn compare_json ( x : & Json , y : & Json ) -> Option < Ordering > {
26
30
fn cmp_num_str ( a_num : & serde_json:: Number , b_str : & str ) -> Option < Ordering > {
27
- let a_f64 = a_num. as_f64 ( ) ?;
28
- let b_f64 = b_str. parse :: < f64 > ( ) . ok ( ) ?;
29
- a_f64. partial_cmp ( & b_f64)
31
+ let b_num = serde_json:: Number :: from_str ( b_str) . ok ( ) ?;
32
+ cmp_nums ( a_num, & b_num)
33
+ }
34
+
35
+ // this function relies on serde_json::Numbers coerce logic
36
+ // for number value between [0, u64::MAX], is_u64() returns true
37
+ // for number value between [i64::MIN, i64::MAX], is_i64() returns true
38
+ // for others, is_f64() returns true, note that this behaviour is not
39
+ // guaranteed according to serde_json docs
40
+ fn cmp_nums ( a_num : & serde_json:: Number , b_num : & serde_json:: Number ) -> Option < Ordering > {
41
+ if a_num. is_u64 ( ) {
42
+ let a = a_num. as_u64 ( ) ?;
43
+ if b_num. is_u64 ( ) {
44
+ NumOrd :: num_partial_cmp ( & a, & b_num. as_u64 ( ) ?)
45
+ } else if b_num. is_i64 ( ) {
46
+ NumOrd :: num_partial_cmp ( & a, & b_num. as_i64 ( ) ?)
47
+ } else {
48
+ NumOrd :: num_partial_cmp ( & a, & b_num. as_f64 ( ) ?)
49
+ }
50
+ } else if a_num. is_i64 ( ) {
51
+ let a = a_num. as_i64 ( ) ?;
52
+ if b_num. is_u64 ( ) {
53
+ NumOrd :: num_partial_cmp ( & a, & b_num. as_u64 ( ) ?)
54
+ } else if b_num. is_i64 ( ) {
55
+ NumOrd :: num_partial_cmp ( & a, & b_num. as_i64 ( ) ?)
56
+ } else {
57
+ NumOrd :: num_partial_cmp ( & a, & b_num. as_f64 ( ) ?)
58
+ }
59
+ } else {
60
+ let a = a_num. as_f64 ( ) ?;
61
+ if b_num. is_u64 ( ) {
62
+ NumOrd :: num_partial_cmp ( & a, & b_num. as_u64 ( ) ?)
63
+ } else if b_num. is_i64 ( ) {
64
+ NumOrd :: num_partial_cmp ( & a, & b_num. as_i64 ( ) ?)
65
+ } else {
66
+ NumOrd :: num_partial_cmp ( & a, & b_num. as_f64 ( ) ?)
67
+ }
68
+ }
30
69
}
31
70
32
71
match ( x, y) {
33
- ( Json :: Number ( a) , Json :: Number ( b) ) => a . as_f64 ( ) . partial_cmp ( & b . as_f64 ( ) ) ,
72
+ ( Json :: Number ( a) , Json :: Number ( b) ) => cmp_nums ( a , b ) ,
34
73
( Json :: String ( a) , Json :: String ( b) ) => Some ( a. cmp ( b) ) ,
35
74
( Json :: Bool ( a) , Json :: Bool ( b) ) => Some ( a. cmp ( b) ) ,
36
75
( Json :: Number ( a) , Json :: String ( b) ) => cmp_num_str ( a, b) ,
@@ -133,6 +172,7 @@ mod test_conditions {
133
172
test_condition ( "(gte 5 5)" , true ) ;
134
173
test_condition ( "(lt 3 5)" , true ) ;
135
174
test_condition ( "(lte 5 5)" , true ) ;
175
+ test_condition ( "(lt 9007199254740992 9007199254740993)" , true ) ;
136
176
137
177
// Float comparisons
138
178
test_condition ( "(gt 5.5 3.3)" , true ) ;
@@ -151,6 +191,16 @@ mod test_conditions {
151
191
test_condition ( r#"(lt 53 "35")"# , false ) ;
152
192
test_condition ( r#"(lt "35" 53)"# , true ) ;
153
193
test_condition ( r#"(gte "53" 53)"# , true ) ;
194
+ test_condition ( r#"(lt -1 0)"# , true ) ;
195
+ test_condition ( r#"(lt "-1" 0)"# , true ) ;
196
+ test_condition ( r#"(lt "-1.00" 0)"# , true ) ;
197
+ test_condition ( r#"(gt "1.00" 0)"# , true ) ;
198
+ test_condition ( r#"(gt 0 -1)"# , true ) ;
199
+ test_condition ( r#"(gt 0 "-1")"# , true ) ;
200
+ test_condition ( r#"(gt 0 "-1.00")"# , true ) ;
201
+ test_condition ( r#"(lt 0 "1.00")"# , true ) ;
202
+ // u64::MAX
203
+ test_condition ( r#"(gt 18446744073709551615 -1)"# , true ) ;
154
204
155
205
// Boolean comparisons
156
206
test_condition ( "(gt true false)" , true ) ;
0 commit comments