diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 0f476bcb..f9444bf7 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -8,8 +8,8 @@ version: 2 updates: # All Rust/Cargo directories are grouped into a single entry so that - # when a dependency is updated, Dependabot creates ONE PR that bumps it - # across the root workspace AND every binding, preventing version skew. + # when a dependency is updated, Dependabot bumps it across the root + # workspace AND every binding, preventing version skew. - package-ecosystem: "cargo" directories: - "/" @@ -22,10 +22,6 @@ updates: interval: "weekly" commit-message: prefix: "build(deps)" - groups: - rust-dependencies: - patterns: - - "*" # Ignore vendored mimalloc crates; updates are managed manually. ignore: - dependency-name: "regorus-mimalloc" diff --git a/bindings/java/src/lib.rs b/bindings/java/src/lib.rs index 7f6a1a53..9bd64395 100644 --- a/bindings/java/src/lib.rs +++ b/bindings/java/src/lib.rs @@ -4,8 +4,9 @@ use anyhow::Result; use core::num::{NonZeroU32, NonZeroUsize}; use jni::objects::{JBooleanArray, JByteArray, JClass, JObject, JObjectArray, JString}; +use jni::strings::JNIString; use jni::sys::{jboolean, jbooleanArray, jbyteArray, jlong, jobjectArray, jstring}; -use jni::JNIEnv; +use jni::{jni_str, Env, EnvUnowned, Outcome}; use regorus::languages::rego::compiler::Compiler; use regorus::rvm::program::{ @@ -17,7 +18,7 @@ use std::sync::Arc; #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeNewEngine( - _env: JNIEnv, + _env: EnvUnowned, _class: JClass, ) -> jlong { let engine = Engine::new(); @@ -26,7 +27,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeNewEngine( #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeClone( - _env: JNIEnv, + _env: EnvUnowned, _class: JClass, engine_ptr: jlong, ) -> jlong { @@ -37,7 +38,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeClone( #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeSetRegoV0( - env: JNIEnv, + env: EnvUnowned, _class: JClass, engine_ptr: jlong, enable: bool, @@ -51,7 +52,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeSetRegoV0( #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeAddPolicy( - env: JNIEnv, + env: EnvUnowned, _class: JClass, engine_ptr: jlong, path: JString, @@ -59,9 +60,9 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeAddPolicy( ) -> jstring { let res = throw_err(env, |env| { let engine = unsafe { &mut *(engine_ptr as *mut Engine) }; - let path: String = env.get_string(&path)?.into(); - let rego: String = env.get_string(®o)?.into(); - let pkg = env.new_string(engine.add_policy(path, rego)?)?; + let path: String = path.try_to_string(env)?; + let rego: String = rego.try_to_string(env)?; + let pkg = JString::new(env, engine.add_policy(path, rego)?)?; Ok(pkg.into_raw()) }); @@ -73,15 +74,15 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeAddPolicy( #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeAddPolicyFromFile( - env: JNIEnv, + env: EnvUnowned, _class: JClass, engine_ptr: jlong, path: JString, ) -> jstring { let res = throw_err(env, |env| { let engine = unsafe { &mut *(engine_ptr as *mut Engine) }; - let path: String = env.get_string(&path)?.into(); - let pkg = env.new_string(engine.add_policy_from_file(path)?)?; + let path: String = path.try_to_string(env)?; + let pkg = JString::new(env, engine.add_policy_from_file(path)?)?; Ok(pkg.into_raw()) }); @@ -93,14 +94,14 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeAddPolicyFromFile #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeGetPackages( - env: JNIEnv, + env: EnvUnowned, _class: JClass, engine_ptr: jlong, ) -> jstring { let res = throw_err(env, |env| { let engine = unsafe { &mut *(engine_ptr as *mut Engine) }; let packages = engine.get_packages()?; - let packages_json = env.new_string(serde_json::to_string_pretty(&packages)?)?; + let packages_json = JString::new(env, serde_json::to_string_pretty(&packages)?)?; Ok(packages_json.into_raw()) }); @@ -112,14 +113,14 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeGetPackages( #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeGetPolicies( - env: JNIEnv, + env: EnvUnowned, _class: JClass, engine_ptr: jlong, ) -> jstring { let res = throw_err(env, |env| { let engine = unsafe { &mut *(engine_ptr as *mut Engine) }; let policies = engine.get_policies_as_json()?; - let policies_json = env.new_string(&policies)?; + let policies_json = JString::new(env, &policies)?; Ok(policies_json.into_raw()) }); @@ -131,7 +132,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeGetPolicies( #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeClearData( - env: JNIEnv, + env: EnvUnowned, _class: JClass, engine_ptr: jlong, ) { @@ -144,14 +145,14 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeClearData( #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeAddDataJson( - env: JNIEnv, + env: EnvUnowned, _class: JClass, engine_ptr: jlong, data: JString, ) { let _ = throw_err(env, |env| { let engine = unsafe { &mut *(engine_ptr as *mut Engine) }; - let data: String = env.get_string(&data)?.into(); + let data: String = data.try_to_string(env)?; engine.add_data_json(&data)?; Ok(()) }); @@ -159,14 +160,14 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeAddDataJson( #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeAddDataJsonFromFile( - env: JNIEnv, + env: EnvUnowned, _class: JClass, engine_ptr: jlong, path: JString, ) { let _ = throw_err(env, |env| { let engine = unsafe { &mut *(engine_ptr as *mut Engine) }; - let path: String = env.get_string(&path)?.into(); + let path: String = path.try_to_string(env)?; engine.add_data(Value::from_json_file(path)?)?; Ok(()) }); @@ -174,14 +175,14 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeAddDataJsonFromFi #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeSetInputJson( - env: JNIEnv, + env: EnvUnowned, _class: JClass, engine_ptr: jlong, input: JString, ) { let _ = throw_err(env, |env| { let engine = unsafe { &mut *(engine_ptr as *mut Engine) }; - let input: String = env.get_string(&input)?.into(); + let input: String = input.try_to_string(env)?; engine.set_input_json(&input)?; Ok(()) }); @@ -189,14 +190,14 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeSetInputJson( #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeSetInputJsonFromFile( - env: JNIEnv, + env: EnvUnowned, _class: JClass, engine_ptr: jlong, path: JString, ) { let _ = throw_err(env, |env| { let engine = unsafe { &mut *(engine_ptr as *mut Engine) }; - let path: String = env.get_string(&path)?.into(); + let path: String = path.try_to_string(env)?; engine.set_input(Value::from_json_file(path)?); Ok(()) }); @@ -204,16 +205,16 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeSetInputJsonFromF #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeEvalQuery( - env: JNIEnv, + env: EnvUnowned, _class: JClass, engine_ptr: jlong, query: JString, ) -> jstring { let res = throw_err(env, |env| { let engine = unsafe { &mut *(engine_ptr as *mut Engine) }; - let query: String = env.get_string(&query)?.into(); + let query: String = query.try_to_string(env)?; let results = engine.eval_query(query, false)?; - let output = env.new_string(serde_json::to_string(&results)?)?; + let output = JString::new(env, serde_json::to_string(&results)?)?; Ok(output.into_raw()) }); @@ -225,16 +226,16 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeEvalQuery( #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeEvalRule( - env: JNIEnv, + env: EnvUnowned, _class: JClass, engine_ptr: jlong, rule: JString, ) -> jstring { let res = throw_err(env, |env| { let engine = unsafe { &mut *(engine_ptr as *mut Engine) }; - let rule: String = env.get_string(&rule)?.into(); + let rule: String = rule.try_to_string(env)?; let value = engine.eval_rule(rule)?; - let output = env.new_string(value.to_json_str()?)?; + let output = JString::new(env, value.to_json_str()?)?; Ok(output.into_raw()) }); @@ -247,7 +248,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeEvalRule( #[no_mangle] #[cfg(feature = "coverage")] pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeSetEnableCoverage( - env: JNIEnv, + env: EnvUnowned, _class: JClass, engine_ptr: jlong, enable: bool, @@ -262,14 +263,14 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeSetEnableCoverage #[no_mangle] #[cfg(feature = "coverage")] pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeGetCoverageReport( - env: JNIEnv, + env: EnvUnowned, _class: JClass, engine_ptr: jlong, ) -> jstring { let res = throw_err(env, |env| { let engine = unsafe { &mut *(engine_ptr as *mut Engine) }; let report = engine.get_coverage_report()?; - let output = env.new_string(serde_json::to_string_pretty(&report)?)?; + let output = JString::new(env, serde_json::to_string_pretty(&report)?)?; Ok(output.into_raw()) }); @@ -282,14 +283,14 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeGetCoverageReport #[no_mangle] #[cfg(feature = "coverage")] pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeGetCoverageReportPretty( - env: JNIEnv, + env: EnvUnowned, _class: JClass, engine_ptr: jlong, ) -> jstring { let res = throw_err(env, |env| { let engine = unsafe { &mut *(engine_ptr as *mut Engine) }; let report = engine.get_coverage_report()?.to_string_pretty()?; - let output = env.new_string(&report)?; + let output = JString::new(env, &report)?; Ok(output.into_raw()) }); @@ -302,7 +303,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeGetCoverageReport #[no_mangle] #[cfg(feature = "coverage")] pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeClearCoverageData( - env: JNIEnv, + env: EnvUnowned, _class: JClass, engine_ptr: jlong, ) { @@ -315,7 +316,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeClearCoverageData #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeSetGatherPrints( - env: JNIEnv, + env: EnvUnowned, _class: JClass, engine_ptr: jlong, b: bool, @@ -329,14 +330,14 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeSetGatherPrints( #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeTakePrints( - env: JNIEnv, + env: EnvUnowned, _class: JClass, engine_ptr: jlong, ) -> jstring { let res = throw_err(env, |env| { let engine = unsafe { &mut *(engine_ptr as *mut Engine) }; let prints = engine.take_prints()?; - let output = env.new_string(serde_json::to_string_pretty(&prints)?)?; + let output = JString::new(env, serde_json::to_string_pretty(&prints)?)?; Ok(output.into_raw()) }); @@ -349,14 +350,14 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeTakePrints( #[no_mangle] #[cfg(feature = "ast")] pub extern "system" fn Java_com_microsoft_regorus_Engine_getAstAsJson( - env: JNIEnv, + env: EnvUnowned, _class: JClass, engine_ptr: jlong, ) -> jstring { let res = throw_err(env, |env| { let engine = unsafe { &mut *(engine_ptr as *mut Engine) }; let ast = engine.get_ast_as_json()?; - let output = env.new_string(&ast)?; + let output = JString::new(env, &ast)?; Ok(output.into_raw()) }); @@ -368,7 +369,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_getAstAsJson( #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeSetPolicyLengthConfig( - env: JNIEnv, + env: EnvUnowned, _class: JClass, engine_ptr: jlong, max_col: u32, @@ -391,7 +392,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeSetPolicyLengthCo #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeClearPolicyLengthConfig( - _env: JNIEnv, + _env: EnvUnowned, _class: JClass, engine_ptr: jlong, ) { @@ -402,7 +403,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeClearPolicyLength #[cfg(feature = "cache")] #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_CacheConfig_nativeSetCacheConfig( - _env: JNIEnv, + _env: EnvUnowned, _class: JClass, regex: jlong, glob: jlong, @@ -424,7 +425,7 @@ pub extern "system" fn Java_com_microsoft_regorus_CacheConfig_nativeSetCacheConf #[cfg(feature = "cache")] #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_CacheConfig_nativeClearCache( - _env: JNIEnv, + _env: EnvUnowned, _class: JClass, ) { regorus::cache::clear(); @@ -432,7 +433,7 @@ pub extern "system" fn Java_com_microsoft_regorus_CacheConfig_nativeClearCache( #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeDestroyEngine( - _env: JNIEnv, + _env: EnvUnowned, _class: JClass, engine_ptr: jlong, ) { @@ -443,7 +444,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeDestroyEngine( #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Program_nativeCompileFromModules( - env: JNIEnv, + env: EnvUnowned, _class: JClass, data_json: JString, module_ids: jobjectArray, @@ -451,7 +452,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Program_nativeCompileFromModul entry_points: jobjectArray, ) -> jlong { let res = throw_err(env, |env| { - let data_json: String = env.get_string(&data_json)?.into(); + let data_json: String = data_json.try_to_string(env)?; let data = Value::from_json_str(&data_json)?; let ids = get_string_array(env, module_ids)?; @@ -487,7 +488,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Program_nativeCompileFromModul #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Program_nativeCompileFromEngine( - env: JNIEnv, + env: EnvUnowned, _class: JClass, engine_ptr: jlong, entry_points: jobjectArray, @@ -512,7 +513,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Program_nativeCompileFromEngin #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Program_nativeGenerateListing( - env: JNIEnv, + env: EnvUnowned, _class: JClass, program_ptr: jlong, ) -> jstring { @@ -520,7 +521,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Program_nativeGenerateListing( let program = unsafe { &*(program_ptr as *mut Arc) }; let listing = generate_assembly_listing(program.as_ref(), &AssemblyListingConfig::default()); - let output = env.new_string(&listing)?; + let output = JString::new(env, &listing)?; Ok(output.into_raw()) }); @@ -532,7 +533,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Program_nativeGenerateListing( #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Program_nativeSerializeBinary( - env: JNIEnv, + env: EnvUnowned, _class: JClass, program_ptr: jlong, ) -> jbyteArray { @@ -556,7 +557,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Program_nativeSerializeBinary( /// for the duration of the call. They must come from the JVM for the current /// thread and not be used after this function returns. pub unsafe extern "system" fn Java_com_microsoft_regorus_Program_nativeDeserializeBinary( - env: JNIEnv, + env: EnvUnowned, _class: JClass, data: jbyteArray, is_partial: jbooleanArray, @@ -566,7 +567,7 @@ pub unsafe extern "system" fn Java_com_microsoft_regorus_Program_nativeDeseriali return Err(anyhow::anyhow!("data must not be null")); } - let data = unsafe { JByteArray::from_raw(data) }; + let data = unsafe { JByteArray::from_raw(env, data) }; let bytes = env.convert_byte_array(&data)?; let (program, partial) = match RvmProgram::deserialize_binary(&bytes).map_err(|e| anyhow::anyhow!(e))? { @@ -575,11 +576,15 @@ pub unsafe extern "system" fn Java_com_microsoft_regorus_Program_nativeDeseriali }; if !is_partial.is_null() { - let is_partial = unsafe { JBooleanArray::from_raw(is_partial) }; - let len = env.get_array_length(&is_partial)?; + let is_partial = unsafe { JBooleanArray::from_raw(env, is_partial) }; + let len = is_partial.len(env)?; if len > 0 { - let value: [jboolean; 1] = [if partial { 1 } else { 0 }]; - env.set_boolean_array_region(&is_partial, 0, &value)?; + let value: [jboolean; 1] = [if partial { + jni::sys::JNI_TRUE + } else { + jni::sys::JNI_FALSE + }]; + is_partial.set_region(env, 0, &value)?; } } @@ -591,7 +596,7 @@ pub unsafe extern "system" fn Java_com_microsoft_regorus_Program_nativeDeseriali #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Program_nativeDrop( - _env: JNIEnv, + _env: EnvUnowned, _class: JClass, program_ptr: jlong, ) { @@ -602,7 +607,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Program_nativeDrop( #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Rvm_nativeNew( - _env: JNIEnv, + _env: EnvUnowned, _class: JClass, ) -> jlong { let vm = RegoVM::new(); @@ -611,7 +616,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Rvm_nativeNew( #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Rvm_nativeLoadProgram( - env: JNIEnv, + env: EnvUnowned, _class: JClass, vm_ptr: jlong, program_ptr: jlong, @@ -626,14 +631,14 @@ pub extern "system" fn Java_com_microsoft_regorus_Rvm_nativeLoadProgram( #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Rvm_nativeSetDataJson( - env: JNIEnv, + env: EnvUnowned, _class: JClass, vm_ptr: jlong, data_json: JString, ) { let _ = throw_err(env, |env| { let vm = unsafe { &mut *(vm_ptr as *mut RegoVM) }; - let data_json: String = env.get_string(&data_json)?.into(); + let data_json: String = data_json.try_to_string(env)?; let data = Value::from_json_str(&data_json)?; vm.set_data(data)?; Ok(()) @@ -642,14 +647,14 @@ pub extern "system" fn Java_com_microsoft_regorus_Rvm_nativeSetDataJson( #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Rvm_nativeSetInputJson( - env: JNIEnv, + env: EnvUnowned, _class: JClass, vm_ptr: jlong, input_json: JString, ) { let _ = throw_err(env, |env| { let vm = unsafe { &mut *(vm_ptr as *mut RegoVM) }; - let input_json: String = env.get_string(&input_json)?.into(); + let input_json: String = input_json.try_to_string(env)?; let input = Value::from_json_str(&input_json)?; vm.set_input(input); Ok(()) @@ -658,7 +663,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Rvm_nativeSetInputJson( #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Rvm_nativeSetExecutionMode( - env: JNIEnv, + env: EnvUnowned, _class: JClass, vm_ptr: jlong, mode: u8, @@ -677,14 +682,14 @@ pub extern "system" fn Java_com_microsoft_regorus_Rvm_nativeSetExecutionMode( #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Rvm_nativeExecute( - env: JNIEnv, + env: EnvUnowned, _class: JClass, vm_ptr: jlong, ) -> jstring { let res = throw_err(env, |env| { let vm = unsafe { &mut *(vm_ptr as *mut RegoVM) }; let result = vm.execute()?; - let output = env.new_string(result.to_json_str()?)?; + let output = JString::new(env, result.to_json_str()?)?; Ok(output.into_raw()) }); @@ -696,16 +701,16 @@ pub extern "system" fn Java_com_microsoft_regorus_Rvm_nativeExecute( #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Rvm_nativeExecuteEntryPoint( - env: JNIEnv, + env: EnvUnowned, _class: JClass, vm_ptr: jlong, entry_point: JString, ) -> jstring { let res = throw_err(env, |env| { let vm = unsafe { &mut *(vm_ptr as *mut RegoVM) }; - let entry_point: String = env.get_string(&entry_point)?.into(); + let entry_point: String = entry_point.try_to_string(env)?; let result = vm.execute_entry_point_by_name(&entry_point)?; - let output = env.new_string(result.to_json_str()?)?; + let output = JString::new(env, result.to_json_str()?)?; Ok(output.into_raw()) }); @@ -717,7 +722,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Rvm_nativeExecuteEntryPoint( #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Rvm_nativeResume( - env: JNIEnv, + env: EnvUnowned, _class: JClass, vm_ptr: jlong, resume_json: JString, @@ -726,13 +731,13 @@ pub extern "system" fn Java_com_microsoft_regorus_Rvm_nativeResume( let res = throw_err(env, |env| { let vm = unsafe { &mut *(vm_ptr as *mut RegoVM) }; let value = if has_value { - let resume_json: String = env.get_string(&resume_json)?.into(); + let resume_json: String = resume_json.try_to_string(env)?; Some(Value::from_json_str(&resume_json)?) } else { None }; let result = vm.resume(value)?; - let output = env.new_string(result.to_json_str()?)?; + let output = JString::new(env, result.to_json_str()?)?; Ok(output.into_raw()) }); @@ -744,13 +749,13 @@ pub extern "system" fn Java_com_microsoft_regorus_Rvm_nativeResume( #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Rvm_nativeGetExecutionState( - env: JNIEnv, + env: EnvUnowned, _class: JClass, vm_ptr: jlong, ) -> jstring { let res = throw_err(env, |env| { let vm = unsafe { &mut *(vm_ptr as *mut RegoVM) }; - let output = env.new_string(format!("{:?}", vm.execution_state()))?; + let output = JString::new(env, format!("{:?}", vm.execution_state()))?; Ok(output.into_raw()) }); @@ -762,7 +767,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Rvm_nativeGetExecutionState( #[no_mangle] pub extern "system" fn Java_com_microsoft_regorus_Rvm_nativeDrop( - _env: JNIEnv, + _env: EnvUnowned, _class: JClass, vm_ptr: jlong, ) { @@ -771,27 +776,57 @@ pub extern "system" fn Java_com_microsoft_regorus_Rvm_nativeDrop( } } -fn throw_err(mut env: JNIEnv, mut f: impl FnMut(&mut JNIEnv) -> Result) -> Result { - match f(&mut env) { - Ok(val) => Ok(val), - Err(err) => { - env.throw(err.to_string())?; +fn throw_err(mut env: EnvUnowned, f: impl FnOnce(&mut Env) -> Result) -> Result { + let outcome = env.with_env(|env| -> Result { + match f(env) { + Ok(val) => Ok(val), + Err(err) => { + if let Err(throw_err) = env.throw_new( + jni_str!("java/lang/RuntimeException"), + JNIString::new(err.to_string()), + ) { + return Err(anyhow::anyhow!( + "Failed to throw Java RuntimeException for error '{err}': {throw_err}" + )); + } + Err(err) + } + } + }); + match outcome.into_outcome() { + Outcome::Ok(val) => Ok(val), + Outcome::Err(err) => Err(err), + Outcome::Panic(payload) => { + let msg = payload + .downcast_ref::() + .map(|s| s.as_str()) + .or_else(|| payload.downcast_ref::<&str>().copied()) + .unwrap_or("unknown panic"); + let err = anyhow::anyhow!("panic: {msg}"); + // Try to surface the panic as a Java exception. + let _ = env.with_env(|env| -> Result<()> { + env.throw_new( + jni_str!("java/lang/RuntimeException"), + JNIString::new(format!("Rust panic: {msg}")), + )?; + Ok(()) + }); Err(err) } } } -fn get_string_array(env: &mut JNIEnv, array: jobjectArray) -> Result> { +fn get_string_array(env: &mut Env, array: jobjectArray) -> Result> { if array.is_null() { return Ok(Vec::new()); } - let array = unsafe { JObjectArray::from_raw(array) }; - let len = env.get_array_length(&array)?; - let mut values = Vec::with_capacity(len as usize); + let array = unsafe { JObjectArray::::from_raw(env, array) }; + let len = array.len(env)?; + let mut values = Vec::with_capacity(len); for i in 0..len { - let obj = env.get_object_array_element(&array, i)?; - let jstr = JString::from(obj); - let value: String = env.get_string(&jstr)?.into(); + let obj = array.get_element(env, i)?; + let jstr = unsafe { JString::from_raw(env, obj.into_raw()) }; + let value: String = jstr.try_to_string(env)?; values.push(value); } Ok(values) diff --git a/bindings/python/src/lib.rs b/bindings/python/src/lib.rs index bff50613..9943c881 100644 --- a/bindings/python/src/lib.rs +++ b/bindings/python/src/lib.rs @@ -44,7 +44,7 @@ impl Default for Engine { fn from(ob: &Bound<'_, PyAny>) -> Result { // dicts - Ok(if let Ok(dict) = ob.downcast::() { + Ok(if let Ok(dict) = ob.cast::() { let mut map = BTreeMap::new(); for (k, v) in dict { map.insert(from(&k)?, from(&v)?); @@ -52,7 +52,7 @@ fn from(ob: &Bound<'_, PyAny>) -> Result { map.into() } // set - else if let Ok(pset) = ob.downcast::() { + else if let Ok(pset) = ob.cast::() { let mut set = BTreeSet::new(); for v in pset { set.insert(from(&v)?); @@ -60,7 +60,7 @@ fn from(ob: &Bound<'_, PyAny>) -> Result { set.into() } // frozen set - else if let Ok(pfset) = ob.downcast::() { + else if let Ok(pfset) = ob.cast::() { // let mut set = BTreeSet::new(); for v in pfset { @@ -69,13 +69,13 @@ fn from(ob: &Bound<'_, PyAny>) -> Result { set.into() } // lists and tuples - else if let Ok(plist) = ob.downcast::() { + else if let Ok(plist) = ob.cast::() { let mut array = Vec::new(); for v in plist { array.push(from(&v)?); } array.into() - } else if let Ok(ptuple) = ob.downcast::() { + } else if let Ok(ptuple) = ob.cast::() { let mut array = Vec::new(); for v in ptuple { array.push(from(&v)?); @@ -99,11 +99,11 @@ fn from(ob: &Bound<'_, PyAny>) -> Result { v.into() } // None - else if ob.downcast::().is_ok() { + else if ob.cast::().is_ok() { Value::Null } // Anything that is a sequence - else if let Ok(pseq) = ob.downcast::() { + else if let Ok(pseq) = ob.cast::() { let mut array = Vec::new(); for i in 0..pseq.len()? { array.push(from(&pseq.get_item(i)?)?); @@ -111,7 +111,7 @@ fn from(ob: &Bound<'_, PyAny>) -> Result { array.into() } // Anything that is a map - else if let Ok(pmap) = ob.downcast::() { + else if let Ok(pmap) = ob.cast::() { let mut map = BTreeMap::new(); let keys = pmap.keys()?; let values = pmap.values()?; @@ -128,7 +128,7 @@ fn from(ob: &Bound<'_, PyAny>) -> Result { }) } -fn to(mut v: Value, py: Python<'_>) -> Result { +fn to(mut v: Value, py: Python<'_>) -> Result> { let obj = match v { Value::Null => None::.into_bound_py_any(py), @@ -297,7 +297,7 @@ impl Engine { /// Evaluate query. /// /// * `query`: Rego expression to be evaluate. - pub fn eval_query(&mut self, query: String, py: Python<'_>) -> Result { + pub fn eval_query(&mut self, query: String, py: Python<'_>) -> Result> { let results = self.engine.eval_query(query, false)?; let rlist = PyList::empty(py); @@ -338,7 +338,7 @@ impl Engine { /// Evaluate rule. /// /// * `rule`: Full path to the rule. - pub fn eval_rule(&mut self, rule: String, py: Python<'_>) -> Result { + pub fn eval_rule(&mut self, rule: String, py: Python<'_>) -> Result> { to(self.engine.eval_rule(rule)?, py) } @@ -366,7 +366,7 @@ impl Engine { /// Note: When the engine is cloned, extensions share the same Python callable reference /// rather than being deep-copied. Stateful callables will share state across clones. pub fn add_extension(&mut self, path: String, nargs: u8, extension: Py) -> Result<()> { - Python::with_gil(|py| { + Python::attach(|py| { if !extension.bind(py).is_callable() { return Err(anyhow!("extension '{}' must be callable", path)); } @@ -377,8 +377,8 @@ impl Engine { let path_clone = path.clone(); let extension_impl = move |args: Vec| -> Result { - Python::with_gil(|py| { - let py_args_vec: Result> = + Python::attach(|py| { + let py_args_vec: Result>> = args.into_iter().map(|arg| to(arg, py)).collect(); let py_args = PyTuple::new(py, py_args_vec?)?; let py_result = func_ref.call1(py, py_args).map_err(|e| { diff --git a/bindings/wasm/Cargo.lock b/bindings/wasm/Cargo.lock index 3a82527a..2592fb46 100644 --- a/bindings/wasm/Cargo.lock +++ b/bindings/wasm/Cargo.lock @@ -354,11 +354,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi 6.0.0", "rand_core", "wasip2", "wasip3", + "wasm-bindgen", ] [[package]] @@ -1022,6 +1024,7 @@ version = "0.9.1" dependencies = [ "getrandom 0.2.17", "getrandom 0.3.4", + "getrandom 0.4.2", "regorus", "serde", "serde-wasm-bindgen", diff --git a/bindings/wasm/Cargo.toml b/bindings/wasm/Cargo.toml index 05b6b306..05afbb3c 100644 --- a/bindings/wasm/Cargo.toml +++ b/bindings/wasm/Cargo.toml @@ -48,9 +48,11 @@ serde-wasm-bindgen = "0.6" # Specify uuid as a mandatory dependency so as to enable `js` feature which is now required # when targeting wasm32-unknown-unknown. uuid = { version = "1.22.0", default-features = false, features = ["v4", "fast-rng", "js"]} -# Enable wasm_js. See https://docs.rs/getrandom/latest/getrandom/#webassembly-support -getrandom_for_jsonschema = { package = "getrandom", version = "0.2.15", features = ["std", "js"] } -getrandom = { version = "0.3.1", features = ["std", "wasm_js"] } +# Configure getrandom for WebAssembly: 0.2 uses the `js` feature, while 0.3+ use `wasm_js`. +# See https://docs.rs/getrandom/latest/getrandom/#webassembly-support +getrandom02 = { package = "getrandom", version = "0.2.15", features = ["std", "js"] } +getrandom03 = { package = "getrandom", version = "0.3.1", features = ["std", "wasm_js"] } +getrandom = { version = "0.4.2", features = ["wasm_js"] } [dev-dependencies] wasm-bindgen-test = "0.3.64" diff --git a/src/builtins/numbers.rs b/src/builtins/numbers.rs index 9cbc8aff..2c55fcb7 100644 --- a/src/builtins/numbers.rs +++ b/src/builtins/numbers.rs @@ -19,7 +19,7 @@ use crate::*; use anyhow::{bail, Result}; #[cfg(feature = "std")] -use rand::Rng; +use rand::RngExt; pub fn register(m: &mut builtins::BuiltinsMap<&'static str, builtins::BuiltinFcn>) { m.insert("abs", (abs, 1)); diff --git a/src/schema/meta.rs b/src/schema/meta.rs index 8c662229..17020ece 100644 --- a/src/schema/meta.rs +++ b/src/schema/meta.rs @@ -38,13 +38,12 @@ pub fn validate_schema(schema: &serde_json::Value) -> bool { /// Validates a schema definition against the Regorus meta-schema. /// Returns Ok(()) if valid, or Err with validation errors if invalid. pub fn validate_schema_detailed(schema: &serde_json::Value) -> Result<(), Vec> { - if let jsonschema::BasicOutput::Invalid(errors) = META_SCHEMA_VALIDATOR.apply(schema).basic() { - let msgs: alloc::collections::BTreeSet = errors - .iter() - .map(|e| format!("{}: {}", e.instance_location(), e.error_description())) - .collect(); - let msgs: Vec = msgs.into_iter().collect(); - return Err(msgs); + let msgs: alloc::collections::BTreeSet = META_SCHEMA_VALIDATOR + .iter_errors(schema) + .map(|e| format!("{}: {}", e.instance_path(), e)) + .collect(); + if !msgs.is_empty() { + return Err(msgs.into_iter().collect()); } Ok(())