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 owned;
pub mod ref_; pub mod ref_;
@ -7,6 +8,9 @@ use jni::sys::jobject;
use toad_jni::java; use toad_jni::java;
pub use ty::Type; pub use ty::Type;
mod payload;
pub use payload::Payload;
mod code; mod code;
pub use code::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 toad_msg::{OptNumber, TryIntoBytes};
use crate::dev::toad::msg::owned::Opt; 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); pub struct Message(java::lang::Object);
@ -43,12 +43,9 @@ impl Message {
OPTIONS.get(e, self).into_iter().collect() OPTIONS.get(e, self).into_iter().collect()
} }
pub fn payload(&self, e: &mut java::Env) -> Vec<u8> { pub fn payload(&self, e: &mut java::Env) -> Payload {
static PAYLOAD: java::Field<Message, Vec<i8>> = java::Field::new("payload"); static PAYLOAD: java::Field<Message, Payload> = java::Field::new("payload");
PAYLOAD.get(e, self) 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> { pub fn addr(&self, e: &mut java::Env) -> Option<InetSocketAddress> {
@ -74,7 +71,7 @@ impl Message {
.collect()) .collect())
}) })
.collect::<BTreeMap<OptNumber, Vec<toad_msg::OptValue<Vec<u8>>>>>(), .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::lang::Throwable;
use toad_jni::java::net::InetSocketAddress; use toad_jni::java::net::InetSocketAddress;
use toad_jni::java::{self, Object, ResultYieldToJavaOrThrow}; use toad_jni::java::{self, Object, ResultYieldToJavaOrThrow};
use toad_msg::MessageOptions;
use crate::dev::toad::ffi::Ptr; use crate::dev::toad::ffi::Ptr;
use crate::dev::toad::msg::ref_::Opt; 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}; use crate::mem::{Shared, SharedMemoryRegion};
pub struct Message(java::lang::Object); pub struct Message(java::lang::Object);
@ -20,9 +21,9 @@ impl java::Class for Message {
} }
impl 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(); 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 { 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> { pub fn to_toad(&self, e: &mut java::Env) -> Addrd<toad_msg::alloc::Message> {
let msg = toad_msg::alloc::Message { ty: self.ty(env), let msg = toad_msg::alloc::Message { ty: self.ty(e),
ver: toad_msg::Version::default(), ver: toad_msg::Version::default(),
code: self.code(env), code: self.code(e),
id: self.id(env), id: self.id(e),
token: self.token(env), token: self.token(e),
payload: toad_msg::Payload(self.payload(env)), payload: toad_msg::Payload(self.payload(e).bytes(e)),
opts: self.options(env) opts: self.options(e)
.into_iter() .into_iter()
.map(|opt| { .map(|opt| {
(opt.number(env), (opt.number(e),
opt.values(env) opt.values(e)
.into_iter() .into_iter()
.map(|v| toad_msg::OptValue(v.bytes(env))) .map(|v| toad_msg::OptValue(v.bytes(e)))
.collect()) .collect())
}) })
.collect::<BTreeMap<toad_msg::OptNumber, .collect::<BTreeMap<toad_msg::OptNumber,
Vec<toad_msg::OptValue<Vec<u8>>>>>() }; Vec<toad_msg::OptValue<Vec<u8>>>>>() };
Addrd(msg, Addrd(msg,
self.addr(env) self.addr(e)
.expect("java should have made sure the address was present")) .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"); 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>> = static SOURCE: java::Method<Message, fn() -> java::util::Optional<InetSocketAddress>> =
java::Method::new("addr"); java::Method::new("addr");
SOURCE.invoke(env, self) SOURCE.invoke(e, self).to_option(e).map(|a| a.to_no_std(e))
.to_option(env)
.map(|a| a.to_no_std(env))
} }
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"); 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"); 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"); 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"); 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"); 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> { pub fn payload(&self, e: &mut java::Env) -> Payload {
static PAYLOAD: java::Method<Message, fn() -> Vec<i8>> = java::Method::new("payloadBytes"); static PAYLOAD: java::Method<Message, fn() -> Payload> = java::Method::new("payload");
PAYLOAD.invoke(env, self) PAYLOAD.invoke(e, self)
.into_iter()
.map(|i| u8::from_be_bytes(i.to_be_bytes()))
.collect()
} }
} }
@ -132,15 +128,21 @@ pub extern "system" fn Java_dev_toad_msg_ref_Message_token<'local>(mut env: java
} }
#[no_mangle] #[no_mangle]
pub extern "system" fn Java_dev_toad_msg_ref_Message_payloadBytes<'local>(mut env: java::Env<'local>, pub extern "system" fn Java_dev_toad_msg_ref_Message_payload<'local>(mut env: java::Env<'local>,
msg: JObject<'local>) msg: JObject<'local>)
-> jobject { -> jobject {
let e = &mut env; let e = &mut env;
java::lang::Object::from_local(e, msg).upcast_to::<Message>(e) java::lang::Object::from_local(e, msg).upcast_to::<Message>(e)
.try_deref(e) .try_deref(e)
.map(|msg| { .map(|msg| {
java::lang::Object::from_local(e, e.byte_array_from_slice(&msg.data().payload.0) msg.data()
.unwrap()) .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) .yield_to_java_or_throw(e)
} }

View File

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

View File

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

View File

@ -110,7 +110,7 @@ public final class Message
this.code.get(), this.code.get(),
this.id.orElse(Id.defaultId()), this.id.orElse(Id.defaultId()),
this.token.orElse(Token.defaultToken()), this.token.orElse(Token.defaultToken()),
this.payload.map(p -> p.bytes()).orElse(new byte[] {}), this.payload.orElse(new Payload()),
this.options.entrySet() this.options.entrySet()
.stream() .stream()
.map(ent -> new dev.toad.msg.owned.Option(ent.getKey(), ent.getValue())) .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 Optional<InetSocketAddress> addr;
final Id id; final Id id;
final Token token; final Token token;
final byte[] payload; final Payload payload;
final Code code; final Code code;
final Type type; final Type type;
final ArrayList<dev.toad.msg.owned.Option> opts; final ArrayList<dev.toad.msg.owned.Option> opts;
@ -26,7 +26,7 @@ public class Message implements dev.toad.msg.Message {
Code code, Code code,
Id id, Id id,
Token token, Token token,
byte[] payload, Payload payload,
ArrayList<dev.toad.msg.owned.Option> opts ArrayList<dev.toad.msg.owned.Option> opts
) { ) {
this.addr = addr; this.addr = addr;
@ -45,7 +45,7 @@ public class Message implements dev.toad.msg.Message {
ref.code(), ref.code(),
ref.id(), ref.id(),
ref.token(), ref.token(),
ref.payloadBytes().clone(), ref.payload(),
Arrays Arrays
.asList(ref.optionRefs()) .asList(ref.optionRefs())
.stream() .stream()
@ -82,11 +82,7 @@ public class Message implements dev.toad.msg.Message {
return List.copyOf(this.opts); return List.copyOf(this.opts);
} }
public byte[] payloadBytes() { public Payload payload() {
return this.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 Token token();
public native byte[] payloadBytes(); public native Payload payload();
public native Code code(); public native Code code();
@ -46,10 +46,6 @@ public final class Message implements dev.toad.msg.Message, AutoCloseable {
return Arrays.asList(this.optionRefs()); return Arrays.asList(this.optionRefs());
} }
public String payloadString() {
return new String(this.payloadBytes());
}
@Override @Override
public void close() { public void close() {
this.ptr.release(); this.ptr.release();

View File

@ -45,6 +45,6 @@ class E2E extends munit.FunSuite {
val respActual = respFuture.get(1, TimeUnit.SECONDS) 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 import dev.toad.msg.option.Query
class MessageBuilder extends munit.FunSuite { 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 val msg = dev.toad.msg.build.Message
.builder() .builder()
.uri("coap://localhost") .uri("coap://localhost")
@ -18,7 +18,7 @@ class MessageBuilder extends munit.FunSuite {
assertEquals(msg.getContentFormat.get, ContentFormat.JSON) 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 val msg = dev.toad.msg.build.Message
.builder() .builder()
.uri("coap://localhost") .uri("coap://localhost")
@ -29,7 +29,7 @@ class MessageBuilder extends munit.FunSuite {
assertEquals(msg.addr.get.getAddress.getHostAddress, "127.0.0.1"); 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 val msg = dev.toad.msg.build.Message
.builder() .builder()
.uri("coap://localhost:1234") .uri("coap://localhost:1234")
@ -40,7 +40,7 @@ class MessageBuilder extends munit.FunSuite {
assertEquals(msg.addr.get.getPort, 1234) 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 val msg = dev.toad.msg.build.Message
.builder() .builder()
.uri("coap://localhost") .uri("coap://localhost")
@ -51,7 +51,7 @@ class MessageBuilder extends munit.FunSuite {
assertEquals(msg.addr.get.getPort, 5683) 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 val msg = dev.toad.msg.build.Message
.builder() .builder()
.uri("coaps://localhost/cheese/gruyere?foo=bar&bingus") .uri("coaps://localhost/cheese/gruyere?foo=bar&bingus")
@ -62,7 +62,7 @@ class MessageBuilder extends munit.FunSuite {
assertEquals(msg.addr.get.getPort, 5684) 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 val msg = dev.toad.msg.build.Message
.builder() .builder()
.uri("coap://localhost/cheese/gruyere?foo=bar&bingus") .uri("coap://localhost/cheese/gruyere?foo=bar&bingus")
@ -73,7 +73,7 @@ class MessageBuilder extends munit.FunSuite {
assertEquals(msg.getHost.get.toString, "localhost") 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 val msg = dev.toad.msg.build.Message
.builder() .builder()
.uri("coap://localhost/cheese/gruyere?foo=bar&bingus") .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 val msg = dev.toad.msg.build.Message
.builder() .builder()
.uri("coap://localhost/cheese/gruyere?foo=bar&bingus") .uri("coap://localhost/cheese/gruyere?foo=bar&bingus")