refactor: rework msg module structure

This commit is contained in:
Orion Kindel 2023-04-11 16:29:23 -05:00
parent 913ed46e13
commit 8679ae0a78
Signed by untrusted user who does not match committer: orion
GPG Key ID: 6D4165AE4C928719
41 changed files with 703 additions and 632 deletions

View File

@ -29,7 +29,7 @@ lazy val root = project
Compile / doc / javacOptions ++= Seq(
"--enable-preview",
"--release",
"20",
"20"
),
Compile / compile / javacOptions ++= Seq(
"--enable-preview",

1
glue/src/dev/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod toad;

View File

@ -0,0 +1,2 @@
mod uint;
pub use uint::{u16, u32, u64, u8};

View File

@ -1,42 +1,95 @@
pub mod ffi;
pub mod msg;
mod retry_strategy;
use std::net::{Ipv4Addr, SocketAddr};
use jni::objects::JClass;
use jni::objects::{JClass, JObject};
use jni::sys::jobject;
use toad::config::{self, BytesPerSecond, Config};
pub use retry_strategy::RetryStrategy;
use toad::platform::Platform;
use toad::retry::{Attempts, Strategy};
use toad::time::Millis;
use toad_jni::java::{self, Class, Object};
use toad_jni::java::{self, Object};
use crate::retry_strategy::RetryStrategy;
use crate::uint;
use crate::mem::{Shared, SharedMemoryRegion};
use crate::Runtime;
pub struct RuntimeConfig(java::lang::Object);
pub struct Toad(java::lang::Object);
java::object_newtype!(RuntimeConfig);
impl java::Class for RuntimeConfig {
const PATH: &'static str = concat!(package!(dev.toad.ToadRuntime), "$Config");
impl Toad {
pub fn new(e: &mut java::Env, cfg: Config) -> Self {
static CTOR: java::Constructor<Toad, fn(Config)> = java::Constructor::new();
CTOR.invoke(e, cfg)
}
pub fn poll_req(&self, e: &mut java::Env) -> Option<msg::ref_::Message> {
static POLL_REQ: java::Method<Toad, fn() -> java::util::Optional<msg::ref_::Message>> =
java::Method::new("pollReq");
POLL_REQ.invoke(e, self).to_option(e)
}
pub fn config(&self, e: &mut java::Env) -> Config {
static CONFIG: java::Method<Toad, fn() -> Config> = java::Method::new("config");
CONFIG.invoke(e, self)
}
fn init_impl(e: &mut java::Env, cfg: Config) -> i64 {
let r = || Runtime::try_new(cfg.addr(e), cfg.to_toad(e)).unwrap();
unsafe { crate::mem::Shared::init(r).addr() as i64 }
}
fn poll_req_impl(e: &mut java::Env, addr: i64) -> java::util::Optional<msg::ref_::Message> {
match unsafe {
Shared::deref::<Runtime>(/* TODO */ 0, addr).as_ref()
.unwrap()
}.poll_req()
{
| Ok(req) => {
let mr = msg::ref_::Message::new(e, req.unwrap().into());
java::util::Optional::<msg::ref_::Message>::of(e, mr)
},
| Err(nb::Error::WouldBlock) => java::util::Optional::<msg::ref_::Message>::empty(e),
| Err(nb::Error::Other(err)) => {
e.throw(format!("{:?}", err)).unwrap();
java::util::Optional::<msg::ref_::Message>::empty(e)
},
}
}
}
impl RuntimeConfig {
java::object_newtype!(Toad);
impl java::Class for Toad {
const PATH: &'static str = package!(dev.toad.Toad);
}
pub struct Config(java::lang::Object);
java::object_newtype!(Config);
impl java::Class for Config {
const PATH: &'static str = concat!(package!(dev.toad.Toad), "$Config");
}
impl Config {
pub fn addr(&self, e: &mut java::Env) -> SocketAddr {
static ADDRESS: java::Field<RuntimeConfig, java::net::InetSocketAddress> =
java::Field::new("addr");
static ADDRESS: java::Field<Config, java::net::InetSocketAddress> = java::Field::new("addr");
ADDRESS.get(e, self).to_std(e)
}
pub fn concurrency(&self, e: &mut java::Env) -> u8 {
static RUNTIME_CONFIG_CONCURRENCY: java::Field<RuntimeConfig, uint::u8> =
static RUNTIME_CONFIG_CONCURRENCY: java::Field<Config, ffi::u8> =
java::Field::new("concurrency");
RUNTIME_CONFIG_CONCURRENCY.get(e, self).to_rust(e)
}
pub fn msg(&self, e: &mut java::Env) -> Msg {
static RUNTIME_CONFIG_MSG: java::Method<RuntimeConfig, fn() -> Msg> = java::Method::new("msg");
static RUNTIME_CONFIG_MSG: java::Method<Config, fn() -> Msg> = java::Method::new("msg");
RUNTIME_CONFIG_MSG.invoke(e, self)
}
pub fn new(e: &mut java::Env, c: Config, addr: SocketAddr) -> Self {
static CTOR: java::Constructor<RuntimeConfig, fn(java::net::InetSocketAddress, uint::u8, Msg)> =
pub fn new(e: &mut java::Env, c: toad::config::Config, addr: SocketAddr) -> Self {
static CTOR: java::Constructor<Config, fn(java::net::InetSocketAddress, ffi::u8, Msg)> =
java::Constructor::new();
let con = Con::new(e,
@ -51,7 +104,7 @@ impl RuntimeConfig {
con,
non);
let concurrency = uint::u8::from_rust(e, c.max_concurrent_requests);
let concurrency = ffi::u8::from_rust(e, c.max_concurrent_requests);
let address = java::net::InetSocketAddress::from_std(e, addr);
@ -59,23 +112,23 @@ impl RuntimeConfig {
jcfg
}
pub fn to_toad(&self, e: &mut java::Env) -> config::Config {
pub fn to_toad(&self, e: &mut java::Env) -> toad::config::Config {
let msg = self.msg(e);
let con = msg.con(e);
let non = msg.non(e);
config::Config { max_concurrent_requests: self.concurrency(e) as u8,
msg: config::Msg { token_seed: msg.token_seed(e) as _,
probing_rate: BytesPerSecond(msg.probing_rate(e) as _),
toad::config::Config { max_concurrent_requests: self.concurrency(e) as u8,
msg: toad::config::Msg { token_seed: msg.token_seed(e) as _,
probing_rate: toad::config::BytesPerSecond(msg.probing_rate(e) as _),
multicast_response_leisure:
msg.multicast_response_leisure(e),
con: config::Con { unacked_retry_strategy:
con: toad::config::Con { unacked_retry_strategy:
con.unacked_retry_strategy(e),
acked_retry_strategy:
con.acked_retry_strategy(e),
max_attempts:
Attempts(con.max_attempts(e) as _) },
non: config::Non { retry_strategy:
non: toad::config::Non { retry_strategy:
non.retry_strategy(e),
max_attempts:
Attempts(non.max_attempts(e) as _) } } }
@ -87,7 +140,7 @@ pub struct Msg(java::lang::Object);
java::object_newtype!(Msg);
impl java::Class for Msg {
const PATH: &'static str = concat!(package!(dev.toad.ToadRuntime), "$Config$Msg");
const PATH: &'static str = concat!(package!(dev.toad.Toad), "$Config$Msg");
}
impl Msg {
@ -98,10 +151,10 @@ impl Msg {
con: Con,
non: Non)
-> Self {
static CTOR: java::Constructor<Msg, fn(uint::u16, uint::u16, java::time::Duration, Con, Non)> =
static CTOR: java::Constructor<Msg, fn(ffi::u16, ffi::u16, java::time::Duration, Con, Non)> =
java::Constructor::new();
let token_seed = uint::u16::from_rust(e, token_seed);
let probe_rate = uint::u16::from_rust(e, probe_rate);
let token_seed = ffi::u16::from_rust(e, token_seed);
let probe_rate = ffi::u16::from_rust(e, probe_rate);
let multicast_response_leisure =
java::time::Duration::of_millis(e, multicast_response_leisure.0 as i64);
@ -147,20 +200,20 @@ pub struct Con(java::lang::Object);
java::object_newtype!(Con);
impl java::Class for Con {
const PATH: &'static str = concat!(package!(dev.toad.ToadRuntime), "$Config$Msg$Con");
const PATH: &'static str = concat!(package!(dev.toad.Toad), "$Config$Msg$Con");
}
impl Con {
pub fn new(e: &mut java::Env,
unacked: toad::retry::Strategy,
acked: toad::retry::Strategy,
unacked: Strategy,
acked: Strategy,
max_attempts: Attempts)
-> Self {
static CTOR: java::Constructor<Con, fn(RetryStrategy, RetryStrategy, uint::u16)> =
static CTOR: java::Constructor<Con, fn(RetryStrategy, RetryStrategy, ffi::u16)> =
java::Constructor::new();
let unacked = RetryStrategy::from_toad(e, unacked);
let acked = RetryStrategy::from_toad(e, acked);
let att = uint::u16::from_rust(e, max_attempts.0);
let att = ffi::u16::from_rust(e, max_attempts.0);
CTOR.invoke(e, unacked, acked, att)
}
@ -186,14 +239,14 @@ pub struct Non(java::lang::Object);
java::object_newtype!(Non);
impl java::Class for Non {
const PATH: &'static str = concat!(package!(dev.toad.ToadRuntime), "$Config$Msg$Non");
const PATH: &'static str = concat!(package!(dev.toad.Toad), "$Config$Msg$Non");
}
impl Non {
pub fn new(e: &mut java::Env, strat: toad::retry::Strategy, max_attempts: Attempts) -> Self {
static CTOR: java::Constructor<Non, fn(RetryStrategy, uint::u16)> = java::Constructor::new();
pub fn new(e: &mut java::Env, strat: Strategy, max_attempts: Attempts) -> Self {
static CTOR: java::Constructor<Non, fn(RetryStrategy, ffi::u16)> = java::Constructor::new();
let strat = RetryStrategy::from_toad(e, strat);
let att = uint::u16::from_rust(e, max_attempts.0);
let att = ffi::u16::from_rust(e, max_attempts.0);
CTOR.invoke(e, strat, att)
}
@ -210,10 +263,30 @@ impl Non {
}
#[no_mangle]
pub extern "system" fn Java_dev_toad_Runtime_defaultConfigImpl<'local>(mut env: java::Env<'local>,
_: JClass<'local>)
-> jobject {
RuntimeConfig::new(&mut env,
Config::default(),
SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), 5683)).yield_to_java(&mut env)
pub extern "system" fn Java_dev_toad_Toad_defaultConfigImpl<'local>(mut env: java::Env<'local>,
_: JClass<'local>)
-> jobject {
Config::new(&mut env,
toad::config::Config::default(),
SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), 5683)).yield_to_java(&mut env)
}
#[no_mangle]
pub extern "system" fn Java_dev_toad_Toad_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::<Config>(e);
Toad::init_impl(e, cfg)
}
#[no_mangle]
pub extern "system" fn Java_dev_toad_Toad_pollReq<'local>(mut e: java::Env<'local>,
_: JClass<'local>,
addr: i64)
-> jobject {
let e = &mut e;
Toad::poll_req_impl(e, addr).yield_to_java(e)
}

View File

@ -0,0 +1,15 @@
use toad_jni::java;
pub struct Code(java::lang::Object);
java::object_newtype!(Code);
impl java::Class for Code {
const PATH: &'static str = package!(dev.toad.msg.Code);
}
impl Code {
pub fn new(e: &mut java::Env, code: toad_msg::Code) -> Self {
static CTOR: java::Constructor<Code, fn(i32, i32)> = java::Constructor::new();
CTOR.invoke(e, code.class.into(), code.detail.into())
}
}

View File

@ -0,0 +1,7 @@
pub mod ref_;
mod ty;
pub use ty::Type;
mod code;
pub use code::Code;

View File

@ -0,0 +1,8 @@
mod opt;
pub use opt::Opt;
mod msg;
pub use msg::Message;
mod opt_value;
pub use opt_value::OptValue;

View File

@ -0,0 +1,97 @@
use jni::objects::JClass;
use jni::sys::jobject;
use toad_jni::java::{self, Object};
use crate::dev::toad::msg::ref_::Opt;
use crate::dev::toad::msg::{Code, Type};
use crate::mem::{Shared, SharedMemoryRegion};
pub struct Message(java::lang::Object);
java::object_newtype!(Message);
impl java::Class for Message {
const PATH: &'static str = package!(dev.toad.msg.ref.Message);
}
impl Message {
pub fn new(env: &mut java::Env, message: toad_msg::alloc::Message) -> Self {
let ptr = unsafe { Shared::alloc_message(message) };
static CTOR: java::Constructor<Message, fn(i64)> = java::Constructor::new();
CTOR.invoke(env, ptr.addr() as i64)
}
pub fn close(&self, env: &mut java::Env) {
static CLOSE: java::Method<Message, fn()> = java::Method::new("close");
CLOSE.invoke(env, self)
}
pub fn ty(&self, env: &mut java::Env) -> toad_msg::Type {
static TYPE: java::Method<Message, fn() -> Type> = java::Method::new("type");
TYPE.invoke(env, self).to_toad(env)
}
pub unsafe fn ptr<'a>(addr: i64) -> &'a mut toad_msg::alloc::Message {
crate::mem::Shared::deref::<toad_msg::alloc::Message>(/* TODO */ 0, addr).as_mut()
.unwrap()
}
}
#[no_mangle]
pub extern "system" fn Java_dev_toad_msg_ref_Message_id<'local>(mut env: java::Env<'local>,
_: JClass<'local>,
addr: i64)
-> i32 {
let msg = unsafe { Message::ptr(addr) };
msg.id.0 as i32
}
#[no_mangle]
pub extern "system" fn Java_dev_toad_msg_ref_Message_token<'local>(mut env: java::Env<'local>,
_: JClass<'local>,
addr: i64)
-> jobject {
let msg = unsafe { Message::ptr(addr) };
env.byte_array_from_slice(&msg.token.0).unwrap().as_raw()
}
#[no_mangle]
pub extern "system" fn Java_dev_toad_msg_ref_Message_payload<'local>(mut env: java::Env<'local>,
_: JClass<'local>,
addr: i64)
-> jobject {
let msg = unsafe { Message::ptr(addr) };
env.byte_array_from_slice(&msg.payload.0).unwrap().as_raw()
}
#[no_mangle]
pub extern "system" fn Java_dev_toad_msg_ref_Message_type<'local>(mut e: java::Env<'local>,
_: JClass<'local>,
addr: i64)
-> jobject {
let msg = unsafe { Message::ptr(addr) };
Type::new(&mut e, msg.ty).yield_to_java(&mut e)
}
#[no_mangle]
pub extern "system" fn Java_dev_toad_msg_ref_Message_code<'local>(mut e: java::Env<'local>,
_: JClass<'local>,
addr: i64)
-> jobject {
let msg = unsafe { Message::ptr(addr) };
Code::new(&mut e, msg.code).yield_to_java(&mut e)
}
#[no_mangle]
pub extern "system" fn Java_dev_toad_msg_ref_Message_opts<'local>(mut e: java::Env<'local>,
_: JClass<'local>,
addr: i64)
-> jobject {
let msg = unsafe { Message::ptr(addr) };
let opts = &msg.opts;
let refs = opts.into_iter()
.map(|(n, v)| Opt::new(&mut e, v as *const _ as i64, n.0.into()))
.collect::<Vec<_>>();
refs.yield_to_java(&mut e)
}

View File

@ -0,0 +1,57 @@
use jni::objects::{JClass, JObject};
use jni::sys::jobject;
use jni::JNIEnv;
use toad_jni::java::{self, Object};
use toad_msg::OptNumber;
use super::OptValue;
use crate::mem::SharedMemoryRegion;
pub struct Opt(pub java::lang::Object);
java::object_newtype!(Opt);
impl java::Class for Opt {
const PATH: &'static str = package!(dev.toad.msg.ref.Option);
}
impl Opt {
pub fn new(env: &mut java::Env, addr: i64, num: i64) -> Self {
static CTOR: java::Constructor<Opt, fn(i64, i64)> = java::Constructor::new();
CTOR.invoke(env, addr, num)
}
pub fn number(&self, env: &mut java::Env) -> OptNumber {
static NUMBER: java::Field<Opt, i64> = java::Field::new("number");
OptNumber(NUMBER.get(env, self) as u32)
}
pub unsafe fn values_ptr<'a>(addr: i64) -> &'a mut Vec<toad_msg::OptValue<Vec<u8>>> {
crate::mem::Shared::deref::<Vec<toad_msg::OptValue<Vec<u8>>>>(/* TODO */ 0, addr).as_mut()
.unwrap()
}
}
#[no_mangle]
pub extern "system" fn Java_dev_toad_msg_Option_number<'local>(mut env: JNIEnv<'local>,
o: JObject<'local>,
p: i64)
-> i64 {
java::lang::Object::from_local(&mut env, o).upcast_to::<Opt>(&mut env)
.number(&mut env)
.0 as i64
}
#[no_mangle]
pub extern "system" fn Java_dev_toad_msg_Option_values<'local>(mut e: JNIEnv<'local>,
_: JClass<'local>,
p: i64)
-> jobject {
let o = &unsafe { Opt::values_ptr(p) };
let refs = o.iter()
.map(|v| OptValue::new(&mut e, (&v.0 as *const Vec<u8>).addr() as i64))
.collect::<Vec<_>>();
refs.yield_to_java(&mut e)
}

View File

@ -0,0 +1,33 @@
use jni::objects::JClass;
use jni::sys::jobject;
use toad_jni::java;
use crate::mem::SharedMemoryRegion;
pub struct OptValue(java::lang::Object);
java::object_newtype!(OptValue);
impl java::Class for OptValue {
const PATH: &'static str = package!(dev.toad.msg.ref.OptionValue);
}
impl OptValue {
pub fn new(env: &mut java::Env, addr: i64) -> Self {
static CTOR: java::Constructor<OptValue, fn(i64)> = java::Constructor::new();
CTOR.invoke(env, addr)
}
pub unsafe fn ptr<'a>(addr: i64) -> &'a mut toad_msg::OptValue<Vec<u8>> {
crate::mem::Shared::deref::<toad_msg::OptValue<Vec<u8>>>(/* TODO */ 0, addr).as_mut()
.unwrap()
}
}
#[no_mangle]
pub extern "system" fn Java_dev_toad_msg_ref_OptionValue_bytes<'local>(mut env: java::Env<'local>,
_: JClass<'local>,
p: i64)
-> jobject {
let val = unsafe { OptValue::ptr(p) };
env.byte_array_from_slice(val.as_bytes()).unwrap().as_raw()
}

View File

@ -0,0 +1,36 @@
use toad_jni::java;
pub struct Type(java::lang::Object);
java::object_newtype!(Type);
impl java::Class for Type {
const PATH: &'static str = package!(dev.toad.msg.Type);
}
impl Type {
pub fn new(env: &mut java::Env, ty: toad_msg::Type) -> Self {
static FROM_STRING: java::StaticMethod<Type, fn(String) -> Type> =
java::StaticMethod::new("fromString");
let str = match ty {
| toad_msg::Type::Con => "CON",
| toad_msg::Type::Non => "NON",
| toad_msg::Type::Ack => "ACK",
| toad_msg::Type::Reset => "RESET",
};
FROM_STRING.invoke(env, str.to_string())
}
pub fn to_toad(&self, env: &mut java::Env) -> toad_msg::Type {
static TO_STRING: java::Method<Type, fn() -> String> = java::Method::new("toString");
match TO_STRING.invoke(env, self).trim().to_uppercase().as_str() {
| "CON" => toad_msg::Type::Con,
| "NON" => toad_msg::Type::Non,
| "ACK" => toad_msg::Type::Ack,
| "RESET" => toad_msg::Type::Reset,
| o => panic!("malformed message type {}", o),
}
}
}

View File

@ -2,7 +2,7 @@ use toad::retry::Strategy;
use toad::time::Millis;
use toad_jni::java::{self, Object};
use crate::uint;
use crate::dev::toad::ffi;
pub struct RetryStrategyExp(java::lang::Object);
@ -26,12 +26,12 @@ impl RetryStrategyExp {
}
pub fn init_min(&self, e: &mut java::Env) -> Millis {
static INIT_MIN: java::Field<RetryStrategyExp, uint::u64> = java::Field::new("initMin");
static INIT_MIN: java::Field<RetryStrategyExp, ffi::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");
static INIT_MAX: java::Field<RetryStrategyExp, ffi::u64> = java::Field::new("initMax");
Millis::new(INIT_MAX.get(e, self).to_rust(e))
}
}
@ -58,12 +58,12 @@ impl RetryStrategyDelay {
}
pub fn min(&self, e: &mut java::Env) -> Millis {
static MIN: java::Field<RetryStrategyDelay, uint::u64> = java::Field::new("min");
static MIN: java::Field<RetryStrategyDelay, ffi::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");
static MAX: java::Field<RetryStrategyDelay, ffi::u64> = java::Field::new("max");
Millis::new(MAX.get(e, self).to_rust(e))
}
}

View File

@ -6,13 +6,11 @@ use toad_jni::java::{self, Object, Signature};
use toad_msg::alloc::Message;
use toad_msg::{Code, Id, Token, Type};
use crate::message_type::MessageType;
use crate::runtime::Runtime;
use crate::runtime_config::RuntimeConfig;
use crate::{dev, Runtime};
#[non_exhaustive]
struct State {
pub runtime: Runtime,
pub runtime: dev::toad::Toad,
pub env: java::Env<'static>,
pub client: crate::Runtime,
pub srv_addr: SocketAddr,
@ -22,12 +20,12 @@ fn init() -> State {
let mut _env = crate::test::init();
let env = &mut _env;
let cfg = RuntimeConfig::new(env,
Config::default(),
std::net::SocketAddr::new(std::net::Ipv4Addr::UNSPECIFIED.into(),
5683));
let runtime = Runtime::new(env, cfg);
let client = crate::Runtime::try_new("0.0.0.0:5684", Default::default()).unwrap();
let cfg =
dev::toad::Config::new(env,
Config::default(),
std::net::SocketAddr::new(std::net::Ipv4Addr::UNSPECIFIED.into(), 5683));
let runtime = dev::toad::Toad::new(env, cfg);
let client = Runtime::try_new("0.0.0.0:5684", Default::default()).unwrap();
State { runtime,
env: _env,
@ -60,7 +58,7 @@ fn message_ref_should_throw_when_used_after_close(State {runtime, env, client, s
let req_o = req.downcast(env);
env.call_method(req_o.as_local(),
"type",
Signature::of::<fn() -> MessageType>(),
Signature::of::<fn() -> dev::toad::msg::Type>(),
&[])
.ok();

View File

@ -5,8 +5,8 @@ use std::ffi::c_void;
use jni::JavaVM;
use mem::SharedMemoryRegion;
pub type Runtime =
toad::std::Platform<toad::std::dtls::N, toad::step::runtime::std::Runtime<toad::std::dtls::N>>;
pub type Runtime = ::toad::std::Platform<::toad::std::dtls::N,
::toad::step::runtime::std::Runtime<::toad::std::dtls::N>>;
#[macro_export]
macro_rules! package {
@ -15,16 +15,8 @@ macro_rules! package {
(ext $start:ident.$($thing:ident).+) => {concat!(stringify!($start), $("/", stringify!($thing)),+)};
}
pub mod dev;
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;
#[no_mangle]
pub extern "system" fn JNI_OnLoad(jvm: JavaVM, _: *const c_void) -> i32 {
@ -51,8 +43,7 @@ pub mod test {
use toad::time::Millis;
use toad_jni::java;
use crate::retry_strategy::RetryStrategy;
use crate::runtime_config::RuntimeConfig;
use crate::dev;
pub fn init<'a>() -> java::Env<'a> {
static INIT: Once = Once::new();
@ -82,9 +73,9 @@ pub mod test {
let mut e = init();
let e = &mut e;
let r = RuntimeConfig::new(e,
Config::default(),
SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), 5683));
let r = dev::toad::Config::new(e,
Config::default(),
SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), 5683));
assert_eq!(r.to_toad(e), Config::default());
}
@ -95,24 +86,23 @@ pub mod test {
let r = Strategy::Exponential { init_min: Millis::new(0),
init_max: Millis::new(100) };
assert_eq!(RetryStrategy::from_toad(e, r).to_toad(e), r);
assert_eq!(dev::toad::RetryStrategy::from_toad(e, r).to_toad(e), r);
let r = Strategy::Delay { min: Millis::new(0),
max: Millis::new(100) };
assert_eq!(RetryStrategy::from_toad(e, r).to_toad(e), r);
assert_eq!(dev::toad::RetryStrategy::from_toad(e, r).to_toad(e), r);
}
#[test]
fn uint() {
use crate::uint;
let mut e = init();
let e = &mut e;
macro_rules! case {
($u:ident) => {{
assert_eq!(uint::$u::from_rust(e, $u::MAX).to_rust(e), $u::MAX);
assert_eq!(uint::$u::from_rust(e, 0).to_rust(e), 0);
assert_eq!(dev::toad::ffi::$u::from_rust(e, $u::MAX).to_rust(e),
$u::MAX);
assert_eq!(dev::toad::ffi::$u::from_rust(e, 0).to_rust(e), 0);
}};
}

View File

@ -1,16 +0,0 @@
use toad_jni::java;
use toad_msg::Code;
pub struct MessageCode(java::lang::Object);
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,57 +0,0 @@
use jni::objects::{JClass, JObject};
use jni::sys::jobject;
use jni::JNIEnv;
use toad_jni::java::{self, Object};
use toad_msg::{OptNumber, OptValue};
use crate::mem::SharedMemoryRegion;
use crate::message_opt_value_ref::MessageOptValueRef;
pub struct MessageOptRef(pub java::lang::Object);
java::object_newtype!(MessageOptRef);
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 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>>> {
crate::mem::Shared::deref::<Vec<OptValue<Vec<u8>>>>(/* TODO */ 0, addr).as_mut()
.unwrap()
}
}
#[no_mangle]
pub extern "system" fn Java_dev_toad_msg_MessageOptionRef_number<'local>(mut env: JNIEnv<'local>,
o: JObject<'local>,
p: i64)
-> 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 e: JNIEnv<'local>,
_: JClass<'local>,
p: i64)
-> jobject {
let o = &unsafe { MessageOptRef::values_ptr(p) };
let refs = o.iter()
.map(|v| MessageOptValueRef::new(&mut e, (&v.0 as *const Vec<u8>).addr() as i64))
.collect::<Vec<_>>();
refs.yield_to_java(&mut e)
}

View File

@ -1,34 +0,0 @@
use jni::objects::JClass;
use jni::sys::jobject;
use toad_jni::java;
use toad_msg::OptValue;
use crate::mem::SharedMemoryRegion;
pub struct MessageOptValueRef(java::lang::Object);
java::object_newtype!(MessageOptValueRef);
impl java::Class for MessageOptValueRef {
const PATH: &'static str = package!(dev.toad.msg.MessageOptionValueRef);
}
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>> {
crate::mem::Shared::deref::<OptValue<Vec<u8>>>(/* TODO */ 0, addr).as_mut()
.unwrap()
}
}
#[no_mangle]
pub extern "system" fn Java_dev_toad_msg_MessageOptionValueRef_bytes<'local>(mut env: java::Env<'local>,
_: JClass<'local>,
p: i64)
-> jobject {
let val = unsafe { MessageOptValueRef::ptr(p) };
env.byte_array_from_slice(val.as_bytes()).unwrap().as_raw()
}

View File

@ -1,100 +0,0 @@
use jni::objects::JClass;
use jni::sys::jobject;
use toad_jni::java::{self, Object};
use toad_msg::alloc::Message;
use toad_msg::Type;
use crate::mem::{Shared, SharedMemoryRegion};
use crate::message_code::MessageCode;
use crate::message_opt_ref::MessageOptRef;
use crate::message_type::MessageType;
pub struct MessageRef(java::lang::Object);
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, message: Message) -> Self {
let ptr = unsafe { Shared::alloc_message(message) };
static CTOR: java::Constructor<MessageRef, fn(i64)> = java::Constructor::new();
CTOR.invoke(env, ptr.addr() as i64)
}
pub fn close(&self, env: &mut java::Env) {
static CLOSE: java::Method<MessageRef, fn()> = java::Method::new("close");
CLOSE.invoke(env, self)
}
pub fn ty(&self, env: &mut java::Env) -> Type {
static TYPE: java::Method<MessageRef, fn() -> MessageType> = java::Method::new("type");
TYPE.invoke(env, self).to_toad(env)
}
pub unsafe fn ptr<'a>(addr: i64) -> &'a mut Message {
crate::mem::Shared::deref::<Message>(/* TODO */ 0, addr).as_mut()
.unwrap()
}
}
#[no_mangle]
pub extern "system" fn Java_dev_toad_msg_MessageRef_id<'local>(mut env: java::Env<'local>,
_: JClass<'local>,
addr: i64)
-> i32 {
let msg = unsafe { MessageRef::ptr(addr) };
msg.id.0 as i32
}
#[no_mangle]
pub extern "system" fn Java_dev_toad_msg_MessageRef_token<'local>(mut env: java::Env<'local>,
_: JClass<'local>,
addr: i64)
-> jobject {
let msg = unsafe { MessageRef::ptr(addr) };
env.byte_array_from_slice(&msg.token.0).unwrap().as_raw()
}
#[no_mangle]
pub extern "system" fn Java_dev_toad_msg_MessageRef_payload<'local>(mut env: java::Env<'local>,
_: JClass<'local>,
addr: i64)
-> jobject {
let msg = unsafe { MessageRef::ptr(addr) };
env.byte_array_from_slice(&msg.payload.0).unwrap().as_raw()
}
#[no_mangle]
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 e, msg.ty).yield_to_java(&mut e)
}
#[no_mangle]
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 e, msg.code).yield_to_java(&mut e)
}
#[no_mangle]
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 refs = opts.into_iter()
.map(|(n, v)| MessageOptRef::new(&mut e, v as *const _ as i64, n.0.into()))
.collect::<Vec<_>>();
refs.yield_to_java(&mut e)
}

