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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use std::collections::BTreeMap;
use std::convert::TryFrom;
use std::sync::Arc;
use crate::environment::Environment;
use crate::error::{Error, ErrorKind};
use crate::value::{Value, ValueArgs};
type TestFunc =
dyn Fn(&Environment, Value, Vec<Value>) -> Result<bool, Error> + Sync + Send + 'static;
pub(crate) struct BoxedTest(Arc<TestFunc>);
pub trait Test<V = Value, Args = Vec<Value>>: Send + Sync + 'static {
fn perform(&self, env: &Environment, value: V, args: Args) -> Result<bool, Error>;
}
macro_rules! tuple_impls {
( $( $name:ident )* ) => {
impl<Func, V, $($name),*> Test<V, ($($name,)*)> for Func
where
Func: Fn(&Environment, V, $($name),*) -> Result<bool, Error> + Send + Sync + 'static
{
fn perform(&self, env: &Environment, value: V, args: ($($name,)*)) -> Result<bool, Error> {
#[allow(non_snake_case)]
let ($($name,)*) = args;
(self)(env, value, $($name,)*)
}
}
};
}
tuple_impls! {}
tuple_impls! { A }
tuple_impls! { A B }
tuple_impls! { A B C }
tuple_impls! { A B C D }
impl BoxedTest {
pub fn new<F, V, Args>(f: F) -> BoxedTest
where
F: Test<V, Args>,
V: TryFrom<Value>,
Args: ValueArgs,
{
BoxedTest(Arc::new(move |env, value, args| -> Result<bool, Error> {
f.perform(
env,
TryFrom::try_from(value).map_err(|_| {
Error::new(
ErrorKind::ImpossibleOperation,
"imcompatible value for filter",
)
})?,
ValueArgs::from_values(args)?,
)
}))
}
pub fn perform(
&self,
env: &Environment,
value: Value,
args: Vec<Value>,
) -> Result<bool, Error> {
(self.0)(env, value, args)
}
}
pub fn is_odd(_env: &Environment, v: Value) -> Result<bool, Error> {
Ok(v.as_primitive()
.and_then(|x| x.as_i128())
.map_or(false, |x| x % 2 != 0))
}
pub fn is_even(_env: &Environment, v: Value) -> Result<bool, Error> {
Ok(v.as_primitive()
.and_then(|x| x.as_i128())
.map_or(false, |x| x % 2 == 0))
}
pub fn is_undefined(_env: &Environment, v: Value) -> Result<bool, Error> {
Ok(v.is_undefined())
}
pub fn is_defined(_env: &Environment, v: Value) -> Result<bool, Error> {
Ok(!v.is_undefined())
}
pub(crate) fn get_default_tests() -> BTreeMap<&'static str, BoxedTest> {
let mut rv = BTreeMap::new();
rv.insert("odd", BoxedTest::new(is_odd));
rv.insert("even", BoxedTest::new(is_even));
rv.insert("undefined", BoxedTest::new(is_undefined));
rv.insert("defined", BoxedTest::new(is_defined));
rv
}
#[test]
fn test_basics() {
fn test(_: &Environment, a: u32, b: u32) -> Result<bool, Error> {
Ok(a == b)
}
let env = Environment::new();
let bx = BoxedTest::new(test);
assert!(bx
.perform(&env, Value::from(23), vec![Value::from(23)])
.unwrap());
}