feat: update toad-jni

This commit is contained in:
Orion Kindel 2023-04-08 10:35:23 -07:00
parent 7c96dd576b
commit 7eef137bcd
Signed by untrusted user who does not match committer: orion
GPG Key ID: 6D4165AE4C928719
15 changed files with 486 additions and 517 deletions

View File

@ -1,2 +1,2 @@
[build]
target-dir = "../target/native"
target-dir = "../target/glue"

28
glue/Cargo.lock generated
View File

@ -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"

View File

@ -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"]}

View File

@ -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<dtls::N, Runtime<dtls::N>> = std::ptr::null();
pub unsafe fn with_runtime_provenance<T>(addr: i64) -> *mut T {
RUNTIME.with_addr(addr as usize).cast::<T>().cast_mut()
}
pub type Runtime =
toad::std::Platform<toad::std::dtls::N, toad::step::runtime::std::Runtime<toad::std::dtls::N>>;
#[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]

50
glue/src/mem.rs Normal file
View File

@ -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<T>(runtime_addr: i64, addr: i64) -> *mut T {
Self::deref(runtime_addr).with_addr(addr as usize)
.cast::<T>()
}
}
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::<crate::Runtime>()).cast::<crate::Runtime>();
*p = r;
RUNTIME = p;
RUNTIME
} else {
RUNTIME
}
}
unsafe fn deref(_: i64) -> *mut crate::Runtime {
RUNTIME
}
}

View File

@ -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<MessageCode, fn(i32, i32)> = java::Constructor::new();
CTOR.invoke(e, code.class.into(), code.detail.into())
}
}

View File