View File

@ -1,37 +0,0 @@
use toad_jni::java;
use toad_msg::Type;
pub struct MessageType(java::lang::Object);
java::object_newtype!(MessageType);
impl java::Class for MessageType {
const PATH: &'static str = package!(dev.toad.msg.MessageType);
}
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");
let str = match ty {
| Type::Con => "CON",
| Type::Non => "NON",
| Type::Ack => "ACK",
| Type::Reset => "RESET",
};
FROM_STRING.invoke(env, str.to_string())
}
pub fn to_toad(&self, env: &mut java::Env) -> Type {
static TO_STRING: java::Method<MessageType, fn() -> String> = java::Method::new("toString");
match TO_STRING.invoke(env, self).trim().to_uppercase().as_str() {
| "CON" => Type::Con,
| "NON" => Type::Non,
| "ACK" => Type::Ack,
| "RESET" => Type::Reset,
| o => panic!("malformed message type {}", o),
}
}
}

View File

@ -1,78 +0,0 @@
use jni::objects::{JClass, JObject};
use jni::sys::jobject;
use toad::platform::Platform;
use toad_jni::java::{self, Object};
use crate::mem::{Shared, SharedMemoryRegion};
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 new(e: &mut java::Env, cfg: RuntimeConfig) -> Self {
static CTOR: java::Constructor<Runtime, fn(RuntimeConfig)> = java::Constructor::new();
CTOR.invoke(e, cfg)
}
pub fn poll_req(&self, e: &mut java::Env) -> Option<MessageRef> {
static POLL_REQ: java::Method<Runtime, fn() -> java::util::Optional<MessageRef>> =
java::Method::new("pollReq");
POLL_REQ.invoke(e, self).to_option(e)
}
pub fn config(&self, e: &mut java::Env) -> RuntimeConfig {
static CONFIG: java::Method<Runtime, fn() -> RuntimeConfig> = java::Method::new("config");
CONFIG.invoke(e, self)
}
fn init_impl(e: &mut java::Env, cfg: RuntimeConfig) -> i64 {
let r = || ToadRuntime::try_new(cfg.addr(e), cfg.to_toad(e)).unwrap();
unsafe { crate::mem::Shared::init(r).addr() as i64 }
}
fn poll_req_impl(e: &mut java::Env, addr: i64) -> java::util::Optional<MessageRef> {
match unsafe {
Shared::deref::<crate::Runtime>(/* TODO */ 0, addr).as_ref()
.unwrap()
}.poll_req()
{
| Ok(req) => {
let mr = MessageRef::new(e, req.unwrap().into());
java::util::Optional::<MessageRef>::of(e, mr)
},
| Err(nb::Error::WouldBlock) => java::util::Optional::<MessageRef>::empty(e),
| Err(nb::Error::Other(err)) => {
e.throw(format!("{:?}", err)).unwrap();
java::util::Optional::<MessageRef>::empty(e)
},
}
}
}
java::object_newtype!(Runtime);
impl java::Class for Runtime {
const PATH: &'static str = package!(dev.toad.ToadRuntime);
}
#[no_mangle]
pub extern "system" fn Java_dev_toad_ToadRuntime_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_impl(e, cfg)
}
#[no_mangle]
pub extern "system" fn Java_dev_toad_ToadRuntime_pollReq<'local>(mut e: java::Env<'local>,
_: JClass<'local>,
addr: i64)
-> jobject {
let e = &mut e;
Runtime::poll_req_impl(e, addr).yield_to_java(e)
}

