feat: use Payload in apis

This commit is contained in:
Orion Kindel 2023-04-20 11:13:27 -05:00
parent b8e9eaceb0
commit 66a3784627
Signed by untrusted user who does not match committer: orion
GPG Key ID: 6D4165AE4C928719
12 changed files with 130 additions and 74 deletions

View File

@ -1,3 +1,4 @@
pub mod option;
pub mod owned;
pub mod ref_;
@ -7,6 +8,9 @@ use jni::sys::jobject;
use toad_jni::java;
pub use ty::Type;
mod payload;
pub use payload::Payload;
mod code;
pub use code::Code;

View File

@ -0,0 +1,16 @@
use toad_jni::java;
use super::owned::Opt;
pub struct ContentFormat(java::lang::Object);
java::object_newtype!(ContentFormat);
impl java::Class for ContentFormat {
const PATH: &'static str = package!(dev.toad.msg.option.ContentFormat);
}
impl ContentFormat {
pub fn new(e: &mut java::Env, o: Opt) -> Self {
static CTOR: java::Constructor<ContentFormat, fn(Opt)> = java::Constructor::new();
CTOR.invoke(e, o)
}
}

View File

@ -8,7 +8,7 @@ use toad_jni::java::{self};
use toad_msg::{OptNumber, TryIntoBytes};
use crate::dev::toad::msg::owned::Opt;
use crate::dev::toad::msg::{Code, Id, Token, Type};
use crate::dev::toad::msg::{Code, Id, Payload, Token, Type};
pub struct Message(java::lang::Object);
@ -43,12 +43,9 @@ impl Message {
OPTIONS.get(e, self).into_iter().collect()
}
pub fn payload(&self, e: &mut java::Env) -> Vec<u8> {
static PAYLOAD: java::Field<Message, Vec<i8>> = java::Field::new("payload");
pub fn payload(&self, e: &mut java::Env) -> Payload {
static PAYLOAD: java::Field<Message, Payload> = java::Field::new("payload");
PAYLOAD.get(e, self)
.into_iter()
.map(|i| u8::from_be_bytes(i.to_be_bytes()))
.collect()
}
pub fn addr(&self, e: &mut java::Env) -> Option<InetSocketAddress> {
@ -74,7 +71,7 @@ impl Message {
.collect())
})
.collect::<BTreeMap<OptNumber, Vec<toad_msg::OptValue<Vec<u8>>>>>(),
payload: toad_msg::Payload(self.payload(e)) }
payload: toad_msg::Payload(self.payload(e).bytes(e)) }
}
}

View File

@ -0,0 +1,42 @@
use toad_jni::java;
use super::option::ContentFormat;
pub struct Payload(java::lang::Object);
java::object_newtype!(Payload);
impl java::Class for Payload {
const PATH: &'static str = package!(dev.toad.msg.Payload);
}
impl Payload {
pub fn new(e: &mut java::Env, bytes: impl IntoIterator<Item = u8>) -> Self {
static CTOR: java::Constructor<Payload, fn(Vec<i8>)> = java::Constructor::new();
CTOR.invoke(e,
bytes.into_iter()
.map(|u| i8::from_be_bytes(u.to_be_bytes()))
.collect())
}
pub fn new_content_format(e: &mut java::Env, bytes: Vec<u8>, f: ContentFormat) -> Self {
static CTOR: java::Constructor<Payload, fn(ContentFormat, Vec<i8>)> = java::Constructor::new();
CTOR.invoke(e,
f,
bytes.into_iter()
.map(|u| i8::from_be_bytes(u.to_be_bytes()))
.collect())
}
pub fn content_format(&self, e: &mut java::Env) -> Option<ContentFormat> {
static CONTENT_FORMAT: java::Method<Payload, fn() -> java::util::Optional<ContentFormat>> =
java::Method::new("contentFormat");
CONTENT_FORMAT.invoke(e, self).to_option(e)
}
pub fn bytes(&self, e: &mut java::Env) -> Vec<u8> {
static BYTES: java::Method<Payload, fn() -> Vec<i8>> = java::Method::new("bytes");
BYTES.invoke(e, self)
.into_iter()
.map(|i| u8::from_be_bytes(i.to_be_bytes()))
.collect()
}
}

