1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
use serde_json::Value;
use super::logic;
pub fn compute(args: &[Value]) -> Value {
match args.len() {
// Return the condition, for whatever reason.
0..=1 => args.get(0).cloned().unwrap_or(Value::Null),
// Normal if/then/else, with default null.
2..=3 => {
let condition = args.get(0).unwrap_or(&Value::Null);
if logic::is_truthy(condition) {
args.get(1).unwrap().clone()
} else {
args.get(2).cloned().unwrap_or(Value::Null)
}
}
// Now the arguments are pairs of condition and then value. The last argument is the
// else value.
// TODO: Actually the logic of this arm computes the other cases properly. Test whether
// the short circuit cases have a performance benefit or not.
_ => {
let mut args = args.iter();
loop {
let arg1 = args.next();
let arg2 = args.next();
match arg2 {
// The value behind arg1 is the last argument to the if operator, which is
// the else argument. Since we come until here, no other (else-)if condition
// was truthy. Therefore return the value of arg1.
None => return arg1.cloned().unwrap_or(Value::Null),
Some(then) => {
let condition = arg1.unwrap_or(&Value::Null);
// If the condition (arg1) is truthy, return the then value (arg2).
// Otherwise just continue with the next pair.
if logic::is_truthy(condition) {
return then.clone();
}
}
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn simple() {
let null = json!(null);
assert_eq!(compute(&[]), null);
assert_eq!(compute(&[Value::Null]), null);
}
#[test]
fn one_arg() {
assert_eq!(compute(&[json!(true)]), json!(true));
assert_eq!(compute(&[json!(false)]), json!(false));
assert_eq!(compute(&[json!("foo")]), json!("foo"));
}
#[test]
fn two_args() {
assert_eq!(compute(&[json!(true), json!(5)]), json!(5));
assert_eq!(compute(&[json!(false), json!(5)]), json!(null));
assert_eq!(compute(&[json!("foo"), json!("bar")]), json!("bar"));
}
#[test]
fn three_args() {
assert_eq!(compute(&[json!(true), json!(5), json!(6)]), json!(5));
assert_eq!(compute(&[json!(false), json!(5), json!(6)]), json!(6));
}
#[test]
fn more() {
assert_eq!(
compute(&[json!(false), json!(5), json!(true), json!(6)]),
json!(6)
);
assert_eq!(
compute(&[json!(false), json!(5), json!(false), json!(6)]),
json!(null)
);
assert_eq!(
compute(&[json!(false), json!(5), json!(false), json!(6), json!(7)]),
json!(7)
);
assert_eq!(
compute(&[
json!(false),
json!(5),
json!(false),
json!(6),
json!(7),
json!(8)
]),
json!(8)
);
}
}