31 个版本

0.8.0-rc.02024年7月24日
0.7.8 2024年6月17日
0.7.5 2024年3月11日
0.7.4 2023年11月7日
0.4.1 2022年11月30日

#362 in 解析器实现

Download history 261/week @ 2024-05-02 101/week @ 2024-05-09 108/week @ 2024-05-16 104/week @ 2024-05-23 66/week @ 2024-05-30 121/week @ 2024-06-06 445/week @ 2024-06-13 155/week @ 2024-06-20 111/week @ 2024-06-27 133/week @ 2024-07-04 26/week @ 2024-07-11 279/week @ 2024-07-18 213/week @ 2024-07-25 87/week @ 2024-08-01 86/week @ 2024-08-08 78/week @ 2024-08-15

546 每月下载量

MIT/Apache

130KB
3.5K SLoC

Reval — 构建状态

Reval(Rust Evaluator 的缩写)是一个轻量级的表达式评估库。它可以作为一个规则引擎或用于其他需要评估简单用户表达式的场景。

表达式或规则可以使用简单的 DSL 或 json 格式编写,该格式可以直接解析为 Reval 表达式 AST 对象。目前 Reval DSL 解析器是实验性的,但最终应取代 json 规则。

可以使用输入数据来评估表达式,以生成输出数据。输入和输出数据以 reval::Value 对象的形式传入和传出规则,该对象可以包含简单数据或更复杂的数据结构,如映射或向量。数据可以嵌套,因此可以将复杂数据传递到 Reval 表达式中。

为了方便从自己的数据类型构建输入数据,Reval 包实现了 Value 类型的 serde 序列化器。因此,任何实现了 serde::Serialize 的类型都可以不编写任何代码就序列化为 reval::Value

有关编写规则的更多信息,请参阅此处: 编写规则

以下示例展示了如何使用构建器设置 RuleSet。添加了一个简单的规则并设置了一个用作规则输入的数据类型;

use reval::prelude::*;
use serde::Serialize;

// The input data-type for the rules, must implement serde::Serialize so it
// can be serialized into a `reval::Value`
#[derive(Serialize)]
struct Data {
    age: u16,
}
// Set up an "age check" rule that checks if the "age" input field is
// greater than or equal to 21
let rule = r"
// age check
age >= 21
";

// Set up the ruleset builder, add the rule and build the `RuleSet`
let ruleset = ruleset().with_rule(Rule::parse_json(rule).unwrap()).unwrap().build();
// Set up input data
let facts = Data { age: 16 };
// Evaluate the ruleset on the input data and check if the rule returns
// `false`
for outcome in ruleset.evaluate(&facts).await.unwrap() {
    assert_eq!(outcome.value.unwrap(), false.into());
}

可以通过在类型上实现 UserFunction 特性并传递该类型的实例到 RuleSet 来使用户函数扩展 Reval。以下示例展示了这是如何工作的;规则输入的数据类型必须实现 serde::Serialize,以便可以将其序列化为 reval::Value

use reval::prelude::*;
use serde::Serialize;

#[derive(Serialize)]
struct Data {
    age: u16,
}
// Set up a FakeId UserFunction that increments an integer `Value` to
// bypass the age check
struct FakeId;
#[async_trait::async_trait]
impl UserFunction for FakeId {
    async fn call(&self, param: Value) -> FunctionResult {
       let age: i128 = param.try_into()?;
       Ok((age * 2).into())
    }

    fn name(&self) -> &'static str {
        "fake_id"
    }
}
// Set up an "age check" rule that checks if the "age" input field is
// greater than or equal to 21. But it first calls the `fake_id` user-
// function.
let rule = r"
// age check
fake_id(age) >= i21
";

// Set up the ruleset builder, add the rule, add the user-function and
// build the `RuleSet`
let ruleset = ruleset()
    .with_rule(Rule::parse_json(rule).unwrap()).unwrap()
    .with_function(FakeId {}).unwrap()
    .build();
// Set up input data
let facts = Data { age: 16 };
// Evaluate the ruleset on the input data and check if the rule returns
// `true`
for outcome in ruleset.evaluate(&facts).await.unwrap() {
    assert_eq!(outcome.value.unwrap(), true.into());
}

版本:{{version}}

许可证

根据以下任一项许可证授权:

由您选择。

贡献

除非您明确说明,否则您根据Apache-2.0许可协议定义的任何有意提交以包含在工作中的贡献,将如上双重许可,不附加任何额外条款或条件。

依赖项

约5-8MB
约142K SLoC