Closed GopherJ closed 4 years ago
Hello @schungx cool, also I'm thinking if rhai
can add in
operator to detect if some element is in a list.
My use case is in casbin-rs: https://github.com/casbin/casbin-rs
We use rhai for evaluating string expression. Now rhai doesn't support in operator so we have to convert
r.sub in ("alice", "bob")
into
inMatch(r.sub, ["alice", "bob"])
and register an inMatch
function.
You can probably write your own very simple function to do it. Rhai doesn't provide one for arrays because, technically speaking, you can override the ==
operator and define your own equality comparisons.
fn contains(array, element) {
for item in array {
if item == element { return true; }
}
false
}
Then you can write something like:
let list = ["alice", "bob"];
if list.contains(r.sub) {
.... do something
}
However, this will be quite inefficient because the list
array is copied by value every time you call the function. If you want it fast, you can write your own small function in Rust and then register_fn
it. For example, if you're only handling arrays of strings, you can do something similar to:
engine.register_fn("contains", |list: &mut Array, item: String| {
list.iter().map(|x| x.as_ref().downcast_ref::<String>().unwrap()).any(|s| s == &item)
});
My use case is in casbin-rs: https://github.com/casbin/casbin-rs
Your use case only seems to need expressions instead of full scripting. Therefore, you should check out compile_expression
which only compiles a subset of the language -- those to support expressions -- to an AST
. Then you can repeatedly evaluate that AST
without needing to parse again.
You'd also want to exclude language features you don't need. For example, you may not need the standard library of functions, so no_stdlib
. You may not need floating-point (no_float
), or different integer types (only_i32
). And definitely you'd not need to define any functions (no_function
).
@schungx that's actually not convinent, I'm using that method but I need to use regex to convert the following expressing:
r.sub in ("alice", "bob")
to
contains(r.sub, ["alice", "bob"])
ideally we should support the javascript-like in operator in rhai
So what you're suggesting is:
Expression : Expression 'in' Expression (must evaluate to Array)
This is probably easily doable by adding an in
infix operator. Let me experiment a bit.
Might as well add:
let x = #{a: 1, b:2};
("a" in x) == true; // JavaScript
contains(r.sub, ["alice", "bob"])
It might be easier for your code generation to convert it into:
let x = r.sub;
(x == "alice") || (x == "bob")
Should be more efficient since arrays and strings do not need to be copied around.
It's already implemented for the conversion but I would like to have it supported in rhai
https://github.com/casbin/casbin-rs/blob/301420c7630cd3b6021f9738facf213e19080dc8/src/util.rs#L13
because it's not a graceful solution, I would like to remove it when in
operator is supported in rhai.
PR https://github.com/jonathandturner/rhai/pull/128 adds 'in' expressions.
@schungx Cool, could you notify me when it's merged and published? I'll test it. Thanks for your awesome work
It is already merged and published to crates.io
as 0.11.1
.
@schungx I mean #128
Yes, https://github.com/jonathandturner/rhai/pull/128 is published as 0.11.1
.
No reason why it can't. I'll make it public.
Watch for it to show up at the latest PR https://github.com/jonathandturner/rhai/pull/123