Struct regorust::Interpreter
source · pub struct Interpreter { /* private fields */ }Expand description
Interface for the Rego interpreter.
This wraps the Rego C API, and handles passing calls to the C API and converting the results to Rust types.
§Examples
let rego = Interpreter::new();
match rego.query("x=5;y=x + (2 - 4 * 0.25) * -3 + 7.4") {
Ok(result) => {
let x = result.binding("x").expect("cannot get x");
let y = result.binding("y").expect("cannot get y");
println!("x = {}", x.json().unwrap());
println!("y = {}", y.json().unwrap());
}
Err(e) => {
panic!("error: {}", e);
}
}let input = r#"
{
"a": 10,
"b": "20",
"c": 30.0,
"d": true
}
"#;
let data0 = r#"
{
"one": {
"bar": "Foo",
"baz": 5,
"be": true,
"bop": 23.4
},
"two": {
"bar": "Bar",
"baz": 12.3,
"be": false,
"bop": 42
}
}
"#;
let data1 = r#"
{
"three": {
"bar": "Baz",
"baz": 15,
"be": true,
"bop": 4.23
}
}
"#;
let module = r#"
package objects
rect := {`width`: 2, "height": 4}
cube := {"width": 3, `height`: 4, "depth": 5}
a := 42
b := false
c := null
d := {"a": a, "x": [b, c]}
index := 1
shapes := [rect, cube]
names := ["prod", `smoke1`, "dev"]
sites := [{"name": "prod"}, {"name": names[index]}, {"name": "dev"}]
e := {
a: "foo",
"three": c,
names[2]: b,
"four": d,
}
f := e["dev"]
"#;
let rego = Interpreter::new();
rego.set_input_json(input);
rego.add_data_json(data0);
rego.add_data_json(data1);
rego.add_module("objects", module);
match rego.query("x=[data.one, input.b, data.objects.sites[1]]") {
Ok(result) => {
println!("{}", result.to_str().unwrap());
let x = result.binding("x").expect("cannot get x");
let data_one = x.index(0).unwrap();
if let NodeValue::String(bar) = data_one
.lookup("bar")
.unwrap()
.value()
.unwrap()
{
println!("data.one.bar = {}", bar);
}
}
Err(e) => {
panic!("error: {}", e);
}
}Implementations§
source§impl Interpreter
impl Interpreter
sourcepub fn set_log_level(&self, log_level: LogLevel) -> Result<(), &'static str>
pub fn set_log_level(&self, log_level: LogLevel) -> Result<(), &'static str>
Sets the level of logging produced by the library.
sourcepub fn get_log_level(&self) -> Result<LogLevel, &'static str>
pub fn get_log_level(&self) -> Result<LogLevel, &'static str>
Sets the level of logging produced by the library.
sourcepub fn add_module_file(&self, path: &Path) -> Result<(), String>
pub fn add_module_file(&self, path: &Path) -> Result<(), String>
Adds a Rego module from a file.
The file must be valid Rego, and is equivalent to adding
the module as a string using add_module.
§Example module file
package scalars
greeting := "Hello"
max_height := 42
pi := 3.14159
allowed := true
location := null
sourcepub fn add_module(&self, name: &str, source: &str) -> Result<(), String>
pub fn add_module(&self, name: &str, source: &str) -> Result<(), String>
Adds a Rego module from a string.
§Example
let module = r#"
package scalars
greeting := "Hello"
max_height := 42
pi := 3.14159
allowed := true
location := null
"#;
let rego = Interpreter::new();
rego.add_module("scalars", module);
let result = rego.query("data.scalars.greeting").unwrap();
println!("{}", result.to_str().unwrap());sourcepub fn add_data_json_file(&self, path: &Path) -> Result<(), String>
pub fn add_data_json_file(&self, path: &Path) -> Result<(), String>
Adds a base document from a file.
The file must be a valid JSON object, and is equivalent to adding
the document as a string using add_data_json.
§Example document file
{
"one": {
"bar": "Foo",
"baz": 5,
"be": true,
"bop": 23.4
},
"two": {
"bar": "Bar",
"baz": 12.3,
"be": false,
"bop": 42
}
}
sourcepub fn add_data_json(&self, data: &str) -> Result<(), String>
pub fn add_data_json(&self, data: &str) -> Result<(), String>
Adds a base document from a string.
The string must contain a valid JSON object.
§Example
let data = r#"
{
"one": {
"bar": "Foo",
"baz": 5,
"be": true,
"bop": 23.4
},
"two": {
"bar": "Bar",
"baz": 12.3,
"be": false,
"bop": 42
}
}
"#;
let rego = Interpreter::new();
rego.add_data_json(data);
let result = rego.query("data.one.bar").unwrap();
println!("{}", result.to_str().unwrap());sourcepub fn set_input_json_file(&self, path: &Path) -> Result<(), String>
pub fn set_input_json_file(&self, path: &Path) -> Result<(), String>
Sets the input JSON expression from a file.
The input must be a single valid JSON value. It is equivalent to adding
the input file as a string using add_input_json.
§Example input files
"Hello, rego"
42
[1, 2, 3]
{"a": 1, "b": 2}
sourcepub fn set_input_json(&self, input: &str) -> Result<(), String>
pub fn set_input_json(&self, input: &str) -> Result<(), String>
Sets the input JSON expression from a string.
The input must be a single valid JSON value.
§Example input files
"Hello, rego"
42
[1, 2, 3]
{"a": 1, "b": 2}
§Example
let input = r#"
{
"a": 10,
"b": "20",
"c": 30.0,
"d": true
}
"#;
let rego = Interpreter::new();
rego.set_input_json(input);
let result = rego.query("input.a").unwrap();
println!("{}", result.to_str().unwrap());sourcepub fn set_input(&self, input: &Input) -> Result<(), String>
pub fn set_input(&self, input: &Input) -> Result<(), String>
Sets the input for the current policy directly.
See Input for more information.
sourcepub fn set_debug_enabled(&self, enabled: bool)
pub fn set_debug_enabled(&self, enabled: bool)
Sets whether the Rego interpreter is in debug mode.
When debug mode is enabled, the Rego interpreter will output extensive debugging information about the compliation process, including intermediary ASTs and the generated bytecode. This is mostly useful for debugging the Rego compiler itself, and is not useful for debugging Rego policies.
sourcepub fn get_debug_enabled(&self) -> bool
pub fn get_debug_enabled(&self) -> bool
Returns whether the Rego interpreter is in debug mode.
sourcepub fn set_debug_path(&self, path: &Path) -> Result<(), String>
pub fn set_debug_path(&self, path: &Path) -> Result<(), String>
Sets the path to the directory where the Rego interpreter will write debug AST files.
This is only useful when debug mode is enabled.
sourcepub fn set_well_formed_checks_enabled(&self, enabled: bool)
pub fn set_well_formed_checks_enabled(&self, enabled: bool)
Sets whether the Rego interpreter will perform well-formedness checks.
When enabled, the Rego interpreter will perform well-formedness checks on the AST during each pass of the compiler.
sourcepub fn get_well_formed_checks_enabled(&self) -> bool
pub fn get_well_formed_checks_enabled(&self) -> bool
Returns whether the Rego interpreter will perform well-formedness checks.
sourcepub fn set_strict_built_in_errors(&self, enabled: bool)
pub fn set_strict_built_in_errors(&self, enabled: bool)
Sets whether the interpreter will forward errors thrown by the built-ins.
By default, the Rego interpreter will catch errors thrown by the built-ins and return them as an Undefined result. When this is enabled, the interpreter will instead forward the error to the caller.
sourcepub fn get_strict_built_in_errors(&self) -> bool
pub fn get_strict_built_in_errors(&self) -> bool
Returns whether the interpreter will forward errors thrown by the built-ins.
sourcepub fn is_built_in(&self, name: &str) -> bool
pub fn is_built_in(&self, name: &str) -> bool
Returns whether the interpreter has a built-in with the given name.
§Example
let rego = Interpreter::new();
println!("{}", rego.is_built_in("json.unmarshal"));sourcepub fn query(&self, query: &str) -> Result<Output, String>
pub fn query(&self, query: &str) -> Result<Output, String>
This method performs a query against the current set of base and virtual documents.
While the Rego interpreter can be used to perform simple queries, in most cases
users will want to load one or more base documents (using Self::add_data_json() or
Self::add_data_json_file()) and one or more Rego modules (using Self::add_module() or
Self::add_module_file()). Then, multiple queries can be performed by providing an input
(using Self::set_input_json() or Self::set_input_json_file()) and then calling this
method.
§Example
let input0 = r#"{"a": 10}"#;
let input1 = r#"{"a": 4}"#;
let input2 = r#"{"a": 7}"#;
let multi = r#"
package multi
default a := 0
a := val {
input.a > 0
input.a < 10
input.a % 2 == 1
val := input.a * 10
} {
input.a > 0
input.a < 10
input.a % 2 == 0
val := input.a * 10 + 1
}
a := input.a / 10 {
input.a >= 10
}
"#;
let rego = Interpreter::new();
rego.add_module("multi", multi);
rego.set_input_json(input0);
let result = rego.query("data.multi.a").unwrap();
println!("{}", result.to_str().unwrap());
rego.set_input_json(input1);
let result = rego.query("data.multi.a").unwrap();
println!("{}", result.to_str().unwrap());
rego.set_input_json(input2);
let result = rego.query("data.multi.a").unwrap();
println!("{}", result.to_str().unwrap());sourcepub fn build<T: AsRef<str>>(
&self,
query: &Option<T>,
entrypoints: &[T],
) -> Result<Bundle, String>
pub fn build<T: AsRef<str>>( &self, query: &Option<T>, entrypoints: &[T], ) -> Result<Bundle, String>
Build a bundle from the current base and virtual documents, along
with query and the provided entrypoints. There must be at least
one entrypoint or a query in order for the build to be successful.
§Example
let input0 = r#"{
"x": 104,
"y": 119
}"#;
let data = r#"{
"a": 7,
"b": 13
}"#;
let module = r#"
package example
foo := data.a * input.x + data.b * input.y
bar := data.b * input.x + data.a * input.y
"#;
let rego_build = Interpreter::new();
rego_build.add_data_json(data);
rego_build.add_module("example.rego", module);
let bundle = rego_build.build(&Some("x=data.example.foo + data.example.bar"),
&["example/foo", "example/bar"]).expect("Unable to build bundle");
let rego_run = Interpreter::new();
rego_run.set_input_json(input0);
let result = rego_run.query_bundle(&bundle).expect("Failed bundle query");
let x = result.binding("x").unwrap();
println!("x = {}", x.json().unwrap());
let result = rego_run.query_bundle_entrypoint(&bundle, "example/foo").expect("Failed bundle entrypoint query");
println!("{}", result.to_str().unwrap());sourcepub fn load_bundle(
&self,
path: &Path,
format: BundleFormat,
) -> Result<Bundle, String>
pub fn load_bundle( &self, path: &Path, format: BundleFormat, ) -> Result<Bundle, String>
Loads a bundle from the disk.
sourcepub fn save_bundle(
&self,
path: &Path,
bundle: &Bundle,
format: BundleFormat,
) -> Result<(), String>
pub fn save_bundle( &self, path: &Path, bundle: &Bundle, format: BundleFormat, ) -> Result<(), String>
Saves a bundle to the disk.
There are two modes for bundle serialization. The JSON serialization scheme creates
a directory at the specified path and then writes at least two files: plan.json
(which contains the compiled virtual documents and plans for execution) and
data.json (which contains the base documents merged into a single JSON hierarchy).
Module source files will also be copied into the directory.
The second mode is binary serialization. This uses the Rego Binary Bundle format to create a single file which contains all the bundle information.
§Example
let rego_build = Interpreter::new();
let bundle = rego_build.build(&Some("a=1"), &[]).expect("Failed to build bundle");
let mut bundle_dir = env::temp_dir();
bundle_dir.push("bundle");
let mut bundle_file = env::temp_dir();
bundle_file.push("bundle.rbb");
rego_build.save_bundle(&bundle_dir, &bundle, BundleFormat::JSON).expect("Unable to save bundle");
rego_build.save_bundle(&bundle_file, &bundle, BundleFormat::Binary).expect("Unable to save binary bundle");
let rego_run = Interpreter::new();
let bundle = rego_run.load_bundle(&bundle_dir, BundleFormat::JSON).expect("Unable to load bundle from disk");
let result = rego_run.query_bundle(&bundle).expect("Failed bundle query");
let a = result.binding("a").unwrap();
println!("a = {}", a.json().unwrap());
let bundle = rego_run.load_bundle(&bundle_file, BundleFormat::Binary).expect("Unable to load bundle from disk");
let result = rego_run.query_bundle(&bundle).expect("Failed bundle query");
let a = result.binding("a").unwrap();
println!("a = {}", a.json().unwrap());sourcepub fn query_bundle_entrypoint(
&self,
bundle: &Bundle,
entrypoint: &str,
) -> Result<Output, String>
pub fn query_bundle_entrypoint( &self, bundle: &Bundle, entrypoint: &str, ) -> Result<Output, String>
Performs a query using the compiled policy in the bundle.
This method requires that the entrypoint specified by entrypoint
was provided to Interpreter::build(). Otherwise, it will fail.
sourcepub fn query_bundle(&self, bundle: &Bundle) -> Result<Output, String>
pub fn query_bundle(&self, bundle: &Bundle) -> Result<Output, String>
Performs a query using the compiled policy in the bundle.
This method requires that a query was provided to Interpreter::build().
Otherwise, it will fail.