From a9c9b5ce988132797b4969d910f3f557014d5a3d Mon Sep 17 00:00:00 2001 From: Yuhang Shi Date: Wed, 6 Dec 2023 15:38:32 +0800 Subject: [PATCH 1/4] refactor future Signed-off-by: Yuhang Shi --- packages/rust-core/Cargo.lock | 75 ++++++++--------- packages/rust-core/java/src/convert.rs | 53 ++++++++++++ packages/rust-core/java/src/future.rs | 77 +++++++++++++++++ packages/rust-core/java/src/lib.rs | 50 +---------- .../java/com/pleisto/FlappyAsyncRegistry.java | 35 ++++++++ .../java/com/pleisto/FlappyJniSandbox.java | 35 +------- packages/rust-core/java/src/sandbox.rs | 84 ++----------------- 7 files changed, 208 insertions(+), 201 deletions(-) create mode 100644 packages/rust-core/java/src/convert.rs create mode 100644 packages/rust-core/java/src/future.rs create mode 100644 packages/rust-core/java/src/main/java/com/pleisto/FlappyAsyncRegistry.java diff --git a/packages/rust-core/Cargo.lock b/packages/rust-core/Cargo.lock index 1420ca07..9756993d 100644 --- a/packages/rust-core/Cargo.lock +++ b/packages/rust-core/Cargo.lock @@ -79,30 +79,30 @@ checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" [[package]] name = "anstyle-parse" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +checksum = "a3a318f1f38d2418400f8209655bfd825785afd25aa30bb7ba6cc792e4596748" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.1" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" dependencies = [ "anstyle", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -195,9 +195,9 @@ dependencies = [ [[package]] name = "atomic-polyfill" -version = "0.1.11" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ff7eb3f316534d83a8a2c3d1674ace8a5a71198eba31e2e2b597833f699b28" +checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" dependencies = [ "critical-section", ] @@ -442,9 +442,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.10" +version = "4.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fffed7514f420abec6d183b1d3acfd9099c79c3a10a06ade4f8203f1411272" +checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2" dependencies = [ "clap_builder", "clap_derive", @@ -452,9 +452,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.9" +version = "4.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63361bae7eef3771745f02d8d892bec2fee5f6e34af316ba556e7f97a7069ff1" +checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb" dependencies = [ "anstream", "anstyle", @@ -1122,14 +1122,14 @@ checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "filetime" -version = "0.2.22" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.3.5", - "windows-sys 0.48.0", + "redox_syscall", + "windows-sys 0.52.0", ] [[package]] @@ -1575,9 +1575,9 @@ checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" [[package]] name = "heapless" -version = "0.7.16" +version = "0.7.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db04bc24a18b9ea980628ecf00e6c0264f3c1426dac36c00cb49b6fbad8b0743" +checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" dependencies = [ "atomic-polyfill", "hash32", @@ -1975,7 +1975,7 @@ checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" dependencies = [ "bitflags 2.4.1", "libc", - "redox_syscall 0.4.1", + "redox_syscall", ] [[package]] @@ -2468,9 +2468,9 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.60" +version = "0.10.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79a4c6c3a2b158f7f8f2a2fc5a969fa3a068df6fc9dbb4a43845436e3af7c800" +checksum = "6b8419dc8cc6d866deb801274bba2e6f8f6108c1bb7fcc10ee5ab864931dbb45" dependencies = [ "bitflags 2.4.1", "cfg-if", @@ -2509,9 +2509,9 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.96" +version = "0.9.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3812c071ba60da8b5677cc12bcb1d42989a65553772897a7e0355545a819838f" +checksum = "c3eaad34cdd97d81de97964fc7f29e2d104f483840d906ef56daa1912338460b" dependencies = [ "cc", "libc", @@ -2540,7 +2540,7 @@ checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.4.1", + "redox_syscall", "smallvec", "windows-targets 0.48.5", ] @@ -2642,9 +2642,9 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "portable-atomic" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bccab0e7fd7cc19f820a1c8c91720af652d0c88dc9664dd72aef2614f04af3b" +checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" [[package]] name = "powerfmt" @@ -2808,15 +2808,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.4.1" @@ -2976,9 +2967,9 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.6" +version = "0.17.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "684d5e6e18f669ccebf64a92236bb7db9a34f07be010e3627368182027180866" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" dependencies = [ "cc", "getrandom", @@ -3530,7 +3521,7 @@ checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ "cfg-if", "fastrand", - "redox_syscall 0.4.1", + "redox_syscall", "rustix", "windows-sys 0.48.0", ] @@ -5060,9 +5051,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.19" +version = "0.5.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b" +checksum = "b7e87b8dfbe3baffbe687eef2e164e32286eff31a5ee16463ce03d991643ec94" dependencies = [ "memchr", ] diff --git a/packages/rust-core/java/src/convert.rs b/packages/rust-core/java/src/convert.rs new file mode 100644 index 00000000..e1591d28 --- /dev/null +++ b/packages/rust-core/java/src/convert.rs @@ -0,0 +1,53 @@ +use std::collections::HashMap; + +use crate::Result; +use jni::objects::JMap; +use jni::objects::JObject; +use jni::objects::JString; +use jni::sys::jboolean; +use jni::sys::JNI_TRUE; +use jni::JNIEnv; + +pub(crate) fn jstring_to_string(env: &mut JNIEnv, s: &JString) -> Result { + let res = unsafe { env.get_string_unchecked(s)? }; + Ok(res.into()) +} + +pub(crate) fn jstring_to_option_string(env: &mut JNIEnv, s: &JString) -> Result> { + let s: String = jstring_to_string(env, s)?; + + if s.is_empty() { + Ok(Default::default()) + } else { + Ok(Some(s)) + } +} + +pub(crate) fn jboolean_to_bool(_env: &mut JNIEnv, bol: jboolean) -> Result { + Ok(bol == JNI_TRUE) +} + +pub(crate) fn jmap_to_vec_string_string( + env: &mut JNIEnv, + params: &JObject, +) -> Result> { + let envs: Vec<(String, String)> = jmap_to_hashmap(env, params)?.into_iter().collect(); + Ok(envs) +} + +pub(crate) fn jmap_to_hashmap( + env: &mut JNIEnv, + params: &JObject, +) -> Result> { + let map = JMap::from_env(env, params)?; + let mut iter = map.iter(env)?; + + let mut result: HashMap = HashMap::new(); + while let Some(e) = iter.next(env)? { + let k = JString::from(e.0); + let v = JString::from(e.1); + result.insert(env.get_string(&k)?.into(), env.get_string(&v)?.into()); + } + + Ok(result) +} diff --git a/packages/rust-core/java/src/future.rs b/packages/rust-core/java/src/future.rs new file mode 100644 index 00000000..2577f25d --- /dev/null +++ b/packages/rust-core/java/src/future.rs @@ -0,0 +1,77 @@ +use jni::objects::JObject; +use jni::objects::JValue; +use jni::objects::JValueOwned; +use jni::sys::jlong; +use jni::JNIEnv; + +use crate::get_current_env; +use crate::Result; + +fn make_object<'local>( + env: &mut JNIEnv<'local>, + value: JValueOwned<'local>, +) -> Result> { + let o = match value { + JValueOwned::Object(o) => o, + JValueOwned::Byte(_) => env.new_object("java/lang/Long", "(B)V", &[value.borrow()])?, + JValueOwned::Char(_) => env.new_object("java/lang/Char", "(C)V", &[value.borrow()])?, + JValueOwned::Short(_) => env.new_object("java/lang/Short", "(S)V", &[value.borrow()])?, + JValueOwned::Int(_) => env.new_object("java/lang/Integer", "(I)V", &[value.borrow()])?, + JValueOwned::Long(_) => env.new_object("java/lang/Long", "(J)V", &[value.borrow()])?, + JValueOwned::Bool(_) => env.new_object("java/lang/Boolean", "(Z)V", &[value.borrow()])?, + JValueOwned::Float(_) => env.new_object("java/lang/Float", "(F)V", &[value.borrow()])?, + JValueOwned::Double(_) => env.new_object("java/lang/Double", "(D)V", &[value.borrow()])?, + JValueOwned::Void => JObject::null(), + }; + Ok(o) +} + +pub(crate) fn complete_future(id: jlong, result: Result) { + let mut env = unsafe { get_current_env() }; + let future = get_future(&mut env, id).unwrap(); + match result { + Ok(result) => { + let result = make_object(&mut env, result).unwrap(); + env + .call_method( + future, + "complete", + "(Ljava/lang/Object;)Z", + &[JValue::Object(&result)], + ) + .unwrap() + } + Err(err) => { + let exception = err.to_exception(&mut env).unwrap(); + env + .call_method( + future, + "completeExceptionally", + "(Ljava/lang/Throwable;)Z", + &[JValue::Object(&exception)], + ) + .unwrap() + } + }; +} + +pub(crate) fn request_id(env: &mut JNIEnv) -> Result { + Ok( + env + .call_static_method("com/pleisto/FlappyAsyncRegistry", "requestId", "()J", &[])? + .j()?, + ) +} + +fn get_future<'local>(env: &mut JNIEnv<'local>, id: jlong) -> Result> { + Ok( + env + .call_static_method( + "com/pleisto/FlappyAsyncRegistry", + "get", + "(J)Ljava/util/concurrent/CompletableFuture;", + &[JValue::Long(id)], + )? + .l()?, + ) +} diff --git a/packages/rust-core/java/src/lib.rs b/packages/rust-core/java/src/lib.rs index bf41973e..381782bb 100644 --- a/packages/rust-core/java/src/lib.rs +++ b/packages/rust-core/java/src/lib.rs @@ -1,13 +1,7 @@ use std::cell::RefCell; -use std::collections::HashMap; use std::ffi::c_void; -use jni::objects::JMap; -use jni::objects::JObject; -use jni::objects::JString; -use jni::sys::jboolean; use jni::sys::jint; -use jni::sys::JNI_TRUE; use jni::sys::JNI_VERSION_1_8; use jni::JNIEnv; use jni::JavaVM; @@ -15,7 +9,9 @@ use once_cell::sync::OnceCell; use tokio::runtime::Builder; use tokio::runtime::Runtime; +mod convert; mod error; +mod future; mod sandbox; use mimalloc::MiMalloc; @@ -80,45 +76,3 @@ unsafe fn get_current_env<'local>() -> JNIEnv<'local> { unsafe fn get_global_runtime<'local>() -> &'local Runtime { RUNTIME.get_unchecked() } - -/// # Safety -/// -/// The caller must guarantee that the Object passed in is an instance -/// of `java.lang.String`, passing in anything else will lead to undefined behavior. -fn jstring_to_string(env: &mut JNIEnv, s: &JString) -> Result { - let res = unsafe { env.get_string_unchecked(s)? }; - Ok(res.into()) -} - -fn jstring_to_option_string(env: &mut JNIEnv, s: &JString) -> Result> { - let s: String = jstring_to_string(env, s)?; - - if s.is_empty() { - Ok(Default::default()) - } else { - Ok(Some(s)) - } -} - -fn jboolean_to_bool(_env: &mut JNIEnv, bol: jboolean) -> Result { - Ok(bol == JNI_TRUE) -} - -fn jmap_to_vec_string_string(env: &mut JNIEnv, params: &JObject) -> Result> { - let envs: Vec<(String, String)> = jmap_to_hashmap(env, params)?.into_iter().collect(); - Ok(envs) -} - -fn jmap_to_hashmap(env: &mut JNIEnv, params: &JObject) -> Result> { - let map = JMap::from_env(env, params)?; - let mut iter = map.iter(env)?; - - let mut result: HashMap = HashMap::new(); - while let Some(e) = iter.next(env)? { - let k = JString::from(e.0); - let v = JString::from(e.1); - result.insert(env.get_string(&k)?.into(), env.get_string(&v)?.into()); - } - - Ok(result) -} diff --git a/packages/rust-core/java/src/main/java/com/pleisto/FlappyAsyncRegistry.java b/packages/rust-core/java/src/main/java/com/pleisto/FlappyAsyncRegistry.java new file mode 100644 index 00000000..98cfb31c --- /dev/null +++ b/packages/rust-core/java/src/main/java/com/pleisto/FlappyAsyncRegistry.java @@ -0,0 +1,35 @@ +package com.pleisto; + +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; + +public enum FlappyAsyncRegistry { + INSTANCE; + + private final Map> registry = new ConcurrentHashMap<>(); + + static long requestId() { + final CompletableFuture f = new CompletableFuture<>(); + while (true) { + final long requestId = Math.abs(UUID.randomUUID().getLeastSignificantBits()); + final CompletableFuture prev = INSTANCE.registry.putIfAbsent(requestId, f); + if (prev == null) { + return requestId; + } + } + } + + static CompletableFuture get(long requestId) { + return INSTANCE.registry.get(requestId); + } + + static CompletableFuture take(long requestId) { + final CompletableFuture f = get(requestId); + if (f != null) { + f.whenComplete((r, e) -> INSTANCE.registry.remove(requestId)); + } + return (CompletableFuture) f; + } +} diff --git a/packages/rust-core/java/src/main/java/com/pleisto/FlappyJniSandbox.java b/packages/rust-core/java/src/main/java/com/pleisto/FlappyJniSandbox.java index 2a46e20b..279c5f0f 100644 --- a/packages/rust-core/java/src/main/java/com/pleisto/FlappyJniSandbox.java +++ b/packages/rust-core/java/src/main/java/com/pleisto/FlappyJniSandbox.java @@ -47,37 +47,6 @@ public FlappyJniSandboxInput(@NonNull String code) { } } - private enum AsyncRegistry { - INSTANCE; - - private final Map> registry = new ConcurrentHashMap<>(); - - @SuppressWarnings("unused") - private static long requestId() { - final CompletableFuture f = new CompletableFuture<>(); - while (true) { - final long requestId = Math.abs(UUID.randomUUID().getLeastSignificantBits()); - final CompletableFuture prev = INSTANCE.registry.putIfAbsent(requestId, f); - if (prev == null) { - return requestId; - } - } - } - - private static CompletableFuture get(long requestId) { - return INSTANCE.registry.get(requestId); - } - - @SuppressWarnings("unchecked") - private static CompletableFuture take(long requestId) { - final CompletableFuture f = get(requestId); - if (f != null) { - f.whenComplete((r, e) -> INSTANCE.registry.remove(requestId)); - } - return (CompletableFuture) f; - } - } - private static native long nativeEvalPythonCode( String code, boolean network, Map envs, String cache_path); @@ -87,11 +56,11 @@ private static native long nativeEvalPythonCode( public CompletableFuture nativePrepareSandbox() { final long requestId = nativePrepareSandbox(this.cachePath); - return AsyncRegistry.take(requestId); + return FlappyAsyncRegistry.take(requestId); } public CompletableFuture evalPythonCode(FlappyJniSandboxInput input) { final long requestId = nativeEvalPythonCode(input.code, input.network, input.envs, this.cachePath); - return AsyncRegistry.take(requestId); + return FlappyAsyncRegistry.take(requestId); } } diff --git a/packages/rust-core/java/src/sandbox.rs b/packages/rust-core/java/src/sandbox.rs index 526d8fbc..13bae9e4 100644 --- a/packages/rust-core/java/src/sandbox.rs +++ b/packages/rust-core/java/src/sandbox.rs @@ -11,88 +11,16 @@ use jni::sys::jlong; use jni::sys::jstring; use jni::JNIEnv; +use crate::convert::jboolean_to_bool; +use crate::convert::jmap_to_vec_string_string; +use crate::convert::jstring_to_option_string; +use crate::convert::jstring_to_string; +use crate::future::complete_future; +use crate::future::request_id; use crate::get_current_env; use crate::get_global_runtime; -use crate::jboolean_to_bool; -use crate::jmap_to_vec_string_string; -use crate::jstring_to_option_string; -use crate::jstring_to_string; use crate::Result; -fn make_object<'local>( - env: &mut JNIEnv<'local>, - value: JValueOwned<'local>, -) -> Result> { - let o = match value { - JValueOwned::Object(o) => o, - JValueOwned::Byte(_) => env.new_object("java/lang/Long", "(B)V", &[value.borrow()])?, - JValueOwned::Char(_) => env.new_object("java/lang/Char", "(C)V", &[value.borrow()])?, - JValueOwned::Short(_) => env.new_object("java/lang/Short", "(S)V", &[value.borrow()])?, - JValueOwned::Int(_) => env.new_object("java/lang/Integer", "(I)V", &[value.borrow()])?, - JValueOwned::Long(_) => env.new_object("java/lang/Long", "(J)V", &[value.borrow()])?, - JValueOwned::Bool(_) => env.new_object("java/lang/Boolean", "(Z)V", &[value.borrow()])?, - JValueOwned::Float(_) => env.new_object("java/lang/Float", "(F)V", &[value.borrow()])?, - JValueOwned::Double(_) => env.new_object("java/lang/Double", "(D)V", &[value.borrow()])?, - JValueOwned::Void => JObject::null(), - }; - Ok(o) -} - -fn complete_future(id: jlong, result: Result) { - let mut env = unsafe { get_current_env() }; - let future = get_future(&mut env, id).unwrap(); - match result { - Ok(result) => { - let result = make_object(&mut env, result).unwrap(); - env - .call_method( - future, - "complete", - "(Ljava/lang/Object;)Z", - &[JValue::Object(&result)], - ) - .unwrap() - } - Err(err) => { - let exception = err.to_exception(&mut env).unwrap(); - env - .call_method( - future, - "completeExceptionally", - "(Ljava/lang/Throwable;)Z", - &[JValue::Object(&exception)], - ) - .unwrap() - } - }; -} - -fn request_id(env: &mut JNIEnv) -> Result { - Ok( - env - .call_static_method( - "com/pleisto/FlappyJniSandbox$AsyncRegistry", - "requestId", - "()J", - &[], - )? - .j()?, - ) -} - -fn get_future<'local>(env: &mut JNIEnv<'local>, id: jlong) -> Result> { - Ok( - env - .call_static_method( - "com/pleisto/FlappyJniSandbox$AsyncRegistry", - "get", - "(J)Ljava/util/concurrent/CompletableFuture;", - &[JValue::Long(id)], - )? - .l()?, - ) -} - #[no_mangle] pub extern "system" fn Java_com_pleisto_FlappyJniSandbox_ping<'local>( env: JNIEnv<'local>, From 48c546bfb770f037e8a94a9b411d23d53f86caa7 Mon Sep 17 00:00:00 2001 From: Yuhang Shi Date: Wed, 6 Dec 2023 17:00:23 +0800 Subject: [PATCH 2/4] refactor java bindings Signed-off-by: Yuhang Shi --- .../workflows/java-bindings-build-common.yml | 2 +- packages/rust-core/Cargo.lock | 26 ++++++- packages/rust-core/java/Cargo.toml | 11 ++- packages/rust-core/java/README.md | 2 +- packages/rust-core/java/build.rs | 63 ++++++++++++++++ packages/rust-core/java/src/future.rs | 14 ++++ packages/rust-core/java/src/lib.rs | 3 + packages/rust-core/java/src/test_utils.rs | 72 +++++++++++++++++++ 8 files changed, 189 insertions(+), 4 deletions(-) create mode 100644 packages/rust-core/java/build.rs create mode 100644 packages/rust-core/java/src/test_utils.rs diff --git a/.github/workflows/java-bindings-build-common.yml b/.github/workflows/java-bindings-build-common.yml index ea407b93..a61bf29d 100644 --- a/.github/workflows/java-bindings-build-common.yml +++ b/.github/workflows/java-bindings-build-common.yml @@ -107,7 +107,7 @@ jobs: shell: bash run: | ./mvnw verify org.sonatype.plugins:nexus-staging-maven-plugin:deploy \ - -DskipTests=true \ + -DskipTests \ -Djni.classifier=${{ matrix.classifier }} \ -Dcargo-build.profile=release \ -DaltStagingDirectory=local-staging \ diff --git a/packages/rust-core/Cargo.lock b/packages/rust-core/Cargo.lock index 9756993d..80abd957 100644 --- a/packages/rust-core/Cargo.lock +++ b/packages/rust-core/Cargo.lock @@ -1181,7 +1181,9 @@ version = "0.1.0" dependencies = [ "anyhow", "flappy-common", + "flappy-java-bindings", "jni", + "lazy_static", "mimalloc", "num_cpus", "once_cell", @@ -1880,6 +1882,16 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +[[package]] +name = "java-locator" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90003f2fd9c52f212c21d8520f1128da0080bad6fff16b68fe6e7f2f0c3780c2" +dependencies = [ + "glob", + "lazy_static", +] + [[package]] name = "jni" version = "0.21.1" @@ -1889,7 +1901,9 @@ dependencies = [ "cesu8", "cfg-if", "combine 4.6.6", + "java-locator", "jni-sys", + "libloading 0.7.4", "log", "thiserror", "walkdir", @@ -1947,6 +1961,16 @@ version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + [[package]] name = "libloading" version = "0.8.1" @@ -2321,7 +2345,7 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2503fa6af34dc83fb74888df8b22afe933b58d37daf7d80424b1c60c68196b8b" dependencies = [ - "libloading", + "libloading 0.8.1", ] [[package]] diff --git a/packages/rust-core/java/Cargo.toml b/packages/rust-core/java/Cargo.toml index 2835e83f..a5d203ae 100644 --- a/packages/rust-core/java/Cargo.toml +++ b/packages/rust-core/java/Cargo.toml @@ -26,7 +26,16 @@ num_cpus.workspace = true tokio.workspace = true thiserror.workspace = true -jni = "0.21.1" +jni = { version = "0.21.1", features = [] } + +[dev-dependencies] +lazy_static.workspace = true +# https://github.com/rust-lang/cargo/issues/2911#issuecomment-749580481 +flappy-java-bindings = { path = ".", features = ["build-java-support"] } + [lints] workspace = true + +[features] +build-java-support = ["jni/invocation"] diff --git a/packages/rust-core/java/README.md b/packages/rust-core/java/README.md index 301f8cd1..eceaa696 100644 --- a/packages/rust-core/java/README.md +++ b/packages/rust-core/java/README.md @@ -86,7 +86,7 @@ To load the shared library correctly, you can choose one of the following approa You can use Maven to build both Rust dynamic lib and JAR files with one command now: ```shell -./mvnw clean package -DskipTests=true +./mvnw clean package -DskipTests ``` ## Run tests diff --git a/packages/rust-core/java/build.rs b/packages/rust-core/java/build.rs new file mode 100644 index 00000000..c7fbf3ea --- /dev/null +++ b/packages/rust-core/java/build.rs @@ -0,0 +1,63 @@ +#[cfg(feature = "build-java-support")] +fn build_java() { + use std::{env, path::PathBuf, process::Command}; + + let java_src_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); + println!("src dir {:?}", java_src_dir); + + let mut java_src_mvnw = java_src_dir.clone(); + java_src_mvnw.push( + #[cfg(target_os = "windows")] + "mvnw.bat", + #[cfg(not(target_os = "windows"))] + "mvnw", + ); + + let java_build_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); + + println!("build dir {:?}", java_build_dir); + + let mut binding = Command::new(java_src_mvnw.clone()); + let command = binding + .args(["package", "-DskipTests", "-Dgpg.skip"]) + .current_dir(java_src_dir.clone()); + + println!("command {:?}", command); + + let result = command.spawn().unwrap().wait().unwrap(); + + if result.success() { + let mut source_dir = java_src_dir; + let version_u8 = Command::new(java_src_mvnw) + .args([ + "help:evaluate", + "-Dexpression=project.version", + "-q", + "-DforceStdout", + ]) + .output() + .unwrap() + .stdout; + let version = String::from_utf8_lossy(&version_u8); + let trimed_version = version.trim(); + + source_dir.push("target"); + source_dir.push(format!("flappy-java-bindings-{}.jar", trimed_version)); + + let mut target_dir = java_build_dir; + target_dir.push("flappy-java-bindings-latest.jar"); + + println!("cargo:warning=build ok {:?}", target_dir); + std::fs::copy(source_dir, target_dir).unwrap(); + } else { + panic!("build error"); + } +} + +fn main() { + println!("cargo:warning=build maven"); + println!("cargo:rerun-if-changed=src/main"); + + #[cfg(feature = "build-java-support")] + build_java(); +} diff --git a/packages/rust-core/java/src/future.rs b/packages/rust-core/java/src/future.rs index 2577f25d..c177f6c2 100644 --- a/packages/rust-core/java/src/future.rs +++ b/packages/rust-core/java/src/future.rs @@ -75,3 +75,17 @@ fn get_future<'local>(env: &mut JNIEnv<'local>, id: jlong) -> Result = { + let mut env = JVM.jvm.attach_current_thread_permanently().unwrap(); + + let thread = env + .call_static_method( + "java/lang/Thread", + "currentThread", + "()Ljava/lang/Thread;", + &[], + ) + .unwrap() + .l() + .unwrap(); + env.call_method( + thread, + "setContextClassLoader", + "(Ljava/lang/ClassLoader;)V", + &[JVM.class_loader.as_obj().into()] + ).unwrap(); + + env + } +} + +lazy_static! { + static ref JVM: GlobalJVM = { + use jni::InitArgsBuilder; + use std::env; + + let mut jni_utils_jar = std::path::PathBuf::from(env::var("OUT_DIR").unwrap()); + jni_utils_jar.push("flappy-java-bindings-latest.jar"); + let option = format!("-Djava.class.path={}", jni_utils_jar.to_str().unwrap()); + + let jvm_args = InitArgsBuilder::new().option(option).build().unwrap(); + let jvm = JavaVM::new(jvm_args).unwrap(); + + let mut env = jvm.attach_current_thread_permanently().unwrap(); + + let thread = env + .call_static_method( + "java/lang/Thread", + "currentThread", + "()Ljava/lang/Thread;", + &[], + ) + .unwrap() + .l() + .unwrap(); + let class_loader = env + .call_method( + thread, + "getContextClassLoader", + "()Ljava/lang/ClassLoader;", + &[], + ) + .unwrap() + .l() + .unwrap(); + let class_loader = env.new_global_ref(class_loader).unwrap(); + + GlobalJVM { jvm, class_loader } + }; +} From db7db9ae75c7341fb83f5628dbc6d4e7d5f3fc96 Mon Sep 17 00:00:00 2001 From: Yuhang Shi Date: Wed, 6 Dec 2023 17:13:02 +0800 Subject: [PATCH 3/4] fix: lint Signed-off-by: Yuhang Shi --- .../java/com/pleisto/FlappyAsyncRegistry.java | 40 +++++++++---------- .../java/com/pleisto/FlappyJniSandbox.java | 2 - 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/packages/rust-core/java/src/main/java/com/pleisto/FlappyAsyncRegistry.java b/packages/rust-core/java/src/main/java/com/pleisto/FlappyAsyncRegistry.java index 98cfb31c..5c7fada7 100644 --- a/packages/rust-core/java/src/main/java/com/pleisto/FlappyAsyncRegistry.java +++ b/packages/rust-core/java/src/main/java/com/pleisto/FlappyAsyncRegistry.java @@ -6,30 +6,30 @@ import java.util.concurrent.ConcurrentHashMap; public enum FlappyAsyncRegistry { - INSTANCE; + INSTANCE; - private final Map> registry = new ConcurrentHashMap<>(); + private final Map> registry = new ConcurrentHashMap<>(); - static long requestId() { - final CompletableFuture f = new CompletableFuture<>(); - while (true) { - final long requestId = Math.abs(UUID.randomUUID().getLeastSignificantBits()); - final CompletableFuture prev = INSTANCE.registry.putIfAbsent(requestId, f); - if (prev == null) { - return requestId; - } + static long requestId() { + final CompletableFuture f = new CompletableFuture<>(); + while (true) { + final long requestId = Math.abs(UUID.randomUUID().getLeastSignificantBits()); + final CompletableFuture prev = INSTANCE.registry.putIfAbsent(requestId, f); + if (prev == null) { + return requestId; + } + } } - } - static CompletableFuture get(long requestId) { - return INSTANCE.registry.get(requestId); - } + static CompletableFuture get(long requestId) { + return INSTANCE.registry.get(requestId); + } - static CompletableFuture take(long requestId) { - final CompletableFuture f = get(requestId); - if (f != null) { - f.whenComplete((r, e) -> INSTANCE.registry.remove(requestId)); + static CompletableFuture take(long requestId) { + final CompletableFuture f = get(requestId); + if (f != null) { + f.whenComplete((r, e) -> INSTANCE.registry.remove(requestId)); + } + return (CompletableFuture) f; } - return (CompletableFuture) f; - } } diff --git a/packages/rust-core/java/src/main/java/com/pleisto/FlappyJniSandbox.java b/packages/rust-core/java/src/main/java/com/pleisto/FlappyJniSandbox.java index 279c5f0f..32c2ab3a 100644 --- a/packages/rust-core/java/src/main/java/com/pleisto/FlappyJniSandbox.java +++ b/packages/rust-core/java/src/main/java/com/pleisto/FlappyJniSandbox.java @@ -4,9 +4,7 @@ import java.nio.file.Files; import java.util.HashMap; import java.util.Map; -import java.util.UUID; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; import lombok.NonNull; public class FlappyJniSandbox extends FlappyJniLoader implements AutoCloseable { From 6eb4130e5d39fbd14b1bafea568bcc476b65613b Mon Sep 17 00:00:00 2001 From: Yuhang Shi Date: Wed, 6 Dec 2023 20:16:13 +0800 Subject: [PATCH 4/4] backtrace Signed-off-by: Yuhang Shi --- .github/workflows/coverage.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 3c8eb652..30e1192b 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -41,6 +41,8 @@ jobs: working-directory: packages/rust-core run: | cargo +nightly tarpaulin --verbose --all-features --workspace --timeout 300 --run-types doctests --run-types lib --run-types tests --out xml + env: + RUST_BACKTRACE: full - name: Upload to codecov.io uses: codecov/codecov-action@v3