View File

@ -6,10 +6,11 @@ use toad::net::Addrd;
use toad_jni::java::lang::Throwable;
use toad_jni::java::net::InetSocketAddress;
use toad_jni::java::{self, Object, ResultYieldToJavaOrThrow};
use toad_msg::MessageOptions;
use crate::dev::toad::ffi::Ptr;
use crate::dev::toad::msg::ref_::Opt;
use crate::dev::toad::msg::{Code, Id, Token, Type};
use crate::dev::toad::msg::{Code, Id, Payload, Token, Type};
use crate::mem::{Shared, SharedMemoryRegion};
pub struct Message(java::lang::Object);
@ -20,9 +21,9 @@ impl java::Class for Message {
}
impl Message {
pub fn new(env: &mut java::Env, msg_addr: i64) -> Self {
pub fn new(e: &mut java::Env, msg_addr: i64) -> Self {
static CTOR: java::Constructor<Message, fn(i64)> = java::Constructor::new();
CTOR.invoke(env, msg_addr)
CTOR.invoke(e, msg_addr)
}
pub fn ptr(&self, e: &mut java::Env) -> Ptr {
@ -39,73 +40,68 @@ impl Message {
})
}
pub fn to_toad(&self, env: &mut java::Env) -> Addrd<toad_msg::alloc::Message> {
let msg = toad_msg::alloc::Message { ty: self.ty(env),
pub fn to_toad(&self, e: &mut java::Env) -> Addrd<toad_msg::alloc::Message> {
let msg = toad_msg::alloc::Message { ty: self.ty(e),
ver: toad_msg::Version::default(),
code: self.code(env),
id: self.id(env),
token: self.token(env),
payload: toad_msg::Payload(self.payload(env)),
opts: self.options(env)
code: self.code(e),
id: self.id(e),
token: self.token(e),
payload: toad_msg::Payload(self.payload(e).bytes(e)),
opts: self.options(e)
.into_iter()
.map(|opt| {
(opt.number(env),
opt.values(env)
(opt.number(e),
opt.values(e)
.into_iter()
.map(|v| toad_msg::OptValue(v.bytes(env)))
.map(|v| toad_msg::OptValue(v.bytes(e)))
.collect())
})
.collect::<BTreeMap<toad_msg::OptNumber,
Vec<toad_msg::OptValue<Vec<u8>>>>>() };
Addrd(msg,
self.addr(env)
self.addr(e)
.expect("java should have made sure the address was present"))
}
pub fn close(&self, env: &mut java::Env) {
pub fn close(&self, e: &mut java::Env) {
static CLOSE: java::Method<Message, fn()> = java::Method::new("close");
CLOSE.invoke(env, self)
CLOSE.invoke(e, self)
}
pub fn addr(&self, env: &mut java::Env) -> Option<no_std_net::SocketAddr> {
pub fn addr(&self, e: &mut java::Env) -> Option<no_std_net::SocketAddr> {
static SOURCE: java::Method<Message, fn() -> java::util::Optional<InetSocketAddress>> =
java::Method::new("addr");
SOURCE.invoke(env, self)
.to_option(env)
.map(|a| a.to_no_std(env))
SOURCE.invoke(e, self).to_option(e).map(|a| a.to_no_std(e))
}
pub fn ty(&self, env: &mut java::Env) -> toad_msg::Type {
pub fn ty(&self, e: &mut java::Env) -> toad_msg::Type {
static TYPE: java::Method<Message, fn() -> Type> = java::Method::new("type");
TYPE.invoke(env, self).to_toad(env)
TYPE.invoke(e, self).to_toad(e)
}
pub fn id(&self, env: &mut java::Env) -> toad_msg::Id {
pub fn id(&self, e: &mut java::Env) -> toad_msg::Id {
static ID: java::Method<Message, fn() -> Id> = java::Method::new("id");
ID.invoke(env, self).to_toad(env)
ID.invoke(e, self).to_toad(e)
}
pub fn token(&self, env: &mut java::Env) -> toad_msg::Token {
pub fn token(&self, e: &mut java::Env) -> toad_msg::Token {
static TOKEN: java::Method<Message, fn() -> Token> = java::Method::new("token");
TOKEN.invoke(env, self).to_toad(env)
TOKEN.invoke(e, self).to_toad(e)
}
pub fn code(&self, env: &mut java::Env) -> toad_msg::Code {
pub fn code(&self, e: &mut java::Env) -> toad_msg::Code {
static CODE: java::Method<Message, fn() -> Code> = java::Method::new("code");
CODE.invoke(env, self).to_toad(env)
CODE.invoke(e, self).to_toad(e)
}
pub fn options(&self, env: &mut java::Env) -> Vec<Opt> {
pub fn options(&self, e: &mut java::Env) -> Vec<Opt> {
static OPTIONS: java::Method<Message, fn() -> Vec<Opt>> = java::Method::new("optionRefs");
OPTIONS.invoke(env, self)
OPTIONS.invoke(e, self)
}
pub fn payload(&self, env: &mut java::Env) -> Vec<u8> {
static PAYLOAD: java::Method<Message, fn() -> Vec<i8>> = java::Method::new("payloadBytes");
PAYLOAD.invoke(env, self)
.into_iter()
.map(|i| u8::from_be_bytes(i.to_be_bytes()))
.collect()
pub fn payload(&self, e: &mut java::Env) -> Payload {
static PAYLOAD: java::Method<Message, fn() -> Payload> = java::Method::new("payload");
PAYLOAD.invoke(e, self)
}
}
@ -132,15 +128,21 @@ pub extern "system" fn Java_dev_toad_msg_ref_Message_token<'local>(mut env: java
}
#[no_mangle]
pub extern "system" fn Java_dev_toad_msg_ref_Message_payloadBytes<'local>(mut env: java::Env<'local>,
msg: JObject<'local>)
-> jobject {
pub extern "system" fn Java_dev_toad_msg_ref_Message_payload<'local>(mut env: java::Env<'local>,
msg: JObject<'local>)
-> jobject {
let e = &mut env;
java::lang::Object::from_local(e, msg).upcast_to::<Message>(e)
.try_deref(e)
.map(|msg| {
java::lang::Object::from_local(e, e.byte_array_from_slice(&msg.data().payload.0)
.unwrap())
msg.data()
.content_format()
.map(|f| {
Payload::new(e, msg.data().payload.0.iter().copied())
})
.unwrap_or_else(|| {
Payload::new(e, msg.data().payload.0.iter().copied())
})
})
.yield_to_java_or_throw(e)
}

View File

@ -26,9 +26,7 @@ public interface Message {
public List<Option> options();
public byte[] payloadBytes();
public String payloadString();
public Payload payload();
public dev.toad.msg.owned.Message toOwned();

View File

@ -9,6 +9,11 @@ public final class Payload {
final byte[] bytes;
final Optional<ContentFormat> contentFormat;
public Payload() {
this.contentFormat = Optional.empty();
this.bytes = new byte[] {};
}
public Payload(byte[] bytes) {
this.contentFormat = Optional.empty();
this.bytes = bytes;

View File

@ -110,7 +110,7 @@ public final class Message
this.code.get(),
this.id.orElse(Id.defaultId()),
this.token.orElse(Token.defaultToken()),
this.payload.map(p -> p.bytes()).orElse(new byte[] {}),
this.payload.orElse(new Payload()),
this.options.entrySet()
.stream()
.map(ent -> new dev.toad.msg.owned.Option(ent.getKey(), ent.getValue()))

View File

@ -15,7 +15,7 @@ public class Message implements dev.toad.msg.Message {
final Optional<InetSocketAddress> addr;
final Id id;
final Token token;
final byte[] payload;
final Payload payload;
final Code code;
final Type type;
final ArrayList<dev.toad.msg.owned.Option> opts;
@ -26,7 +26,7 @@ public class Message implements dev.toad.msg.Message {
Code code,
Id id,
Token token,
byte[] payload,
Payload payload,
ArrayList<dev.toad.msg.owned.Option> opts
) {
this.addr = addr;
@ -45,7 +45,7 @@ public class Message implements dev.toad.msg.Message {
ref.code(),
ref.id(),
ref.token(),
ref.payloadBytes().clone(),
ref.payload(),
Arrays
.asList(ref.optionRefs())
.stream()
@ -82,11 +82,7 @@ public class Message implements dev.toad.msg.Message {
return List.copyOf(this.opts);
}
public byte[] payloadBytes() {
public Payload payload() {
return this.payload;
}
public String payloadString() {
return new String(this.payload);
}
}

View File

@ -24,7 +24,7 @@ public final class Message implements dev.toad.msg.Message, AutoCloseable {
public native Token token();
public native byte[] payloadBytes();
public native Payload payload();
public native Code code();
@ -46,10 +46,6 @@ public final class Message implements dev.toad.msg.Message, AutoCloseable {
return Arrays.asList(this.optionRefs());
}
public String payloadString() {
return new String(this.payloadBytes());
}
@Override
public void close() {
this.ptr.release();

View File

@ -45,6 +45,6 @@ class E2E extends munit.FunSuite {
val respActual = respFuture.get(1, TimeUnit.SECONDS)
assertEquals(resp.payloadBytes().toSeq, respActual.payloadBytes().toSeq)
assertEquals(resp.payload.bytes.toSeq, respActual.payload.bytes.toSeq)
}
}

View File

@ -6,7 +6,7 @@ import dev.toad.msg.option.Path
import dev.toad.msg.option.Query
class MessageBuilder extends munit.FunSuite {
test("payload sets content format") {
test("payload(Payload) sets content format to ContentFormat.JSON") {
val msg = dev.toad.msg.build.Message
.builder()
.uri("coap://localhost")
@ -18,7 +18,7 @@ class MessageBuilder extends munit.FunSuite {
assertEquals(msg.getContentFormat.get, ContentFormat.JSON)
}
test("uri uses system DNS to resolve host address") {
test("uri(String) uses system DNS to resolve host address") {
val msg = dev.toad.msg.build.Message
.builder()
.uri("coap://localhost")
@ -29,7 +29,7 @@ class MessageBuilder extends munit.FunSuite {
assertEquals(msg.addr.get.getAddress.getHostAddress, "127.0.0.1");
}
test("uri gets port from URI") {
test("uri(String) gets port from URI") {
val msg = dev.toad.msg.build.Message
.builder()
.uri("coap://localhost:1234")
@ -40,7 +40,7 @@ class MessageBuilder extends munit.FunSuite {
assertEquals(msg.addr.get.getPort, 1234)
}
test("uri gets port 5683 from scheme coap://") {
test("uri(String) gets port 5683 from scheme coap://") {
val msg = dev.toad.msg.build.Message
.builder()
.uri("coap://localhost")
@ -51,7 +51,7 @@ class MessageBuilder extends munit.FunSuite {
assertEquals(msg.addr.get.getPort, 5683)
}
test("uri gets port 5684 from scheme coaps://") {
test("uri(String) gets port 5684 from scheme coaps://") {
val msg = dev.toad.msg.build.Message
.builder()
.uri("coaps://localhost/cheese/gruyere?foo=bar&bingus")
@ -62,7 +62,7 @@ class MessageBuilder extends munit.FunSuite {
assertEquals(msg.addr.get.getPort, 5684)
}
test("uri sets host to host section of uri") {
test("uri(String) sets host to host section of uri") {
val msg = dev.toad.msg.build.Message
.builder()
.uri("coap://localhost/cheese/gruyere?foo=bar&bingus")
@ -73,7 +73,7 @@ class MessageBuilder extends munit.FunSuite {
assertEquals(msg.getHost.get.toString, "localhost")
}
test("uri sets path to path section of uri") {
test("uri(String) sets path to path section of uri") {
val msg = dev.toad.msg.build.Message
.builder()
.uri("coap://localhost/cheese/gruyere?foo=bar&bingus")
@ -87,7 +87,7 @@ class MessageBuilder extends munit.FunSuite {
)
}
test("uri sets query to query section of uri") {
test("uri(String) sets query to query section of uri") {
val msg = dev.toad.msg.build.Message
.builder()
.uri("coap://localhost/cheese/gruyere?foo=bar&bingus")