rule/
op.rs

1use std::ops::{Add, Sub, Mul, Div, Rem};
2use std::collections::HashMap;
3
4use lazy_static::lazy_static;
5
6use crate::arg::Arg;
7
8pub type Func = fn(Vec<Arg>) -> Arg;
9
10/// The Operator type, mainly contains a function pointer.
11#[derive(Clone, Debug, PartialEq, PartialOrd)]
12pub struct Op {
13    pub name: String,
14    pub func: Func,
15}
16
17// TODO:
18// 1. static hashmap -> built-in ops [done]
19// 2. custom ops register to whom? maybe just use a global static mut hashmap
20// 3. add more ops [ing]
21// 4. use macro to init register ops [done]
22// 5. func return Result, error handling? or not.
23
24impl Op {
25    /// Constructs a new Operator.
26    pub fn new(name: &str, func: Func) -> Op {
27        Op {
28            name: name.to_owned(),
29            func: func,
30        }
31    }
32
33    /// Get an Operator by name, returns an Option, `None` if not exists.
34    pub fn get(name: &str) -> Option<&Op> {
35        OPS.get(name)
36    }
37}
38
39/// Register builtin OPs.
40///
41/// # Examples
42///
43/// ```
44/// register_builtin!(
45///     "var" => var,
46///     "=" => eq,
47///     "<" => lt,
48/// )
49/// ```
50macro_rules! register_builtin {
51    ( $($alias:tt => $func:tt),* $(,)? ) => {
52        lazy_static! {
53            /// All built-in OPs registered to OPS HashMap.
54            static ref OPS: HashMap<&'static str, Op> = {
55                let mut map = HashMap::new();
56                $(
57                map.insert($alias, Op::new($alias, $func as Func));
58                map.insert(stringify!($func), Op::new(stringify!($func), $func as Func));
59                )*
60                map
61            };
62        }
63    };
64}
65
66register_builtin!(
67    "var" => var,
68
69    // logic operator
70    "=" => eq,
71    "<" => lt,
72    "<=" => le,
73    "!=" => ne,
74    ">=" => ge,
75    ">=" => ge,
76    ">" => gt,
77    "&" => and,
78    "&&" => and,
79    "all" => and,
80    "|" => or,
81    "||" => or,
82    "any" => or,
83    "!" => not,
84
85    // arithmetic operator
86    "+" => add,
87    "sum" => add,
88    "-" => sub,
89    "minus" => sub,
90    "neg" => neg,
91    "*" => mul,
92    "/" => div,
93    "%" => rem,
94    "mod" => rem,
95    "abs" => abs,
96
97    // collection operator
98    "in" => r#in,
99    "startswith" => startswith,
100    "endswith" => endswith,
101    "split" => split,
102    "join" => join,
103
104    // string operator
105    "lower" => lower,
106    "upper" => upper,
107    "match" => r#match,
108    "regex" => regex,
109
110    // casting operator
111    "num" => num,
112    "string" => string,
113);
114
115/// just a placeholder, will not be called
116pub fn var(args: Vec<Arg>) -> Arg {
117    args[0].clone()
118}
119
120pub fn eq(args: Vec<Arg>) -> Arg {
121    Arg::Bool(args.windows(2).all(|w| w[0] == w[1]))
122}
123
124/// `lt` is equivalent to the `<` sign, args[0] and args[1] must be the same type.
125///
126/// ```
127/// use ::rule::{rule, json};
128/// assert!(rule!["lt", 1, 2].unwrap().matches(&json!({})).unwrap());
129/// assert!(rule!["lt", "10", "2"].unwrap().matches(&json!({})).unwrap());
130/// assert!(rule!["lt", 1.1, 1.23].unwrap().matches(&json!({})).unwrap());
131/// assert_eq!(rule!["lt", 1.23, 1.1].unwrap().matches(&json!({})).unwrap(), false);
132/// assert_eq!(rule!["lt", 2, 1].unwrap().matches(&json!({})).unwrap(), false);
133/// ```
134pub fn lt(args: Vec<Arg>) -> Arg {
135    Arg::Bool(args.windows(2).all(|w| w[0] < w[1]))
136}
137
138pub fn le(args: Vec<Arg>) -> Arg {
139    Arg::Bool(args.windows(2).all(|w| w[0] <= w[1]))
140}
141
142pub fn ne(args: Vec<Arg>) -> Arg {
143    Arg::Bool(args.windows(2).all(|w| w[0] != w[1]))
144}
145
146pub fn ge(args: Vec<Arg>) -> Arg {
147    Arg::Bool(args.windows(2).all(|w| w[0] >= w[1]))
148}
149
150pub fn gt(args: Vec<Arg>) -> Arg {
151    Arg::Bool(args.windows(2).all(|w| w[0] > w[1]))
152}
153
154pub fn and(args: Vec<Arg>) -> Arg {
155    Arg::Bool(args.iter().all(|v| v.into()))
156}
157
158pub fn or(args: Vec<Arg>) -> Arg {
159    Arg::Bool(args.iter().any(|v| v.into()))
160}
161
162pub fn not(args: Vec<Arg>) -> Arg {
163    let b: bool = args.get(0).unwrap_or(&Arg::Null).into();
164    Arg::Bool(!b)
165}
166
167pub fn add(args: Vec<Arg>) -> Arg {
168    let mut it = args.into_iter();
169    it.next().map(|first| it.fold(first, Add::add)).unwrap_or(Arg::Null)
170}
171
172pub fn sub(args: Vec<Arg>) -> Arg {
173    let mut it = args.into_iter();
174    it.next().map(|first| it.fold(first, Sub::sub)).unwrap_or(Arg::Null)
175}
176
177pub fn neg(args: Vec<Arg>) -> Arg {
178    -args.get(0).unwrap_or(&Arg::Null)
179}
180
181pub fn mul(args: Vec<Arg>) -> Arg {
182    let mut it = args.into_iter();
183    it.next().map(|first| it.fold(first, Mul::mul)).unwrap_or(Arg::Null)
184}
185
186pub fn div(args: Vec<Arg>) -> Arg {
187    let mut it = args.into_iter();
188    it.next().map(|first| it.fold(first, Div::div)).unwrap_or(Arg::Null)
189}
190
191/// The remainder operator %.
192/// Aliases: %, rem, mod
193pub fn rem(args: Vec<Arg>) -> Arg {
194    let mut it = args.into_iter();
195    it.next().map(|first| it.fold(first, Rem::rem)).unwrap_or(Arg::Null)
196}
197
198/// Computes the absolute value of arg[0].
199pub fn abs(args: Vec<Arg>) -> Arg {
200    let int: i64 = args.get(0).unwrap_or(&Arg::Null).into();
201    Arg::Int(int.abs())
202}
203
204/// Return true if args[0] in args[1..].
205/// e.g. rule json string: ["in", 1, 1, 2, 3]
206/// ```
207/// use ::rule::{rule, json};
208/// assert!(rule!["in", 1, 1, 2, 3].unwrap().matches(&json!({})).unwrap());
209/// ```
210pub fn r#in(args: Vec<Arg>) -> Arg {
211    Arg::Bool(args[1..].contains(&args[0]))
212}
213
214/// Return true if args[0] starts with args[1]
215///
216/// ```
217/// use ::rule::{rule, json};
218/// assert!(rule!["startswith", "hello", "he"].unwrap().matches(&json!({})).unwrap());
219/// assert!(rule!["startswith", "arr", "foo", "bar"].unwrap().matches(&json!({"arr": ["foo", "bar", "baz"]})).unwrap());
220/// ```
221pub fn startswith(args: Vec<Arg>) -> Arg {
222    let ret = match &args[0] {
223        Arg::String(s) => Arg::Bool((&s).starts_with(&args[1].to_string())),
224        Arg::Array(a) => Arg::Bool(a.starts_with(&args[1..])),
225        _ => Arg::Bool(false),
226    };
227    ret
228}
229
230/// Return true if args[0] ends with args[1]
231///
232/// ```
233/// use ::rule::{rule, json};
234/// assert!(rule!["endswith", "hello", "lo"].unwrap().matches(&json!({})).unwrap());
235/// assert!(rule!["endswith", "arr", "bar", "baz"].unwrap().matches(&json!({"arr": ["foo", "bar", "baz"]})).unwrap());
236/// ```
237pub fn endswith(args: Vec<Arg>) -> Arg {
238    let ret = match &args[0] {
239        Arg::String(s) => Arg::Bool((&s).ends_with(&args[1].to_string())),
240        Arg::Array(a) => Arg::Bool(a.ends_with(&args[1..])),
241        _ => Arg::Bool(false),
242    };
243    ret
244}
245
246/// Convert upper case letters to lower case.
247///
248/// ```
249/// use ::rule::{rule, json};
250/// assert!(rule!["=", ["lower", "Hi"], "hi"].unwrap().matches(&json!({})).unwrap());
251/// ```
252pub fn lower(args: Vec<Arg>) -> Arg {
253    Arg::String(String::from(&args[0]).to_lowercase())
254}
255
256/// Convert lower case letters to upper case.
257///
258/// ```
259/// use ::rule::{rule, json};
260/// assert!(rule!["=", ["upper", "Hi"], "HI"].unwrap().matches(&json!({})).unwrap());
261/// ```
262pub fn upper(args: Vec<Arg>) -> Arg {
263    Arg::String(String::from(&args[0]).to_uppercase())
264}
265
266/// Split strings using a seperator.
267///
268/// ```
269/// use ::rule::{rule, json};
270/// assert!(rule!["startswith", ["split", "apple,pear", ","], "apple"].unwrap().matches(&json!({})).unwrap());
271/// ```
272pub fn split(args: Vec<Arg>) -> Arg {
273    let s = &String::from(&args[0]);
274    let sep = &String::from(&args[1]);
275    Arg::Array(s.split(sep).map(|x| Arg::String(x.to_owned())).collect())
276}
277
278/// Concatenate strings with a seperator.
279///
280/// ```
281/// use ::rule::{rule, json};
282/// assert!(rule!["=", ["join", " ", "hello", "world"], "hello world"].unwrap().matches(&json!({})).unwrap());
283/// ```
284pub fn join(args: Vec<Arg>) -> Arg {
285    let mut it = args.into_iter();
286    let sep = &String::from(&it.nth(0).unwrap_or(Arg::String("".to_owned())));
287    Arg::String(it.map(|x| String::from(&x)).collect::<Vec<String>>().join(sep))
288}
289
290/// Match string using an Unix shell style pattern.
291///
292/// ```
293/// use ::rule::{rule, json};
294/// assert!(rule!["match", "hello", "he*"].unwrap().matches(&json!({})).unwrap());
295/// ```
296pub fn r#match(args: Vec<Arg>) -> Arg {
297    match glob::Pattern::new(&String::from(&args[1])) {
298        Ok(patt) => {
299            Arg::Bool(patt.matches(&String::from(&args[0])))
300        },
301        Err(_) => Arg::Bool(false),
302    }
303}
304
305/// Match strings using regular expressions.
306///
307/// ```
308/// use ::rule::{rule, json};
309/// assert!(rule!["regex", "hello", "^he[l-o]*$"].unwrap().matches(&json!({})).unwrap());
310/// ```
311pub fn regex(args: Vec<Arg>) -> Arg {
312    match regex::Regex::new(&String::from(&args[1])) {
313        Ok(re) => {
314            Arg::Bool(re.is_match(&String::from(&args[0])))
315        },
316        Err(_) => Arg::Bool(false),
317    }
318}
319
320/// Convert a string into a number.
321///
322/// ```
323/// use ::rule::{rule, json};
324/// assert!(rule!["=", ["num", "100"], 100].unwrap().matches(&json!({})).unwrap());
325/// assert!(rule!["=", ["num", "1.23"], 1.23].unwrap().matches(&json!({})).unwrap());
326/// assert_eq!(rule!["=", "100", 100].unwrap().matches(&json!({})).unwrap(), false);
327/// ```
328pub fn num(args: Vec<Arg>) -> Arg {
329    let a = args[0].clone();
330    match a {
331        Arg::Int(_) => a,
332        Arg::Float(_) => a,
333        Arg::String(v) => {
334            match v.parse::<i64>() {
335                Ok(i) => Arg::Int(i),
336                Err(_) => match v.parse::<f64>() {
337                    Ok(f) => Arg::Float(f),
338                    Err(_) => Arg::Int(0i64),
339                }
340            }
341        },
342        _ => Arg::Int(Into::<i64>::into(a)),
343    }
344}
345
346/// Convert a number into a string.
347///
348/// ```
349/// use ::rule::{rule, json};
350/// assert!(rule!["=", ["string", 100], "100"].unwrap().matches(&json!({})).unwrap());
351/// ```
352pub fn string(args: Vec<Arg>) -> Arg {
353    Arg::String(String::from(&args[0]))
354}
355
356// TODO: add more OPs
357//
358//    ('contains', None),
359//    ('onlycontains/allin', None),
360//    uniq
361//    bool/notempty
362//    empty