Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions bindings/cpp/regorus.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ namespace regorus {
return std::unique_ptr<Engine>(new Engine(regorus_engine_clone(engine)));
}

Result prepare() {
return Result(regorus_engine_prepare(engine));
}

Result set_rego_v0(bool enable) {
return Result(regorus_engine_set_rego_v0(engine, enable));
}
Expand Down
12 changes: 12 additions & 0 deletions bindings/csharp/Regorus/Engine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,18 @@ public Engine Clone()
});
}

/// <summary>
/// Prepare internal evaluation structures without executing a query.
/// This is optional: if skipped, the first evaluation pays this setup cost.
/// </summary>
public void Prepare()
{
UseHandle(enginePtr =>
{
CheckAndDropResult(Regorus.Internal.API.regorus_engine_prepare((Regorus.Internal.RegorusEngine*)enginePtr));
});
}

public void SetStrictBuiltinErrors(bool strict)
{
UseHandle(enginePtr =>
Expand Down
6 changes: 6 additions & 0 deletions bindings/csharp/Regorus/NativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@ internal static unsafe partial class API
[DllImport(LibraryName, EntryPoint = "regorus_engine_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
internal static extern RegorusEngine* regorus_engine_clone(RegorusEngine* engine);

/// <summary>
/// Prepare a RegorusEngine for evaluation without executing a query.
/// </summary>
[DllImport(LibraryName, EntryPoint = "regorus_engine_prepare", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
internal static extern RegorusResult regorus_engine_prepare(RegorusEngine* engine);

/// <summary>
/// Compile an RVM program from the engine state with entry points.
/// </summary>
Expand Down
15 changes: 15 additions & 0 deletions bindings/ffi/src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,21 @@ pub extern "C" fn regorus_engine_clone(engine: *mut RegorusEngine) -> *mut Regor
}
}

/// Prepare a [`RegorusEngine`] for evaluation without executing a query.
///
/// This is optional. If not called, first eval performs the same setup.
/// If policy/data changes after preparation, setup is invalidated.
#[no_mangle]
pub extern "C" fn regorus_engine_prepare(engine: *mut RegorusEngine) -> RegorusResult {
with_unwind_guard(|| {
to_regorus_result(|| -> Result<()> {
let engine = to_ref(engine)?;
let mut guard = engine.try_write()?;
guard.prepare()
}())
})
}

#[no_mangle]
pub extern "C" fn regorus_engine_drop(engine: *mut RegorusEngine) {
if let Ok(e) = to_ref(engine) {
Expand Down
11 changes: 11 additions & 0 deletions bindings/go/pkg/regorus/mod.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@ func (e *Engine) Clone() *Engine {
return c
}

func (e *Engine) Prepare() error {
result := C.regorus_engine_prepare(e.e)
defer C.regorus_result_drop(result)

if result.status != C.Ok {
return fmt.Errorf("%s", C.GoString(result.error_message))
}

return nil
}

func (e *Engine) SetRegoV0(enable bool) error {
result := C.regorus_engine_set_rego_v0(e.e, C.bool(enable))
defer C.regorus_result_drop(result)
Expand Down
8 changes: 8 additions & 0 deletions bindings/java/com_microsoft_regorus_Engine.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 31 additions & 4 deletions bindings/java/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,30 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeNewEngine(

#[no_mangle]
pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeClone(
_env: EnvUnowned,
env: EnvUnowned,
_class: JClass,
engine_ptr: jlong,
) -> jlong {
let engine = unsafe { &mut *(engine_ptr as *mut Engine) };
let c = engine.clone();
Box::into_raw(Box::new(c)) as jlong
let res = throw_err(env, |_env| {
let engine = unsafe { &mut *get_engine_ptr(engine_ptr)? };
let c = engine.clone();
Ok(Box::into_raw(Box::new(c)) as jlong)
});

res.unwrap_or_default()
}

#[no_mangle]
pub extern "system" fn Java_com_microsoft_regorus_Engine_nativePrepare(
env: EnvUnowned,
_class: JClass,
engine_ptr: jlong,
) {
let _ = throw_err(env, |_env| {
let engine = unsafe { &mut *get_engine_ptr(engine_ptr)? };
engine.prepare()?;
Ok(())
});
}

#[no_mangle]
Expand Down Expand Up @@ -437,6 +454,9 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeDestroyEngine(
_class: JClass,
engine_ptr: jlong,
) {
if engine_ptr == 0 {
return;
}
unsafe {
let _engine = Box::from_raw(engine_ptr as *mut Engine);
}
Expand Down Expand Up @@ -816,6 +836,13 @@ fn throw_err<T>(mut env: EnvUnowned, f: impl FnOnce(&mut Env) -> Result<T>) -> R
}
}

fn get_engine_ptr(engine_ptr: jlong) -> Result<*mut Engine> {
if engine_ptr == 0 {
return Err(anyhow::anyhow!("Engine is closed"));
}
Ok(engine_ptr as *mut Engine)
}

fn get_string_array(env: &mut Env, array: jobjectArray) -> Result<Vec<String>> {
if array.is_null() {
return Ok(Vec::new());
Expand Down
65 changes: 42 additions & 23 deletions bindings/java/src/main/java/com/microsoft/regorus/Engine.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public class Engine implements AutoCloseable, Cloneable {
// if you update the native API.
private static native long nativeNewEngine();
private static native long nativeClone(long enginePtr);
private static native void nativePrepare(long enginePtr);
private static native void nativeSetRegoV0(long enginePtr, boolean enable);
private static native String nativeAddPolicy(long enginePtr, String path, String rego);
private static native String nativeAddPolicyFromFile(long enginePtr, String path);
Expand All @@ -45,7 +46,7 @@ public class Engine implements AutoCloseable, Cloneable {

// Pointer to Engine allocated on Rust's heap, all native methods works on
// engine expects this pointer. It is free'd in `close` method.
private final long enginePtr;
private long enginePtr;

/**
* Creates a new Regorus Engine.
Expand All @@ -63,7 +64,15 @@ public Engine() {
* Efficiently clones an Engine.
*/
public Engine clone() {
return new Engine(nativeClone(enginePtr));
return new Engine(nativeClone(requireOpen()));
}

/**
* Prepares internal evaluation structures without executing a query.
* Optional: if skipped, first evaluation performs the same setup.
*/
public void prepare() {
nativePrepare(requireOpen());
}

/**
Expand All @@ -73,7 +82,7 @@ public Engine clone() {
*
*/
public void setRegoV0(boolean enable) {
nativeSetRegoV0(enginePtr, enable);
nativeSetRegoV0(requireOpen(), enable);
}

/**
Expand All @@ -85,7 +94,7 @@ public void setRegoV0(boolean enable) {
* @return Rego package defined in the policy.
*/
public String addPolicy(String filename, String rego) {
return nativeAddPolicy(enginePtr, filename, rego);
return nativeAddPolicy(requireOpen(), filename, rego);
}

/**
Expand All @@ -96,7 +105,7 @@ public String addPolicy(String filename, String rego) {
* @return Rego package defined in the policy.
*/
public String addPolicyFromFile(String path) {
return nativeAddPolicyFromFile(enginePtr, path);
return nativeAddPolicyFromFile(requireOpen(), path);
}

/**
Expand All @@ -105,7 +114,7 @@ public String addPolicyFromFile(String path) {
* @return List of Rego packages as a JSON array of strings.
*/
public String getPackages() {
return nativeGetPackages(enginePtr);
return nativeGetPackages(requireOpen());
}

/**
Expand All @@ -114,14 +123,14 @@ public String getPackages() {
* @return List of Rego policies as a JSON array of sources.
*/
public String getPolicies() {
return nativeGetPolicies(enginePtr);
return nativeGetPolicies(requireOpen());
}

/**
* Clears the data document.
*/
public void clearData() {
nativeClearData(enginePtr);
nativeClearData(requireOpen());
}

/**
Expand All @@ -143,7 +152,7 @@ public void clearData() {
* @param data Inline data document.
*/
public void addDataJson(String data) throws RuntimeException {
nativeAddDataJson(enginePtr, data);
nativeAddDataJson(requireOpen(), data);
}

/**
Expand All @@ -160,7 +169,7 @@ public void addDataJson(String data) throws RuntimeException {
* @param path Path to JSON data document.
*/
public void addDataJsonFromFile(String path) throws RuntimeException {
nativeAddDataJsonFromFile(enginePtr, path);
nativeAddDataJsonFromFile(requireOpen(), path);
}

/**
Expand All @@ -169,7 +178,7 @@ public void addDataJsonFromFile(String path) throws RuntimeException {
* @param input inline JSON input.
*/
public void setInputJson(String input) {
nativeSetInputJson(enginePtr, input);
nativeSetInputJson(requireOpen(), input);
}

/**
Expand All @@ -178,7 +187,7 @@ public void setInputJson(String input) {
* @param path Path to JSON input.
*/
public void setInputJsonFromFile(String path) {
nativeSetInputJsonFromFile(enginePtr, path);
nativeSetInputJsonFromFile(requireOpen(), path);
}

/**
Expand All @@ -189,7 +198,7 @@ public void setInputJsonFromFile(String path) {
* @return Query results as a JSON string.
*/
public String evalQuery(String query) {
return nativeEvalQuery(enginePtr, query);
return nativeEvalQuery(requireOpen(), query);
}

/**
Expand All @@ -200,7 +209,7 @@ public String evalQuery(String query) {
* @return Value of the rule as a JSON string.
*/
public String evalRule(String rule) {
return nativeEvalRule(enginePtr, rule);
return nativeEvalRule(requireOpen(), rule);
}

/**
Expand All @@ -210,15 +219,15 @@ public String evalRule(String rule) {
*
*/
public void setEnableCoverage(boolean enable) {
nativeSetEnableCoverage(enginePtr, enable);
nativeSetEnableCoverage(requireOpen(), enable);
}

/**
* Clear coverage data.
*
*/
public void clearCoverageData() {
nativeClearCoverageData(enginePtr);
nativeClearCoverageData(requireOpen());
}

/**
Expand All @@ -228,7 +237,7 @@ public void clearCoverageData() {
*
*/
public String getCoverageReport() {
return nativeGetCoverageReport(enginePtr);
return nativeGetCoverageReport(requireOpen());
}

/**
Expand All @@ -238,7 +247,7 @@ public String getCoverageReport() {
*
*/
public String getCoverageReportPretty() {
return nativeGetCoverageReportPretty(enginePtr);
return nativeGetCoverageReportPretty(requireOpen());
}

/**
Expand All @@ -248,7 +257,7 @@ public String getCoverageReportPretty() {
*
*/
public void setGatherPrints(boolean b) {
nativeSetGatherPrints(enginePtr, b);
nativeSetGatherPrints(requireOpen(), b);
}

/**
Expand All @@ -258,7 +267,7 @@ public void setGatherPrints(boolean b) {
*
*/
public String takePrints() {
return nativeTakePrints(enginePtr);
return nativeTakePrints(requireOpen());
}

/**
Expand All @@ -267,24 +276,34 @@ public String takePrints() {
* @param config Policy length configuration.
*/
public void setPolicyLengthConfig(PolicyLengthConfig config) {
nativeSetPolicyLengthConfig(enginePtr, config.maxCol, config.maxFileBytes, config.maxLines);
nativeSetPolicyLengthConfig(requireOpen(), config.maxCol, config.maxFileBytes, config.maxLines);
}

/**
* Clear the policy length configuration, reverting to defaults.
*/
public void clearPolicyLengthConfig() {
nativeClearPolicyLengthConfig(enginePtr);
nativeClearPolicyLengthConfig(requireOpen());
}

long getPtr() {
return requireOpen();
}

private long requireOpen() {
if (enginePtr == 0) {
throw new IllegalStateException("Engine is closed");
}
return enginePtr;
}


@Override
public void close() {
nativeDestroyEngine(enginePtr);
if (enginePtr != 0) {
nativeDestroyEngine(enginePtr);
enginePtr = 0;
}
}

// Loading native library from JAR is adapted from:
Expand Down
Loading