@ -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<MessageOptRef, fn(i64, i64)> = 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<MessageOptRef, i64> = java::Field::new("number");
OptNumber(NUMBER.get(env, self) as u32)
}
pub unsafe fn values_ptr<'a>(addr: i64) -> &'a mut Vec<OptValue<Vec<u8>>> {
with_runtime_provenance::<Vec<OptValue<Vec<u8>>>>(addr).as_mut()
.unwrap()
crate::mem::Runtime::deref_inner::<Vec<OptValue<Vec<u8>>>>(/* 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::<MessageOptRef>(&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<u8>).addr() as i64))
.collect::<Vec<_>>();
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()
}

View File

@ -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<MessageOptValueRef, fn(i64)> = java::Constructor::new();
CTOR.invoke(env, addr)
}
pub unsafe fn ptr<'a>(addr: i64) -> &'a mut OptValue<Vec<u8>> {
with_runtime_provenance::<OptValue<Vec<u8>>>(addr).as_mut()
.unwrap()
crate::mem::Runtime::deref_inner::<OptValue<Vec<u8>>>(/* 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 {

View File

@ -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<MessageRef, fn(i64)> = java::Constructor::new();
CTOR.invoke(env, addr.addr() as i64)
}
pub unsafe fn ptr<'a>(addr: i64) -> &'a mut Message {
with_runtime_provenance::<Message>(addr).as_mut().unwrap()
crate::mem::Runtime::deref_inner::<Message>(/* 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::<Vec<_>>();
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()
}

View File

@ -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, fn(String) -> 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())
}
}

View File

@ -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<RetryStrategyExp,
fn(java::time::Duration, java::time::Duration)> =
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<RetryStrategyExp, uint::u64> = 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<RetryStrategyExp, uint::u64> = 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<RetryStrategyDelay,
fn(java::time::Duration, java::time::Duration)> =
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<RetryStrategyDelay, uint::u64> = 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<RetryStrategyDelay, uint::u64> = 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::<RetryStrategyExp>(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::<RetryStrategyDelay>(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
}
}
}

69
glue/src/runtime.rs Normal file
View File

@ -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<Runtime, i64> = 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::<RuntimeConfig>(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::<Runtime>(e);
match runtime.ref_(e).poll_req() {
| Ok(req) => {
let mr = MessageRef::new(e, req.data().msg());
java::util::Optional::<MessageRef>::of(e, mr).downcast(e)
.as_raw()
},
| Err(nb::Error::WouldBlock) => java::util::Optional::<MessageRef>::empty(e).downcast(e)
.as_raw(),
| Err(nb::Error::Other(err)) => {
e.throw(format!("{:?}", err)).unwrap();
core::ptr::null_mut()
},
}
}

View File

@ -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<RuntimeConfig, fn()> = 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<RuntimeConfig, fn() -> 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<Net, fn() -> 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<Net, fn() -> 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<Net, fn() -> 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::<jint>::PATH));
pub const PROBING_RATE: Sig =
Sig::new().returning(Sig::class(java::util::Optional::<jint>::PATH));
pub const MULTICAST_RESP_LEISURE: Sig =
Sig::new().returning(Sig::class(java::util::Optional::<GlobalRef>::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<jint> {
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::<jint>::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<i32> {
static TOKEN_SEED: java::Method<Msg, fn() -> java::util::Optional<i32>> =
java::Method::new("tokenSeed");
TOKEN_SEED.invoke(e, self).to_option(e)
}
pub fn probing_rate(&self, e: &mut JNIEnv<'a>) -> Option<jint> {
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::<jint>::from_java(g).to_option(e)
pub fn probing_rate(&self, e: &mut java::Env) -> Option<i32> {
static PROBING_RATE: java::Method<Msg, fn() -> java::util::Optional<i32>> =
java::Method::new("probingRateBytesPerSecond");
PROBING_RATE.invoke(e, self).to_option(e)
}
pub fn multicast_response_leisure(&self, e: &mut JNIEnv<'a>) -> Option<Millis> {
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::<GlobalRef>::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<Millis> {
static MULTICAST_RESP_LEISURE: java::Method<Msg,
fn()
-> java::util::Optional<java::time::Duration>> =
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<Msg, fn() -> 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<Msg, fn() -> 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::<GlobalRef>::PATH));
pub const UNACKED_RETRY_STRATEGY: Sig =
Sig::new().returning(Sig::class(java::util::Optional::<GlobalRef>::PATH));
pub const MAX_ATTEMPTS: Sig =
Sig::new().returning(Sig::class(java::util::Optional::<jint>::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<Strategy> {
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::<GlobalRef>::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<Strategy> {
static ACKED_RETRY_STRATEGY: java::Method<Con, fn() -> java::util::Optional<RetryStrategy>> =
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<Strategy> {
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::<GlobalRef>::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<Strategy> {
static UNACKED_RETRY_STRATEGY: java::Method<Con, fn() -> java::util::Optional<RetryStrategy>> =
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<jint> {
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::<GlobalRef>::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<i32> {
static MAX_ATTEMPTS: java::Method<Con, fn() -> java::util::Optional<i32>> =
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::<GlobalRef>::PATH));
pub const MAX_ATTEMPTS: Sig =
Sig::new().returning(Sig::class(java::util::Optional::<jint>::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<Strategy> {
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::<GlobalRef>::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<Strategy> {
static RETRY_STRATEGY: java::Method<Non, fn() -> java::util::Optional<RetryStrategy>> =
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<jint> {
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::<GlobalRef>::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<i32> {
static MAX_ATTEMPTS: java::Method<Non, fn() -> java::util::Optional<i32>> =
java::Method::new("maxAttempts");
MAX_ATTEMPTS.invoke(e, self).to_option(e)
}
}

View File

@ -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<u64, fn() -> 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<u64, fn(java::math::BigInteger)> = 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<u32, fn() -> 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<u32, fn(i64)> = 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<u16, fn() -> 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<u16, fn(i32)> = 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<u8, fn() -> 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<u8, fn(i16)> = java::Constructor::new();
CTOR.invoke(e, u.into())
}
}

View File

@ -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<MessageRef> pollReq(RuntimeOptions o);
public Runtime(RuntimeOptions o) {
this.addr = Runtime.init(o);
}
}