View File

@ -0,0 +1,10 @@
package dev.toad;
public final class Client {
final Toad toad;
Client(Toad toad) {
this.toad = toad;
}
}

View File

@ -1,46 +1,58 @@
package dev.toad;
import dev.toad.ffi.*;
import dev.toad.msg.MessageRef;
import java.net.InetSocketAddress;
import java.time.Duration;
import java.util.Optional;
import java.util.function.Function;
public class ToadRuntime {
public final class Toad {
static native Config defaultConfigImpl();
static Config defaultConfig = null;
static Config defaultConfig() {
if (ToadRuntime.defaultConfig == null) {
ToadRuntime.defaultConfig = ToadRuntime.defaultConfigImpl();
if (Toad.defaultConfig == null) {
Toad.defaultConfig = Toad.defaultConfigImpl();
}
return ToadRuntime.defaultConfig;
return Toad.defaultConfig;
}
static {
System.loadLibrary("toad_java_glue");
}
private final Ptr ptr;
private final Config config;
final Ptr ptr;
final Config config;
private static native long init(Config o);
static native long init(Config o);
private static native Optional<MessageRef> pollReq(long addr);
static native Optional<dev.toad.msg.ref.Message> pollReq(long ptr);
Optional<MessageRef> pollReq() {
return ToadRuntime.pollReq(this.ptr.addr());
static native Optional<dev.toad.msg.ref.Message> pollResp(
long ptr,
dev.toad.msg.Token t,
InetSocketAddress n
);
Optional<dev.toad.msg.ref.Message> pollReq() {
return Toad.pollReq(this.ptr.addr());
}
Optional<dev.toad.msg.ref.Message> pollResp(
dev.toad.msg.Token regarding,
InetSocketAddress from
) {
return Toad.pollResp(this.ptr.addr(), regarding, from);
}
public static BuilderRequiresBindToAddress builder() {
return new Builder();
}
ToadRuntime(Config o) {
Toad(Config o) {
this.config = o;
this.ptr = Ptr.register(this.getClass(), this.init(o));
}
@ -50,21 +62,21 @@ public class ToadRuntime {
}
public interface BuilderRequiresBindToAddress {
ToadRuntime.Builder port(short port);
ToadRuntime.Builder address(InetSocketAddress addr);
Toad.Builder port(short port);
Toad.Builder address(InetSocketAddress addr);
}
public static final class Builder implements BuilderRequiresBindToAddress {
Config.Msg.Builder msg = Config.Msg.builder();
Optional<InetSocketAddress> addr = Optional.empty();
u8 concurrency = ToadRuntime.defaultConfig().concurrency;
u8 concurrency = Toad.defaultConfig().concurrency;
Builder() {}
public ToadRuntime build() {
public Toad build() {
var cfg = new Config(this.addr.get(), this.concurrency, this.msg.build());
return new ToadRuntime(cfg);
return new Toad(cfg);
}
public Builder msg(Function<Config.Msg.Builder, Config.Msg.Builder> f) {
@ -183,10 +195,10 @@ public class ToadRuntime {
Con.Builder con = Con.builder();
Non.Builder non = Non.builder();
u16 tokenSeed = ToadRuntime.defaultConfig().msg.tokenSeed;
u16 probingRateBytesPerSecond = ToadRuntime.defaultConfig()
u16 tokenSeed = Toad.defaultConfig().msg.tokenSeed;
u16 probingRateBytesPerSecond = Toad.defaultConfig()
.msg.probingRateBytesPerSecond;
Duration multicastResponseLeisure = ToadRuntime.defaultConfig()
Duration multicastResponseLeisure = Toad.defaultConfig()
.msg.multicastResponseLeisure;
public Msg build() {
@ -275,11 +287,11 @@ public class ToadRuntime {
public static final class Builder {
RetryStrategy ackedRetryStrategy = ToadRuntime.defaultConfig()
RetryStrategy ackedRetryStrategy = Toad.defaultConfig()
.msg.con.ackedRetryStrategy;
RetryStrategy unackedRetryStrategy = ToadRuntime.defaultConfig()
RetryStrategy unackedRetryStrategy = Toad.defaultConfig()
.msg.con.unackedRetryStrategy;
u16 maxAttempts = ToadRuntime.defaultConfig().msg.con.maxAttempts;
u16 maxAttempts = Toad.defaultConfig().msg.con.maxAttempts;
public Con build() {
return new Con(
@ -343,9 +355,9 @@ public class ToadRuntime {
public static final class Builder {
RetryStrategy retryStrategy = ToadRuntime.defaultConfig()
RetryStrategy retryStrategy = Toad.defaultConfig()
.msg.non.retryStrategy;
u16 maxAttempts = ToadRuntime.defaultConfig().msg.non.maxAttempts;
u16 maxAttempts = Toad.defaultConfig().msg.non.maxAttempts;
public Non build() {
return new Non(this.retryStrategy, this.maxAttempts);

View File

@ -1,11 +1,11 @@
package dev.toad.msg;
public class MessageCode {
public class Code {
private final int clazz;
private final int detail;
public MessageCode(int clazz, int detail) {
public Code(int clazz, int detail) {
this.clazz = clazz;
this.detail = detail;
}

View File

@ -0,0 +1,14 @@
package dev.toad.msg;
public final class Id {
final int id;
public Id(int id) {
this.id = id;
}
public int toInt() {
return this.id;
}
}

View File

@ -6,15 +6,15 @@ import java.util.List;
public interface Message {
public InetSocketAddress source();
public int id();
public Id id();
public byte[] token();
public Token token();
public MessageCode code();
public Code code();
public MessageType type();
public Type type();
public List<MessageOption> options();
public List<Option> options();
public byte[] payloadBytes();

View File

@ -1,9 +0,0 @@
package dev.toad.msg;
import java.util.List;
public interface MessageOption {
public long number();
public List<MessageOptionValue> values();
}

View File

@ -1,30 +0,0 @@
package dev.toad.msg;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class MessageOptionOwned implements MessageOption {
public final long number;
public final List<MessageOptionValue> values;
public MessageOptionOwned(MessageOptionRef ref) {
this.number = ref.number();
this.values =
Arrays
.asList(ref.valueRefs())
.stream()
.map(MessageOptionValueRef::clone)
.collect(Collectors.toList());
}
public long number() {
return this.number;
}
public List<MessageOptionValue> values() {
return this.values;
}
}

View File

@ -1,39 +0,0 @@
package dev.toad.msg;
import dev.toad.ffi.Ptr;
import java.util.Arrays;
import java.util.List;
public class MessageOptionRef implements MessageOption, AutoCloseable {
private Ptr ptr;
private final long number;
private native MessageOptionValueRef[] values(long ptr);
public MessageOptionRef(long addr, long number) {
this.ptr = Ptr.register(this.getClass(), addr);
this.number = number;
}
public long number() {
return this.number;
}
public MessageOptionValueRef[] valueRefs() {
return this.values(this.ptr.addr());
}
public List<MessageOptionValue> values() {
return Arrays.asList(this.values(this.ptr.addr()));
}
public MessageOption clone() {
return new MessageOptionOwned(this);
}
@Override
public void close() {
this.ptr.release();
}
}

View File

@ -1,23 +0,0 @@
package dev.toad.msg;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class MessageOptionValueOwned implements MessageOptionValue {
public final byte[] bytes;
public MessageOptionValueOwned(MessageOptionValueRef ref) {
this.bytes = ref.asBytes().clone();
}
public byte[] asBytes() {
return this.bytes;
}
public String asString() {
return new String(this.asBytes());
}
}

View File

@ -1,66 +0,0 @@
package dev.toad.msg;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class MessageOwned implements Message {
private final InetSocketAddress source;
private final int id;
private final byte[] token;
private final byte[] payload;
private final MessageCode code;
private final MessageType type;
private final List<MessageOption> opts;
public MessageOwned(MessageRef ref) {
this.id = ref.id();
this.token = ref.token();
this.code = ref.code();
this.type = ref.type();
this.payload = ref.payloadBytes().clone();
this.source = ref.source();
this.opts =
Arrays
.asList(ref.optionRefs())
.stream()
.map(MessageOptionRef::clone)
.collect(Collectors.toList());
}
public InetSocketAddress source() {
return this.source;
}
public int id() {
return this.id;
}
public byte[] token() {
return this.token;
}
public MessageCode code() {
return this.code;
}
public MessageType type() {
return this.type;
}
public List<MessageOption> options() {
return this.opts;
}
public byte[] payloadBytes() {
return this.payload;
}
public String payloadString() {
return new String(this.payload);
}
}

View File

@ -0,0 +1,9 @@
package dev.toad.msg;
import java.util.List;
public interface Option {
public long number();
public List<OptionValue> values();
}

View File

@ -1,6 +1,6 @@
package dev.toad.msg;
public interface MessageOptionValue {
public interface OptionValue {
public byte[] asBytes();
public String asString();

View File

@ -0,0 +1,14 @@
package dev.toad.msg;
public final class Token {
final byte[] bytes;
public Token(byte[] bytes) {
this.bytes = bytes;
}
public byte[] toBytes() {
return this.bytes;
}
}

View File

@ -1,12 +1,12 @@
package dev.toad.msg;
public enum MessageType {
public enum Type {
CON(1),
NON(2),
ACK(3),
RESET(4);
private MessageType(int val) {}
private Type(int val) {}
public String toString() {
return switch (this) {
@ -18,7 +18,7 @@ public enum MessageType {
};
}
public static MessageType fromString(String s) {
public static Type fromString(String s) {
return switch (s.toLowerCase().trim()) {
case "con" -> CON;
case "non" -> NON;

View File

@ -0,0 +1,85 @@
package dev.toad.msg.owned;
import dev.toad.msg.*;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class Message implements dev.toad.msg.Message {
final InetSocketAddress source;
final Id id;
final Token token;
final byte[] payload;
final Code code;
final Type type;
final List<dev.toad.msg.Option> opts;
public Message(
InetSocketAddress source,
Type type,
Code code,
Id id,
Token token,
byte[] payload,
List<dev.toad.msg.Option> opts
) {
this.source = source;
this.id = id;
this.token = token;
this.payload = payload;
this.code = code;
this.type = type;
this.opts = opts;
}
public Message(dev.toad.msg.ref.Message ref) {
this(
ref.source(),
ref.type(),
ref.code(),
ref.id(),
ref.token(),
ref.payloadBytes().clone(),
Arrays
.asList(ref.optionRefs())
.stream()
.map(dev.toad.msg.ref.Option::clone)
.collect(Collectors.toList())
);
}
public InetSocketAddress source() {
return this.source;
}
public Id id() {
return this.id;
}
public Token token() {
return this.token;
}
public Code code() {
return this.code;
}
public Type type() {
return this.type;
}
public List<dev.toad.msg.Option> options() {
return this.opts;
}
public byte[] payloadBytes() {
return this.payload;
}
public String payloadString() {
return new String(this.payload);
}
}

View File

@ -0,0 +1,36 @@
package dev.toad.msg.owned;
import dev.toad.msg.*;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class Option implements dev.toad.msg.Option {
final long number;
final List<dev.toad.msg.OptionValue> values;
public Option(long number, List<dev.toad.msg.OptionValue> values) {
this.number = number;
this.values = values;
}
public Option(dev.toad.msg.ref.Option ref) {
this(
ref.number(),
Arrays
.asList(ref.valueRefs())
.stream()
.map(dev.toad.msg.ref.OptionValue::clone)
.collect(Collectors.toList())
);
}
public long number() {
return this.number;
}
public List<dev.toad.msg.OptionValue> values() {
return this.values;
}
}

View File

@ -0,0 +1,22 @@
package dev.toad.msg.owned;
public class OptionValue implements dev.toad.msg.OptionValue {
public final byte[] bytes;
public OptionValue(byte[] bytes) {
this.bytes = bytes;
}
public OptionValue(dev.toad.msg.ref.OptionValue ref) {
this(ref.asBytes().clone());
}
public byte[] asBytes() {
return this.bytes;
}
public String asString() {
return new String(this.asBytes());
}
}

View File

@ -1,6 +1,7 @@
package dev.toad.msg;
package dev.toad.msg.ref;
import dev.toad.ffi.Ptr;
import dev.toad.msg.*;
import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.List;
@ -13,32 +14,32 @@ import java.util.Optional;
* control is yielded back to the rust runtime, meaning instances of
* MessageRef should never be stored in state; invoke `.clone()` first.
*/
public class MessageRef implements Message, AutoCloseable {
public final class Message implements dev.toad.msg.Message, AutoCloseable {
private Ptr ptr;
Ptr ptr;
private Optional<InetSocketAddress> source = Optional.empty();
Optional<InetSocketAddress> source = Optional.empty();
private static native InetSocketAddress source(long addr);
static native InetSocketAddress source(long addr);
private static native int id(long addr);
static native Id id(long addr);
private static native byte[] token(long addr);
static native Token token(long addr);
private static native byte[] payload(long addr);
static native byte[] payload(long addr);
private static native MessageCode code(long addr);
static native Code code(long addr);
private static native MessageType type(long addr);
static native Type type(long addr);
private static native MessageOptionRef[] opts(long addr);
static native dev.toad.msg.ref.Option[] opts(long addr);
public MessageRef(long addr) {
Message(long addr) {
this.ptr = Ptr.register(this.getClass(), addr);
}
public Message clone() {
return new MessageOwned(this);
public dev.toad.msg.Message clone() {
return new dev.toad.msg.owned.Message(this);
}
public InetSocketAddress source() {
@ -49,27 +50,27 @@ public class MessageRef implements Message, AutoCloseable {
return this.source.get();
}
public int id() {
public Id id() {
return this.id(this.ptr.addr());
}
public byte[] token() {
public Token token() {
return this.token(this.ptr.addr());
}
public MessageCode code() {
public Code code() {
return this.code(this.ptr.addr());
}
public MessageType type() {
public Type type() {
return this.type(this.ptr.addr());
}
public MessageOptionRef[] optionRefs() {
public dev.toad.msg.ref.Option[] optionRefs() {
return this.opts(this.ptr.addr());
}
public List<MessageOption> options() {
public List<dev.toad.msg.Option> options() {
return Arrays.asList(this.opts(this.ptr.addr()));
}

View File

@ -0,0 +1,40 @@
package dev.toad.msg.ref;
import dev.toad.ffi.Ptr;
import dev.toad.msg.*;
import java.util.Arrays;
import java.util.List;
public class Option implements dev.toad.msg.Option, AutoCloseable {
Ptr ptr;
final long number;
native dev.toad.msg.ref.OptionValue[] values(long ptr);
Option(long addr, long number) {
this.ptr = Ptr.register(this.getClass(), addr);
this.number = number;
}
public long number() {
return this.number;
}
public dev.toad.msg.ref.OptionValue[] valueRefs() {
return this.values(this.ptr.addr());
}
public List<dev.toad.msg.OptionValue> values() {
return Arrays.asList(this.values(this.ptr.addr()));
}
public dev.toad.msg.Option clone() {
return new dev.toad.msg.owned.Option(this);
}
@Override
public void close() {
this.ptr.release();
}
}

View File

@ -1,15 +1,15 @@
package dev.toad.msg;
package dev.toad.msg.ref;
import dev.toad.ffi.Ptr;
public class MessageOptionValueRef
implements MessageOptionValue, AutoCloseable {
public final class OptionValue
implements dev.toad.msg.OptionValue, AutoCloseable {
private final Ptr ptr;
private native byte[] bytes(long addr);
public MessageOptionValueRef(long addr) {
OptionValue(long addr) {
this.ptr = Ptr.register(this.getClass(), addr);
}
@ -21,8 +21,8 @@ public class MessageOptionValueRef
return new String(this.bytes(this.ptr.addr()));
}
public MessageOptionValue clone() {
return this;
public dev.toad.msg.OptionValue clone() {
return new dev.toad.msg.owned.OptionValue(this);
}
@Override