From 7eef137bcdf8bdb08d2ffe40c7ccbf66b4a3f70f Mon Sep 17 00:00:00 2001 From: Orion Kindel Date: Sat, 8 Apr 2023 10:35:23 -0700 Subject: [PATCH] feat: update toad-jni --- glue/.cargo/config.toml | 2 +- glue/Cargo.lock | 28 +-- glue/Cargo.toml | 5 +- glue/src/lib.rs | 29 ++- glue/src/mem.rs | 50 ++++++ glue/src/message_code.rs | 25 ++- glue/src/message_opt_ref.rs | 60 +++---- glue/src/message_opt_value_ref.rs | 35 ++-- glue/src/message_ref.rs | 57 +++--- glue/src/message_type.rs | 43 ++--- glue/src/retry_strategy.rs | 162 +++++++++-------- glue/src/runtime.rs | 69 ++++++++ glue/src/runtime_config.rs | 263 ++++++++++------------------ glue/src/uint.rs | 163 ++++++----------- src/main/java/dev.toad/Runtime.java | 12 +- 15 files changed, 486 insertions(+), 517 deletions(-) create mode 100644 glue/src/mem.rs create mode 100644 glue/src/runtime.rs diff --git a/glue/.cargo/config.toml b/glue/.cargo/config.toml index 28b4d1f..e58e7bc 100644 --- a/glue/.cargo/config.toml +++ b/glue/.cargo/config.toml @@ -1,2 +1,2 @@ [build] -target-dir = "../target/native" +target-dir = "../target/glue" diff --git a/glue/Cargo.lock b/glue/Cargo.lock index 4b6a3d8..b5562d6 100644 --- a/glue/Cargo.lock +++ b/glue/Cargo.lock @@ -504,9 +504,9 @@ checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" [[package]] name = "toad" -version = "0.17.2" +version = "0.17.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6e3e3216e542ea3b2da0d2200e498b016907b68acb288b47a487cb9fd681b42" +checksum = "5d4000090e5f6d1380e1a4bfb9a5428019cb7a4374b3663792ef7965384968fc" dependencies = [ "embedded-time", "log", @@ -525,7 +525,7 @@ dependencies = [ "toad-len", "toad-macros", "toad-map", - "toad-msg 0.15.1", + "toad-msg", "toad-stem", "toad-writable", ] @@ -570,17 +570,18 @@ name = "toad-java-glue" version = "0.1.0" dependencies = [ "jni", + "nb", "tinyvec", "toad", "toad-jni", - "toad-msg 0.18.1", + "toad-msg", ] [[package]] name = "toad-jni" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff5fbc1fb554ad85160c74d6c6db551f164b79917c89509037477ad308d2b4ac" +checksum = "9d47119dc7ecc1c65fa860a7b2c95dd45b177d07331ee8a18cac0cc41c9bd825" dependencies = [ "jni", "toad-array 0.5.0", @@ -618,21 +619,6 @@ dependencies = [ "toad-len", ] -[[package]] -name = "toad-msg" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "172e73f5ce192a45314eef776dd7e1e3cbde1c51ea021d79ac3630549925fbe5" -dependencies = [ - "blake2", - "tinyvec", - "toad-array 0.2.3", - "toad-cursor", - "toad-len", - "toad-macros", - "toad-map", -] - [[package]] name = "toad-msg" version = "0.18.1" diff --git a/glue/Cargo.toml b/glue/Cargo.toml index 7b7ba67..836189c 100644 --- a/glue/Cargo.toml +++ b/glue/Cargo.toml @@ -9,7 +9,8 @@ crate_type = ["cdylib"] [dependencies] jni = "0.21.1" -toad = "0.17.2" -toad-jni = "0.4.1" +nb = "1" +toad = "0.17.3" +toad-jni = "0.5.1" toad-msg = "0.18.1" tinyvec = {version = "1.5", default_features = false, features = ["rustc_1_55"]} diff --git a/glue/src/lib.rs b/glue/src/lib.rs index 54ce5fe..0c874dc 100644 --- a/glue/src/lib.rs +++ b/glue/src/lib.rs @@ -1,15 +1,7 @@ #![feature(strict_provenance)] -use jni::objects::{JClass, JObject}; -use jni::JNIEnv; -use toad::std::{dtls, Platform as Std}; -use toad::step::runtime::std::Runtime; - -pub static mut RUNTIME: *const Std> = std::ptr::null(); - -pub unsafe fn with_runtime_provenance(addr: i64) -> *mut T { - RUNTIME.with_addr(addr as usize).cast::().cast_mut() -} +pub type Runtime = + toad::std::Platform>; #[macro_export] macro_rules! package { @@ -18,33 +10,31 @@ macro_rules! package { (ext $start:ident.$($thing:ident).+) => {concat!(stringify!($start), $("/", stringify!($thing)),+)}; } +pub mod mem; pub mod message_code; pub mod message_opt_ref; pub mod message_opt_value_ref; pub mod message_ref; pub mod message_type; pub mod retry_strategy; +pub mod runtime; pub mod runtime_config; pub mod uint; -pub extern "system" fn Java_dev_toad_Runtime_init<'local>(mut env: JNIEnv<'local>, - _: JClass<'local>, - cfg: JObject<'local>) { -} - #[cfg(test)] mod tests { use std::sync::Once; - use jni::{InitArgsBuilder, JNIEnv, JavaVM}; + use jni::{InitArgsBuilder, JavaVM}; use toad::retry::Strategy; use toad::time::Millis; + use toad_jni::java; use crate::retry_strategy::RetryStrategy; use crate::runtime_config::RuntimeConfig; static INIT: Once = Once::new(); - pub fn init<'a>() -> JNIEnv<'a> { + pub fn init<'a>() -> java::Env<'a> { INIT.call_once(|| { let jvm = JavaVM::new(InitArgsBuilder::new().option("--enable-preview") @@ -54,8 +44,9 @@ mod tests { toad_jni::global::init_with(jvm); }); - toad_jni::global::jvm().attach_current_thread_permanently(); - toad_jni::global::env() + toad_jni::global::jvm().attach_current_thread_permanently() + .unwrap(); + toad_jni::global::jvm().get_env().unwrap() } #[test] diff --git a/glue/src/mem.rs b/glue/src/mem.rs new file mode 100644 index 0000000..6092332 --- /dev/null +++ b/glue/src/mem.rs @@ -0,0 +1,50 @@ +/// global [`RuntimeAllocator`] implementation +pub type Runtime = RuntimeGlobalStaticAllocator; + +/// Trait managing the memory region(s) associated with the toad runtime +/// data structure. +/// +/// Notably, any and all references produced by the runtime will be to data +/// within the Runtime's memory region, meaning that we can easily leverage +/// strict provenance to prevent addresses from leaking outside of that memory region. +pub trait RuntimeAllocator: core::default::Default + core::fmt::Debug + Copy { + /// Allocate memory for the runtime and yield a stable pointer to it + unsafe fn alloc(r: crate::Runtime) -> *mut crate::Runtime; + + /// Coerce a `long` rep of the stable pointer created by [`Self::alloc`] to + /// a pointer (preferably using strict_provenance) + unsafe fn deref(addr: i64) -> *mut crate::Runtime; + + /// Coerce a `long` rep of a pointer to some data within the + /// Runtime data structure. + /// + /// Requires the Runtime address in order for the new pointer + /// to inherit its provenance. + unsafe fn deref_inner(runtime_addr: i64, addr: i64) -> *mut T { + Self::deref(runtime_addr).with_addr(addr as usize) + .cast::() + } +} + +static mut RUNTIME: *mut crate::Runtime = core::ptr::null_mut(); + +#[derive(Default, Debug, Clone, Copy)] +pub struct RuntimeGlobalStaticAllocator; +impl RuntimeAllocator for RuntimeGlobalStaticAllocator { + /// Nops on already-init + unsafe fn alloc(r: crate::Runtime) -> *mut crate::Runtime { + if RUNTIME.is_null() { + let p = + std::alloc::alloc(std::alloc::Layout::new::()).cast::(); + *p = r; + RUNTIME = p; + RUNTIME + } else { + RUNTIME + } + } + + unsafe fn deref(_: i64) -> *mut crate::Runtime { + RUNTIME + } +} diff --git a/glue/src/message_code.rs b/glue/src/message_code.rs index 31e782e..5dff7a0 100644 --- a/glue/src/message_code.rs +++ b/glue/src/message_code.rs @@ -1,19 +1,16 @@ -use jni::objects::{JClass, JObject}; -use jni::sys::jobject; -use jni::JNIEnv; -use toad_jni::Sig; +use toad_jni::java; use toad_msg::Code; -pub struct MessageCode<'local>(pub JObject<'local>); -impl<'local> MessageCode<'local> { - const ID: &'static str = package!(dev.toad.msg.MessageCode); - const CTOR: Sig = Sig::new().arg(Sig::INT).arg(Sig::INT).returning(Sig::VOID); +pub struct MessageCode(java::lang::Object); - pub fn new(env: &mut JNIEnv<'local>, code: Code) -> Self { - let o = env.new_object(Self::ID, - Self::CTOR, - &[i32::from(code.class).into(), i32::from(code.detail).into()]) - .unwrap(); - Self(o) +java::object_newtype!(MessageCode); +impl java::Class for MessageCode { + const PATH: &'static str = package!(dev.toad.msg.MessageCode); +} + +impl MessageCode { + pub fn new(e: &mut java::Env, code: Code) -> Self { + static CTOR: java::Constructor = java::Constructor::new(); + CTOR.invoke(e, code.class.into(), code.detail.into()) } } diff --git a/glue/src/message_opt_ref.rs b/glue/src/message_opt_ref.rs index be49f92..de4cc21 100644 --- a/glue/src/message_opt_ref.rs +++ b/glue/src/message_opt_ref.rs @@ -1,41 +1,34 @@ use jni::objects::{JClass, JObject}; use jni::sys::jobject; use jni::JNIEnv; -use toad_jni::Sig; +use toad_jni::java::{self, Object}; use toad_msg::{OptNumber, OptValue}; +use crate::mem::RuntimeAllocator; use crate::message_opt_value_ref::MessageOptValueRef; -use crate::with_runtime_provenance; -pub struct MessageOptRef<'local>(pub JObject<'local>); -impl<'local> MessageOptRef<'local> { - const ID: &'static str = package!(dev.toad.msg.MessageOptionRef); - const CTOR: Sig = Sig::new().arg(Sig::LONG) - .arg(Sig::LONG) - .returning(Sig::VOID); +pub struct MessageOptRef(pub java::lang::Object); - const NUMBER: &'static str = "number"; +java::object_newtype!(MessageOptRef); - pub fn class(env: &mut JNIEnv<'local>) -> JClass<'local> { - env.find_class(Self::ID).unwrap() +impl java::Class for MessageOptRef { + const PATH: &'static str = package!(dev.toad.msg.MessageOptionRef); +} + +impl MessageOptRef { + pub fn new(env: &mut java::Env, addr: i64, num: i64) -> Self { + static CTOR: java::Constructor = java::Constructor::new(); + CTOR.invoke(env, addr, num) } - pub fn new(env: &mut JNIEnv<'local>, addr: i64, num: i64) -> Self { - let o = env.new_object(Self::ID, Self::CTOR, &[addr.into(), num.into()]) - .unwrap(); - Self(o) - } - - pub fn number(&self, env: &mut JNIEnv<'local>) -> OptNumber { - OptNumber(env.get_field(&self.0, Self::NUMBER, Sig::LONG) - .unwrap() - .j() - .unwrap() as u32) + pub fn number(&self, env: &mut java::Env) -> OptNumber { + static NUMBER: java::Field = java::Field::new("number"); + OptNumber(NUMBER.get(env, self) as u32) } pub unsafe fn values_ptr<'a>(addr: i64) -> &'a mut Vec>> { - with_runtime_provenance::>>>(addr).as_mut() - .unwrap() + crate::mem::Runtime::deref_inner::>>>(/* TODO */ 0, addr).as_mut() + .unwrap() } } @@ -44,24 +37,21 @@ pub extern "system" fn Java_dev_toad_msg_MessageOptionRef_number<'local>(mut env o: JObject<'local>, p: i64) -> i64 { - MessageOptRef(o).number(&mut env).0 as i64 + java::lang::Object::from_local(&mut env, o).upcast_to::(&mut env) + .number(&mut env) + .0 as i64 } #[no_mangle] -pub extern "system" fn Java_dev_toad_msg_MessageOptionRef_values<'local>(mut env: JNIEnv<'local>, +pub extern "system" fn Java_dev_toad_msg_MessageOptionRef_values<'local>(mut e: JNIEnv<'local>, _: JClass<'local>, p: i64) -> jobject { let o = &unsafe { MessageOptRef::values_ptr(p) }; - let value_ref_class = MessageOptValueRef::class(&mut env); - let mut arr = env.new_object_array(o.len() as i32, value_ref_class, JObject::null()) - .unwrap(); + let refs = o.iter() + .map(|v| MessageOptValueRef::new(&mut e, (&v.0 as *const Vec).addr() as i64)) + .collect::>(); - for (ix, v) in o.iter().enumerate() { - let value_ref = MessageOptValueRef::new(&mut env, v as *const _ as i64); - env.set_object_array_element(&mut arr, ix as i32, value_ref.0); - } - - arr.as_raw() + refs.downcast(&mut e).as_raw() } diff --git a/glue/src/message_opt_value_ref.rs b/glue/src/message_opt_value_ref.rs index d7f91a6..f2c8d85 100644 --- a/glue/src/message_opt_value_ref.rs +++ b/glue/src/message_opt_value_ref.rs @@ -1,34 +1,31 @@ -use jni::objects::{JClass, JObject}; +use jni::objects::JClass; use jni::sys::jobject; -use jni::JNIEnv; -use toad_jni::Sig; -use toad_msg::{OptNumber, OptValue}; +use toad_jni::java; +use toad_msg::OptValue; -use crate::with_runtime_provenance; +use crate::mem::RuntimeAllocator; -pub struct MessageOptValueRef<'local>(pub JObject<'local>); -impl<'local> MessageOptValueRef<'local> { - const ID: &'static str = package!(dev.toad.msg.MessageOptionValueRef); - const CTOR: Sig = Sig::new().arg(Sig::LONG).returning(Sig::VOID); +pub struct MessageOptValueRef(java::lang::Object); - pub fn class(env: &mut JNIEnv<'local>) -> JClass<'local> { - env.find_class(Self::ID).unwrap() - } +java::object_newtype!(MessageOptValueRef); +impl java::Class for MessageOptValueRef { + const PATH: &'static str = package!(dev.toad.msg.MessageOptionValueRef); +} - pub fn new(env: &mut JNIEnv<'local>, addr: i64) -> Self { - let o = env.new_object(Self::ID, Self::CTOR, &[addr.into()]) - .unwrap(); - Self(o) +impl MessageOptValueRef { + pub fn new(env: &mut java::Env, addr: i64) -> Self { + static CTOR: java::Constructor = java::Constructor::new(); + CTOR.invoke(env, addr) } pub unsafe fn ptr<'a>(addr: i64) -> &'a mut OptValue> { - with_runtime_provenance::>>(addr).as_mut() - .unwrap() + crate::mem::Runtime::deref_inner::>>(/* TODO */ 0, addr).as_mut() + .unwrap() } } #[no_mangle] -pub extern "system" fn Java_dev_toad_msg_MessageOptionValueRef_bytes<'local>(mut env: JNIEnv<'local>, +pub extern "system" fn Java_dev_toad_msg_MessageOptionValueRef_bytes<'local>(mut env: java::Env<'local>, _: JClass<'local>, p: i64) -> jobject { diff --git a/glue/src/message_ref.rs b/glue/src/message_ref.rs index 51215f1..f1f3965 100644 --- a/glue/src/message_ref.rs +++ b/glue/src/message_ref.rs @@ -1,32 +1,34 @@ -use jni::objects::{JClass, JObject}; +use jni::objects::JClass; use jni::sys::jobject; -use jni::JNIEnv; -use toad_jni::Sig; +use toad_jni::java::{self, Object}; use toad_msg::alloc::Message; +use crate::mem::RuntimeAllocator; use crate::message_code::MessageCode; use crate::message_opt_ref::MessageOptRef; use crate::message_type::MessageType; -use crate::{with_runtime_provenance, RUNTIME}; -pub struct MessageRef<'local>(pub JObject<'local>); -impl<'local> MessageRef<'local> { - const ID: &'static str = package!(dev.toad.msg.MessageRef); - const CTOR: Sig = Sig::new().arg(Sig::LONG).returning(Sig::VOID); +pub struct MessageRef(java::lang::Object); - pub fn new(env: &mut JNIEnv<'local>, addr: i64) -> Self { - let o = env.new_object(Self::ID, Self::CTOR, &[addr.into()]) - .unwrap(); - Self(o) +java::object_newtype!(MessageRef); +impl java::Class for MessageRef { + const PATH: &'static str = package!(dev.toad.msg.MessageRef); +} + +impl MessageRef { + pub fn new(env: &mut java::Env, addr: *const Message) -> Self { + static CTOR: java::Constructor = java::Constructor::new(); + CTOR.invoke(env, addr.addr() as i64) } pub unsafe fn ptr<'a>(addr: i64) -> &'a mut Message { - with_runtime_provenance::(addr).as_mut().unwrap() + crate::mem::Runtime::deref_inner::(/* TODO */ 0, addr).as_mut() + .unwrap() } } #[no_mangle] -pub extern "system" fn Java_dev_toad_msg_MessageRef_id<'local>(mut env: JNIEnv<'local>, +pub extern "system" fn Java_dev_toad_msg_MessageRef_id<'local>(mut env: java::Env<'local>, _: JClass<'local>, addr: i64) -> i32 { @@ -35,7 +37,7 @@ pub extern "system" fn Java_dev_toad_msg_MessageRef_id<'local>(mut env: JNIEnv<' } #[no_mangle] -pub extern "system" fn Java_dev_toad_msg_MessageRef_token<'local>(mut env: JNIEnv<'local>, +pub extern "system" fn Java_dev_toad_msg_MessageRef_token<'local>(mut env: java::Env<'local>, _: JClass<'local>, addr: i64) -> jobject { @@ -44,7 +46,7 @@ pub extern "system" fn Java_dev_toad_msg_MessageRef_token<'local>(mut env: JNIEn } #[no_mangle] -pub extern "system" fn Java_dev_toad_msg_MessageRef_payload<'local>(mut env: JNIEnv<'local>, +pub extern "system" fn Java_dev_toad_msg_MessageRef_payload<'local>(mut env: java::Env<'local>, _: JClass<'local>, addr: i64) -> jobject { @@ -53,39 +55,34 @@ pub extern "system" fn Java_dev_toad_msg_MessageRef_payload<'local>(mut env: JNI } #[no_mangle] -pub extern "system" fn Java_dev_toad_msg_MessageRef_type<'local>(mut env: JNIEnv<'local>, +pub extern "system" fn Java_dev_toad_msg_MessageRef_type<'local>(mut e: java::Env<'local>, _: JClass<'local>, addr: i64) -> jobject { let msg = unsafe { MessageRef::ptr(addr) }; - MessageType::new(&mut env, msg.ty).0.into_raw() + MessageType::new(&mut e, msg.ty).downcast(&mut e).as_raw() } #[no_mangle] -pub extern "system" fn Java_dev_toad_msg_MessageRef_code<'local>(mut env: JNIEnv<'local>, +pub extern "system" fn Java_dev_toad_msg_MessageRef_code<'local>(mut e: java::Env<'local>, _: JClass<'local>, addr: i64) -> jobject { let msg = unsafe { MessageRef::ptr(addr) }; - MessageCode::new(&mut env, msg.code).0.into_raw() + MessageCode::new(&mut e, msg.code).downcast(&mut e).as_raw() } #[no_mangle] -pub extern "system" fn Java_dev_toad_msg_MessageRef_opts<'local>(mut env: JNIEnv<'local>, +pub extern "system" fn Java_dev_toad_msg_MessageRef_opts<'local>(mut e: java::Env<'local>, _: JClass<'local>, addr: i64) -> jobject { let msg = unsafe { MessageRef::ptr(addr) }; let opts = &msg.opts; - let opt_ref_class = MessageOptRef::class(&mut env); - let mut arr = env.new_object_array((*opts).len() as i32, opt_ref_class, JObject::null()) - .unwrap(); + let refs = opts.into_iter() + .map(|(n, v)| MessageOptRef::new(&mut e, v as *const _ as i64, n.0.into())) + .collect::>(); - for (ix, (num, v)) in (*opts).iter().enumerate() { - let opt_ref = MessageOptRef::new(&mut env, v as *const _ as i64, num.0.into()); - env.set_object_array_element(&mut arr, ix as i32, opt_ref.0); - } - - arr.as_raw() + refs.downcast(&mut e).as_raw() } diff --git a/glue/src/message_type.rs b/glue/src/message_type.rs index 4a291e6..a27beaa 100644 --- a/glue/src/message_type.rs +++ b/glue/src/message_type.rs @@ -1,32 +1,25 @@ -use jni::objects::{JObject, JString, JValueGen}; -use jni::sys::jstring; -use jni::JNIEnv; -use toad_jni::Sig; +use toad_jni::java; use toad_msg::Type; -pub struct MessageType<'local>(pub JObject<'local>); -impl<'local> MessageType<'local> { - const ID: &'static str = package!(dev.toad.msg.MessageType); - const FROM_STRING: Sig = Sig::new().arg(Sig::class("java/lang/String")) - .returning(Sig::class(Self::ID)); +pub struct MessageType(java::lang::Object); - pub fn new(env: &mut JNIEnv<'local>, ty: Type) -> Self { - let str = env.new_string(match ty { - | Type::Con => "CON", - | Type::Non => "NON", - | Type::Ack => "ACK", - | Type::Reset => "RESET", - }) - .unwrap(); +java::object_newtype!(MessageType); +impl java::Class for MessageType { + const PATH: &'static str = package!(dev.toad.msg.MessageType); +} - let o = env.call_static_method(Self::ID, - "fromString", - Self::FROM_STRING, - &[JValueGen::Object(&str)]) - .unwrap() - .l() - .unwrap(); +impl MessageType { + pub fn new(env: &mut java::Env, ty: Type) -> Self { + static FROM_STRING: java::StaticMethod MessageType> = + java::StaticMethod::new("fromString"); - Self(o) + let str = match ty { + | Type::Con => "CON", + | Type::Non => "NON", + | Type::Ack => "ACK", + | Type::Reset => "RESET", + }; + + FROM_STRING.invoke(env, str.to_string()) } } diff --git a/glue/src/retry_strategy.rs b/glue/src/retry_strategy.rs index 6a34981..4795344 100644 --- a/glue/src/retry_strategy.rs +++ b/glue/src/retry_strategy.rs @@ -1,89 +1,103 @@ -use jni::objects::{GlobalRef, JObject}; -use jni::JNIEnv; use toad::retry::Strategy; use toad::time::Millis; -use toad_jni::cls::java; -use toad_jni::convert::Object; -use toad_jni::Sig; +use toad_jni::java::{self, Object}; use crate::uint; -pub struct RetryStrategy(GlobalRef); +pub struct RetryStrategyExp(java::lang::Object); + +java::object_newtype!(RetryStrategyExp); +impl java::Class for RetryStrategyExp { + const PATH: &'static str = package!(dev.toad.RetryStrategyExponential); +} + +impl RetryStrategyExp { + pub fn new(e: &mut java::Env, init_min: Millis, init_max: Millis) -> Self { + let (init_min, init_max) = (java::time::Duration::of_millis(e, init_min.0 as i64), + java::time::Duration::of_millis(e, init_max.0 as i64)); + static CTOR: java::Constructor = + java::Constructor::new(); + CTOR.invoke(e, init_min, init_max) + } + + pub fn as_super(self) -> RetryStrategy { + RetryStrategy(self.0) + } + + pub fn init_min(&self, e: &mut java::Env) -> Millis { + static INIT_MIN: java::Field = java::Field::new("initMin"); + Millis::new(INIT_MIN.get(e, self).to_rust(e)) + } + + pub fn init_max(&self, e: &mut java::Env) -> Millis { + static INIT_MAX: java::Field = java::Field::new("initMax"); + Millis::new(INIT_MAX.get(e, self).to_rust(e)) + } +} + +pub struct RetryStrategyDelay(java::lang::Object); + +java::object_newtype!(RetryStrategyDelay); +impl java::Class for RetryStrategyDelay { + const PATH: &'static str = package!(dev.toad.RetryStrategyDelay); +} + +impl RetryStrategyDelay { + pub fn new(e: &mut java::Env, min: Millis, max: Millis) -> Self { + let (min, max) = (java::time::Duration::of_millis(e, min.0 as i64), + java::time::Duration::of_millis(e, max.0 as i64)); + static CTOR: java::Constructor = + java::Constructor::new(); + CTOR.invoke(e, min, max) + } + + pub fn as_super(self) -> RetryStrategy { + RetryStrategy(self.0) + } + + pub fn min(&self, e: &mut java::Env) -> Millis { + static MIN: java::Field = java::Field::new("min"); + Millis::new(MIN.get(e, self).to_rust(e)) + } + + pub fn max(&self, e: &mut java::Env) -> Millis { + static MAX: java::Field = java::Field::new("max"); + Millis::new(MAX.get(e, self).to_rust(e)) + } +} + +pub struct RetryStrategy(java::lang::Object); + +java::object_newtype!(RetryStrategy); +impl java::Class for RetryStrategy { + const PATH: &'static str = package!(dev.toad.RetryStrategy); +} impl RetryStrategy { - pub const PATH: &'static str = package!(dev.toad.RetryStrategy); - - pub const EXPONENTIAL: &'static str = package!(dev.toad.RetryStrategyExponential); - pub const EXPONENTIAL_CTOR: Sig = Sig::new().arg(Sig::class(java::time::Duration::PATH)) - .arg(Sig::class(java::time::Duration::PATH)) - .returning(Sig::VOID); - - pub const DELAY: &'static str = package!(dev.toad.RetryStrategyDelay); - pub const DELAY_CTOR: Sig = Sig::new().arg(Sig::class(java::time::Duration::PATH)) - .arg(Sig::class(java::time::Duration::PATH)) - .returning(Sig::VOID); - - pub fn exp<'a>(&self, e: &mut JNIEnv<'a>) -> Self { - let o = e.new_object(Self::PATH, Sig::new().returning(Sig::VOID), &[]) - .unwrap(); - let g = e.new_global_ref(o).unwrap(); - Self(g) - } - - pub fn millis_field<'a>(&self, e: &mut JNIEnv<'a>, key: &str) -> Millis { - let o = e.get_field(&self.0, key, Sig::class(uint::u64::PATH)) - .unwrap() - .l() - .unwrap(); - let g = e.new_global_ref(o).unwrap(); - let d = uint::u64::from_java(g); - Millis::new(d.to_rust(e)) - } - - pub fn to_toad<'a>(self, e: &mut JNIEnv<'a>) -> Strategy { - if e.is_instance_of(&self.0, Self::EXPONENTIAL).unwrap() { - Strategy::Exponential { init_min: self.millis_field(e, "initMin"), - init_max: self.millis_field(e, "initMax") } + pub fn to_toad(self, e: &mut java::Env) -> Strategy { + if self.0.is_instance_of::(e) { + let me = RetryStrategyExp(self.0); + Strategy::Exponential { init_min: me.init_min(e), + init_max: me.init_max(e) } + } else if self.0.is_instance_of::(e) { + let me = RetryStrategyDelay(self.0); + Strategy::Delay { min: me.min(e), + max: me.max(e) } } else { - Strategy::Delay { min: self.millis_field(e, "min"), - max: self.millis_field(e, "max") } + let cls = e.get_object_class(self.0).unwrap(); + panic!("unknown inheritor of RetryStrategy: {}", + java::lang::Object::from_local(e, cls).to_string(e)); } } - pub fn from_toad<'a>(e: &mut JNIEnv<'a>, s: Strategy) -> Self { - let g = match s { - | Strategy::Delay { min, max } => { - let (min, max) = (java::time::Duration::of_millis(e, min.0 as i64), - java::time::Duration::of_millis(e, max.0 as i64)); - let (min, max) = (min.to_java(), max.to_java()); - let o = e.new_object(Self::DELAY, - Self::DELAY_CTOR, - &[min.as_obj().into(), max.as_obj().into()]) - .unwrap(); - e.new_global_ref(o).unwrap() - }, + pub fn from_toad(e: &mut java::Env, s: Strategy) -> Self { + match s { + | Strategy::Delay { min, max } => RetryStrategyDelay::new(e, min, max).as_super(), | Strategy::Exponential { init_min, init_max } => { - let (init_min, init_max) = (java::time::Duration::of_millis(e, init_min.0 as i64), - java::time::Duration::of_millis(e, init_max.0 as i64)); - let (init_min, init_max) = (init_min.to_java(), init_max.to_java()); - let o = e.new_object(Self::EXPONENTIAL, - Self::EXPONENTIAL_CTOR, - &[init_min.as_obj().into(), init_max.as_obj().into()]) - .unwrap(); - e.new_global_ref(o).unwrap() + RetryStrategyExp::new(e, init_min, init_max).as_super() }, - }; - - Self(g) - } -} - -impl Object for RetryStrategy { - fn from_java(jobj: GlobalRef) -> Self { - Self(jobj) - } - - fn to_java(self) -> GlobalRef { - self.0 + } } } diff --git a/glue/src/runtime.rs b/glue/src/runtime.rs new file mode 100644 index 0000000..464f101 --- /dev/null +++ b/glue/src/runtime.rs @@ -0,0 +1,69 @@ +use jni::objects::{JClass, JObject}; +use jni::sys::jobject; +use toad::platform::Platform; +use toad_jni::java::{self, Object}; + +use crate::mem::RuntimeAllocator; +use crate::message_ref::MessageRef; +use crate::runtime_config::RuntimeConfig; +use crate::Runtime as ToadRuntime; + +pub struct Runtime(java::lang::Object); + +impl Runtime { + pub fn init(e: &mut java::Env, cfg: RuntimeConfig) -> i64 { + let r = + ToadRuntime::try_new(format!("0.0.0.0:{}", cfg.net(e).port(e)), cfg.to_toad(e)).unwrap(); + unsafe { crate::mem::Runtime::alloc(r).addr() as i64 } + } + + pub fn addr(&self, e: &mut java::Env) -> i64 { + static ADDR: java::Field = java::Field::new("addr"); + ADDR.get(e, self) + } + + pub fn ref_(&self, e: &mut java::Env) -> &'static ToadRuntime { + unsafe { crate::mem::Runtime::deref(self.addr(e)).as_ref().unwrap() } + } +} + +java::object_newtype!(Runtime); + +impl java::Class for Runtime { + const PATH: &'static str = package!(dev.toad.Runtime); +} + +#[no_mangle] +pub extern "system" fn Java_dev_toad_Runtime_init<'local>(mut e: java::Env<'local>, + _: JClass<'local>, + cfg: JObject<'local>) + -> i64 { + let e = &mut e; + let cfg = java::lang::Object::from_local(e, cfg).upcast_to::(e); + + Runtime::init(e, cfg) +} + +// JNIEXPORT jobject JNICALL Java_dev_toad_Runtime_pollReq +// (JNIEnv *, jobject, jobject); +#[no_mangle] +pub extern "system" fn Java_dev_toad_Runtime_pollReq<'local>(mut e: java::Env<'local>, + runtime: JObject<'local>, + cfg: JObject<'local>) + -> jobject { + let e = &mut e; + let runtime = java::lang::Object::from_local(e, runtime).upcast_to::(e); + match runtime.ref_(e).poll_req() { + | Ok(req) => { + let mr = MessageRef::new(e, req.data().msg()); + java::util::Optional::::of(e, mr).downcast(e) + .as_raw() + }, + | Err(nb::Error::WouldBlock) => java::util::Optional::::empty(e).downcast(e) + .as_raw(), + | Err(nb::Error::Other(err)) => { + e.throw(format!("{:?}", err)).unwrap(); + core::ptr::null_mut() + }, + } +} diff --git a/glue/src/runtime_config.rs b/glue/src/runtime_config.rs index 5d361e7..7a12ca9 100644 --- a/glue/src/runtime_config.rs +++ b/glue/src/runtime_config.rs @@ -1,39 +1,29 @@ -use jni::objects::{GlobalRef, JObject}; -use jni::sys::{jint, jshort}; -use jni::JNIEnv; use toad::config::{self, BytesPerSecond}; use toad::retry::{Attempts, Strategy}; use toad::time::Millis; -use toad_jni::cls::java; -use toad_jni::convert::{Object, Primitive}; -use toad_jni::Sig; +use toad_jni::java; use crate::retry_strategy::RetryStrategy; -pub struct RuntimeConfig<'a>(JObject<'a>); +pub struct RuntimeConfig(java::lang::Object); -impl<'a> RuntimeConfig<'a> { - pub const PATH: &'static str = package!(dev.toad.RuntimeOptions); +java::object_newtype!(RuntimeConfig); +impl java::Class for RuntimeConfig { + const PATH: &'static str = package!(dev.toad.RuntimeOptions); +} - pub const CTOR: Sig = Sig::new().returning(Sig::VOID); - - pub fn new(e: &mut JNIEnv<'a>) -> Self { - let o = e.new_object(Self::PATH, Self::CTOR, &[]).unwrap(); - Self(o) +impl RuntimeConfig { + pub fn new(e: &mut java::Env) -> Self { + static CTOR: java::Constructor = java::Constructor::new(); + CTOR.invoke(e) } - pub fn net(&self, e: &mut JNIEnv<'a>) -> Net<'a> { - let o = e.call_method(&self.0, - "net", - Sig::new().returning(Sig::class(Net::PATH)), - &[]) - .unwrap() - .l() - .unwrap(); - Net(o) + pub fn net(&self, e: &mut java::Env) -> Net { + static NET: java::Method Net> = java::Method::new("net"); + NET.invoke(e, self) } - pub fn to_toad(&self, e: &mut JNIEnv<'a>) -> config::Config { + pub fn to_toad(&self, e: &mut java::Env) -> config::Config { let def = config::Config::default(); let net = self.net(e); @@ -78,182 +68,121 @@ impl<'a> RuntimeConfig<'a> { } } -pub struct Net<'a>(JObject<'a>); -impl<'a> Net<'a> { - pub const PATH: &'static str = concat!(package!(dev.toad.RuntimeOptions), "$Net"); +pub struct Net(java::lang::Object); +java::object_newtype!(Net); +impl java::Class for Net { + const PATH: &'static str = concat!(package!(dev.toad.RuntimeOptions), "$Net"); +} - pub fn port(&self, e: &mut JNIEnv<'a>) -> jshort { - e.call_method(&self.0, "port", Sig::new().returning(Sig::SHORT), &[]) - .unwrap() - .s() - .unwrap() +impl Net { + pub fn port(&self, e: &mut java::Env) -> i16 { + static PORT: java::Method i16> = java::Method::new("port"); + PORT.invoke(e, self) } - pub fn concurrency(&self, e: &mut JNIEnv<'a>) -> jshort { - e.call_method(&self.0, - "concurrency", - Sig::new().returning(Sig::SHORT), - &[]) - .unwrap() - .s() - .unwrap() + pub fn concurrency(&self, e: &mut java::Env) -> i16 { + static CONCURRENCY: java::Method i16> = java::Method::new("concurrency"); + CONCURRENCY.invoke(e, self) } - pub fn msg(&self, e: &mut JNIEnv<'a>) -> Msg<'a> { - let o = e.call_method(&self.0, - "msg", - Sig::new().returning(Sig::class(Msg::PATH)), - &[]) - .unwrap() - .l() - .unwrap(); - Msg(o) + pub fn msg(&self, e: &mut java::Env) -> Msg { + static MSG: java::Method Msg> = java::Method::new("msg"); + MSG.invoke(e, self) } } -pub struct Msg<'a>(JObject<'a>); -impl<'a> Msg<'a> { - pub const PATH: &'static str = concat!(package!(dev.toad.RuntimeOptions), "$Msg"); +pub struct Msg(java::lang::Object); - pub const TOKEN_SEED: Sig = Sig::new().returning(Sig::class(java::util::Optional::::PATH)); - pub const PROBING_RATE: Sig = - Sig::new().returning(Sig::class(java::util::Optional::::PATH)); - pub const MULTICAST_RESP_LEISURE: Sig = - Sig::new().returning(Sig::class(java::util::Optional::::PATH)); - pub const CON: Sig = Sig::new().returning(Sig::class(Con::PATH)); - pub const NON: Sig = Sig::new().returning(Sig::class(Non::PATH)); +java::object_newtype!(Msg); - pub fn token_seed(&self, e: &mut JNIEnv<'a>) -> Option { - let o = e.call_method(&self.0, "tokenSeed", Self::TOKEN_SEED, &[]) - .unwrap() - .l() - .unwrap(); - let g = e.new_global_ref(o).unwrap(); - java::util::Optional::::from_java(g).to_option(e) +impl java::Class for Msg { + const PATH: &'static str = concat!(package!(dev.toad.RuntimeOptions), "$Msg"); +} + +impl Msg { + pub fn token_seed(&self, e: &mut java::Env) -> Option { + static TOKEN_SEED: java::Method java::util::Optional> = + java::Method::new("tokenSeed"); + TOKEN_SEED.invoke(e, self).to_option(e) } - pub fn probing_rate(&self, e: &mut JNIEnv<'a>) -> Option { - let o = e.call_method(&self.0, - "probingRateBytesPerSecond", - Self::PROBING_RATE, - &[]) - .unwrap() - .l() - .unwrap(); - let g = e.new_global_ref(o).unwrap(); - java::util::Optional::::from_java(g).to_option(e) + pub fn probing_rate(&self, e: &mut java::Env) -> Option { + static PROBING_RATE: java::Method java::util::Optional> = + java::Method::new("probingRateBytesPerSecond"); + PROBING_RATE.invoke(e, self).to_option(e) } - pub fn multicast_response_leisure(&self, e: &mut JNIEnv<'a>) -> Option { - let o = e.call_method(&self.0, - "multicastResponseLeisure", - Self::MULTICAST_RESP_LEISURE, - &[]) - .unwrap() - .l() - .unwrap(); - let g = e.new_global_ref(o).unwrap(); - java::util::Optional::::from_java(g).to_option(e) - .map(java::time::Duration::from_java) - .map(|d| Millis::new(d.to_millis(e) as u64)) + pub fn multicast_response_leisure(&self, e: &mut java::Env) -> Option { + static MULTICAST_RESP_LEISURE: java::Method java::util::Optional> = + java::Method::new("multicastResponseLeisure"); + MULTICAST_RESP_LEISURE.invoke(e, self) + .to_option(e) + .map(|d| Millis::new(d.to_millis(e) as u64)) } - pub fn con(&self, e: &mut JNIEnv<'a>) -> Con<'a> { - let o = e.call_method(&self.0, "con", Self::CON, &[]) - .unwrap() - .l() - .unwrap(); - Con(o) + pub fn con(&self, e: &mut java::Env) -> Con { + static CON: java::Method Con> = java::Method::new("con"); + CON.invoke(e, self) } - pub fn non(&self, e: &mut JNIEnv<'a>) -> Non<'a> { - let o = e.call_method(&self.0, "non", Self::NON, &[]) - .unwrap() - .l() - .unwrap(); - Non(o) + pub fn non(&self, e: &mut java::Env) -> Non { + static NON: java::Method Non> = java::Method::new("non"); + NON.invoke(e, self) } } -pub struct Con<'a>(JObject<'a>); -impl<'a> Con<'a> { - pub const PATH: &'static str = concat!(package!(dev.toad.RuntimeOptions), "$Msg$Con"); +pub struct Con(java::lang::Object); - pub const ACKED_RETRY_STRATEGY: Sig = - Sig::new().returning(Sig::class(java::util::Optional::::PATH)); - pub const UNACKED_RETRY_STRATEGY: Sig = - Sig::new().returning(Sig::class(java::util::Optional::::PATH)); - pub const MAX_ATTEMPTS: Sig = - Sig::new().returning(Sig::class(java::util::Optional::::PATH)); +java::object_newtype!(Con); +impl java::Class for Con { + const PATH: &'static str = concat!(package!(dev.toad.RuntimeOptions), "$Msg$Con"); +} - pub fn acked_retry_strategy(&self, e: &mut JNIEnv<'a>) -> Option { - let o = e.call_method(&self.0, - "ackedRetryStrategy", - Self::ACKED_RETRY_STRATEGY, - &[]) - .unwrap() - .l() - .unwrap(); - let g = e.new_global_ref(o).unwrap(); - java::util::Optional::::from_java(g).to_option(e) - .map(RetryStrategy::from_java) - .map(|j| j.to_toad(e)) +impl Con { + pub fn acked_retry_strategy(&self, e: &mut java::Env) -> Option { + static ACKED_RETRY_STRATEGY: java::Method java::util::Optional> = + java::Method::new("ackedRetryStrategy"); + ACKED_RETRY_STRATEGY.invoke(e, self) + .to_option(e) + .map(|s| s.to_toad(e)) } - pub fn unacked_retry_strategy(&self, e: &mut JNIEnv<'a>) -> Option { - let o = e.call_method(&self.0, - "unackedRetryStrategy", - Self::UNACKED_RETRY_STRATEGY, - &[]) - .unwrap() - .l() - .unwrap(); - let g = e.new_global_ref(o).unwrap(); - java::util::Optional::::from_java(g).to_option(e) - .map(RetryStrategy::from_java) - .map(|j| j.to_toad(e)) + pub fn unacked_retry_strategy(&self, e: &mut java::Env) -> Option { + static UNACKED_RETRY_STRATEGY: java::Method java::util::Optional> = + java::Method::new("unackedRetryStrategy"); + UNACKED_RETRY_STRATEGY.invoke(e, self) + .to_option(e) + .map(|s| s.to_toad(e)) } - pub fn max_attempts(&self, e: &mut JNIEnv<'a>) -> Option { - let o = e.call_method(&self.0, "maxAttempts", Self::MAX_ATTEMPTS, &[]) - .unwrap() - .l() - .unwrap(); - let g = e.new_global_ref(o).unwrap(); - java::util::Optional::::from_java(g).to_option(e) - .map(java::lang::Integer::from_java) - .map(Primitive::dewrap) + pub fn max_attempts(&self, e: &mut java::Env) -> Option { + static MAX_ATTEMPTS: java::Method java::util::Optional> = + java::Method::new("maxAttempts"); + MAX_ATTEMPTS.invoke(e, self).to_option(e) } } -pub struct Non<'a>(JObject<'a>); -impl<'a> Non<'a> { - pub const PATH: &'static str = concat!(package!(dev.toad.RuntimeOptions), "$Msg$Non"); +pub struct Non(java::lang::Object); - pub const RETRY_STRATEGY: Sig = - Sig::new().returning(Sig::class(java::util::Optional::::PATH)); - pub const MAX_ATTEMPTS: Sig = - Sig::new().returning(Sig::class(java::util::Optional::::PATH)); +java::object_newtype!(Non); +impl java::Class for Non { + const PATH: &'static str = concat!(package!(dev.toad.RuntimeOptions), "$Msg$Non"); +} - pub fn retry_strategy(&self, e: &mut JNIEnv<'a>) -> Option { - let o = e.call_method(&self.0, "retryStrategy", Self::RETRY_STRATEGY, &[]) - .unwrap() - .l() - .unwrap(); - let g = e.new_global_ref(o).unwrap(); - java::util::Optional::::from_java(g).to_option(e) - .map(RetryStrategy::from_java) - .map(|j| j.to_toad(e)) +impl Non { + pub fn retry_strategy(&self, e: &mut java::Env) -> Option { + static RETRY_STRATEGY: java::Method java::util::Optional> = + java::Method::new("retryStrategy"); + RETRY_STRATEGY.invoke(e, self) + .to_option(e) + .map(|s| s.to_toad(e)) } - pub fn max_attempts(&self, e: &mut JNIEnv<'a>) -> Option { - let o = e.call_method(&self.0, "maxAttempts", Self::MAX_ATTEMPTS, &[]) - .unwrap() - .l() - .unwrap(); - let g = e.new_global_ref(o).unwrap(); - java::util::Optional::::from_java(g).to_option(e) - .map(java::lang::Integer::from_java) - .map(Primitive::dewrap) + pub fn max_attempts(&self, e: &mut java::Env) -> Option { + static MAX_ATTEMPTS: java::Method java::util::Optional> = + java::Method::new("maxAttempts"); + MAX_ATTEMPTS.invoke(e, self).to_option(e) } } diff --git a/glue/src/uint.rs b/glue/src/uint.rs index 99940e1..3ef42e4 100644 --- a/glue/src/uint.rs +++ b/glue/src/uint.rs @@ -1,139 +1,86 @@ use core::primitive as rust; -use jni::objects::{GlobalRef, JByteArray, JObject}; -use jni::JNIEnv; -use toad_jni::cls::java; -use toad_jni::convert::Object; -use toad_jni::Sig; +use toad_jni::java; #[allow(non_camel_case_types)] -pub struct u64(GlobalRef); +pub struct u64(java::lang::Object); + +java::object_newtype!(u64); +impl java::Class for u64 { + const PATH: &'static str = package!(dev.toad.ffi.u64); +} + impl u64 { - pub const PATH: &'static str = package!(dev.toad.ffi.u64); - pub const CTOR: Sig = Sig::new().arg(Sig::class(java::math::BigInteger::PATH)) - .returning(Sig::VOID); - pub const BIGINT_VALUE: Sig = Sig::new().returning(Sig::class(java::math::BigInteger::PATH)); - - pub fn to_rust<'a>(&self, e: &mut JNIEnv<'a>) -> rust::u64 { - let bi = e.call_method(self.0.as_obj(), "bigintValue", Self::BIGINT_VALUE, &[]) - .unwrap() - .l() - .unwrap(); - let bi = e.new_global_ref(bi).unwrap(); - let bi = java::math::BigInteger::from_java(bi); - bi.to_i128(e) as rust::u64 + pub fn to_rust(&self, e: &mut java::Env) -> rust::u64 { + static BIGINT_VALUE: java::Method java::math::BigInteger> = + java::Method::new("bigintValue"); + let bigint = BIGINT_VALUE.invoke(e, self); + bigint.to_i128(e) as rust::u64 } - pub fn from_rust<'a>(e: &mut JNIEnv<'a>, u: rust::u64) -> Self { + pub fn from_rust(e: &mut java::Env, u: rust::u64) -> Self { + static CTOR: java::Constructor = java::Constructor::new(); let bi = java::math::BigInteger::from_be_bytes(e, &i128::from(u).to_be_bytes()); - let bi = e.new_object(Self::PATH, Self::CTOR, &[bi.to_java().as_obj().into()]) - .unwrap(); - Self(e.new_global_ref(bi).unwrap()) - } -} - -impl Object for u64 { - fn from_java(jobj: GlobalRef) -> Self { - Self(jobj) - } - - fn to_java(self) -> GlobalRef { - self.0 + CTOR.invoke(e, bi) } } #[allow(non_camel_case_types)] -pub struct u32(GlobalRef); +pub struct u32(java::lang::Object); + +java::object_newtype!(u32); +impl java::Class for u32 { + const PATH: &'static str = package!(dev.toad.ffi.u32); +} + impl u32 { - pub const PATH: &'static str = package!(dev.toad.ffi.u32); - pub const CTOR: Sig = Sig::new().arg(Sig::LONG).returning(Sig::VOID); - pub const LONG_VALUE: Sig = Sig::new().returning(Sig::LONG); - - pub fn to_rust<'a>(&self, e: &mut JNIEnv<'a>) -> rust::u32 { - let long = e.call_method(self.0.as_obj(), "longValue", Self::LONG_VALUE, &[]) - .unwrap() - .j() - .unwrap(); - long as rust::u32 + pub fn to_rust(&self, e: &mut java::Env) -> rust::u32 { + static LONG_VALUE: java::Method i64> = java::Method::new("longValue"); + LONG_VALUE.invoke(e, self) as rust::u32 } - pub fn from_rust<'a>(e: &mut JNIEnv<'a>, u: rust::u32) -> Self { - let bi = e.new_object(Self::PATH, Self::CTOR, &[rust::i64::from(u).into()]) - .unwrap(); - Self(e.new_global_ref(bi).unwrap()) - } -} - -impl Object for u32 { - fn from_java(jobj: GlobalRef) -> Self { - Self(jobj) - } - - fn to_java(self) -> GlobalRef { - self.0 + pub fn from_rust(e: &mut java::Env, u: rust::u32) -> Self { + static CTOR: java::Constructor = java::Constructor::new(); + CTOR.invoke(e, u.into()) } } #[allow(non_camel_case_types)] -pub struct u16(GlobalRef); +pub struct u16(java::lang::Object); + +java::object_newtype!(u16); +impl java::Class for u16 { + const PATH: &'static str = package!(dev.toad.ffi.u16); +} + impl u16 { - pub const PATH: &'static str = package!(dev.toad.ffi.u16); - pub const CTOR: Sig = Sig::new().arg(Sig::INT).returning(Sig::VOID); - pub const INT_VALUE: Sig = Sig::new().returning(Sig::INT); - - pub fn to_rust<'a>(&self, e: &mut JNIEnv<'a>) -> rust::u16 { - let int = e.call_method(self.0.as_obj(), "intValue", Self::INT_VALUE, &[]) - .unwrap() - .i() - .unwrap(); - int as rust::u16 + pub fn to_rust(&self, e: &mut java::Env) -> rust::u16 { + static INT_VALUE: java::Method i32> = java::Method::new("intValue"); + INT_VALUE.invoke(e, self) as rust::u16 } - pub fn from_rust<'a>(e: &mut JNIEnv<'a>, u: rust::u16) -> Self { - let bi = e.new_object(Self::PATH, Self::CTOR, &[rust::i32::from(u).into()]) - .unwrap(); - Self(e.new_global_ref(bi).unwrap()) - } -} - -impl Object for u16 { - fn from_java(jobj: GlobalRef) -> Self { - Self(jobj) - } - - fn to_java(self) -> GlobalRef { - self.0 + pub fn from_rust(e: &mut java::Env, u: rust::u16) -> Self { + static CTOR: java::Constructor = java::Constructor::new(); + CTOR.invoke(e, u.into()) } } #[allow(non_camel_case_types)] -pub struct u8(GlobalRef); +pub struct u8(java::lang::Object); + +java::object_newtype!(u8); +impl java::Class for u8 { + const PATH: &'static str = package!(dev.toad.ffi.u8); +} + impl u8 { - pub const PATH: &'static str = package!(dev.toad.ffi.u8); - pub const CTOR: Sig = Sig::new().arg(Sig::SHORT).returning(Sig::VOID); - pub const SHORT_VALUE: Sig = Sig::new().returning(Sig::SHORT); - - pub fn to_rust<'a>(&self, e: &mut JNIEnv<'a>) -> rust::u8 { - let int = e.call_method(self.0.as_obj(), "shortValue", Self::SHORT_VALUE, &[]) - .unwrap() - .s() - .unwrap(); - int as rust::u8 + pub fn to_rust(&self, e: &mut java::Env) -> rust::u8 { + static SHORT_VALUE: java::Method i16> = java::Method::new("shortValue"); + SHORT_VALUE.invoke(e, self) as rust::u8 } - pub fn from_rust<'a>(e: &mut JNIEnv<'a>, u: rust::u8) -> Self { - let bi = e.new_object(Self::PATH, Self::CTOR, &[rust::i16::from(u).into()]) - .unwrap(); - Self(e.new_global_ref(bi).unwrap()) - } -} - -impl Object for u8 { - fn from_java(jobj: GlobalRef) -> Self { - Self(jobj) - } - - fn to_java(self) -> GlobalRef { - self.0 + pub fn from_rust(e: &mut java::Env, u: rust::u8) -> Self { + static CTOR: java::Constructor = java::Constructor::new(); + CTOR.invoke(e, u.into()) } } diff --git a/src/main/java/dev.toad/Runtime.java b/src/main/java/dev.toad/Runtime.java index 67b9146..d89158f 100644 --- a/src/main/java/dev.toad/Runtime.java +++ b/src/main/java/dev.toad/Runtime.java @@ -1,8 +1,16 @@ package dev.toad; +import dev.toad.msg.MessageRef; +import java.util.Optional; + public class Runtime { - public static native void init(RuntimeOptions o); + private final long addr; - private Runtime() {} + private static native long init(RuntimeOptions o); + private native Optional pollReq(RuntimeOptions o); + + public Runtime(RuntimeOptions o) { + this.addr = Runtime.init(o); + } }