# Reval   [![Build Status](https://github.com/mendelt/reval/workflows/Build/badge.svg)](https://github.com/mendelt/reval/actions?query=workflow%3ABuild+event%3Apush+branch%3Amain) Reval, short for Rust Evaluator is a light-weight expression evaluator library. It can be used as a rules-engine or in other situations where simple user expressions need to be evaluated. Expressions or rules can be written in a simple DSL or in a json format that is directly parsed into Reval expression AST objects. For now the Reval DSL parser is experimental but eventually this should replace json rules. Expressions can be evaluated against input data to produce output data. The input and output data is passed in and out of the rules as a `reval::Value` object which can contain simple data or more complex structures like maps or vectors. Data can be nested so complex data can be passed into Reval expressions. To make it easy to construct input data from your own datatypes the Reval crate implements a serde serializer for Value types. So any type that implements `serde::Serialize` can be serialized into a `reval::Value` without writing any code. More information on writing rules can be found here: [Writing Rules](https://mendelt.github.io/reval/) This example shows how to set up a RuleSet using the builder. A simple Rule is added and a data-type is set up that is used as input for the rules; ```rust 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()); } ``` Reval can be extended with user-functions by implementing the `UserFunction` trait on a type and passing an instance of that type to the RuleSet. The following example shows how this would work; The input data-type for the rules, must implement serde::Serialize so it can be serialized into a `reval::Value` ```rust 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: {{version}}* ## License Licensed under either of * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) at your option. ### Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.