From ecf9086b35244b57aeb81531b44f56c33288567e Mon Sep 17 00:00:00 2001 From: Orion Kindel Date: Tue, 4 Apr 2023 15:36:01 -0700 Subject: [PATCH] feat: small commit --- .gitignore | 2 + .jvmopts | 1 + .scalafmt.conf | 2 + .tool-versions | 1 + build.sbt | 67 +- src/main/java/dev.toad/RetryStrategy.java | 47 ++ src/main/java/dev.toad/Runtime.java | 7 + src/main/java/dev.toad/RuntimeOptions.java | 318 +++++++ src/main/java/dev.toad/msg/Message.java | 13 + src/main/java/dev.toad/msg/MessageCode.java | 44 + src/main/java/dev.toad/msg/MessageOption.java | 8 + .../java/dev.toad/msg/MessageOptionOwned.java | 22 + .../java/dev.toad/msg/MessageOptionRef.java | 32 + .../java/dev.toad/msg/MessageOptionValue.java | 6 + .../dev.toad/msg/MessageOptionValueOwned.java | 22 + .../dev.toad/msg/MessageOptionValueRef.java | 22 + src/main/java/dev.toad/msg/MessageOwned.java | 56 ++ src/main/java/dev.toad/msg/MessageRef.java | 62 ++ src/main/java/dev.toad/msg/MessageType.java | 27 + src/main/scala/Main.scala | 5 - toad-java-glue-rs/Cargo.lock | 792 ++++++++++++++++++ toad-java-glue-rs/Cargo.toml | 15 + toad-java-glue-rs/compile_commands.json | 1 + toad-java-glue-rs/rust-toolchain.toml | 2 + toad-java-glue-rs/rustfmt.toml | 24 + toad-java-glue-rs/src/lib.rs | 68 ++ toad-java-glue-rs/src/message_code.rs | 19 + toad-java-glue-rs/src/message_opt_ref.rs | 67 ++ .../src/message_opt_value_ref.rs | 38 + toad-java-glue-rs/src/message_ref.rs | 91 ++ toad-java-glue-rs/src/message_type.rs | 32 + toad-java-glue-rs/src/retry_strategy.rs | 52 ++ toad-java-glue-rs/src/runtime_config.rs | 259 ++++++ 33 files changed, 2217 insertions(+), 7 deletions(-) create mode 100644 .jvmopts create mode 100644 .scalafmt.conf create mode 100644 .tool-versions create mode 100644 src/main/java/dev.toad/RetryStrategy.java create mode 100644 src/main/java/dev.toad/Runtime.java create mode 100644 src/main/java/dev.toad/RuntimeOptions.java create mode 100644 src/main/java/dev.toad/msg/Message.java create mode 100644 src/main/java/dev.toad/msg/MessageCode.java create mode 100644 src/main/java/dev.toad/msg/MessageOption.java create mode 100644 src/main/java/dev.toad/msg/MessageOptionOwned.java create mode 100644 src/main/java/dev.toad/msg/MessageOptionRef.java create mode 100644 src/main/java/dev.toad/msg/MessageOptionValue.java create mode 100644 src/main/java/dev.toad/msg/MessageOptionValueOwned.java create mode 100644 src/main/java/dev.toad/msg/MessageOptionValueRef.java create mode 100644 src/main/java/dev.toad/msg/MessageOwned.java create mode 100644 src/main/java/dev.toad/msg/MessageRef.java create mode 100644 src/main/java/dev.toad/msg/MessageType.java delete mode 100644 src/main/scala/Main.scala create mode 100644 toad-java-glue-rs/Cargo.lock create mode 100644 toad-java-glue-rs/Cargo.toml create mode 100644 toad-java-glue-rs/compile_commands.json create mode 100644 toad-java-glue-rs/rust-toolchain.toml create mode 100644 toad-java-glue-rs/rustfmt.toml create mode 100644 toad-java-glue-rs/src/lib.rs create mode 100644 toad-java-glue-rs/src/message_code.rs create mode 100644 toad-java-glue-rs/src/message_opt_ref.rs create mode 100644 toad-java-glue-rs/src/message_opt_value_ref.rs create mode 100644 toad-java-glue-rs/src/message_ref.rs create mode 100644 toad-java-glue-rs/src/message_type.rs create mode 100644 toad-java-glue-rs/src/retry_strategy.rs create mode 100644 toad-java-glue-rs/src/runtime_config.rs diff --git a/.gitignore b/.gitignore index 9e79245..f51d6b8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +toad-jni.so + # macOS .DS_Store diff --git a/.jvmopts b/.jvmopts new file mode 100644 index 0000000..de9ed59 --- /dev/null +++ b/.jvmopts @@ -0,0 +1 @@ +-Dfile.encoding=UTF-8 --enable-preview diff --git a/.scalafmt.conf b/.scalafmt.conf new file mode 100644 index 0000000..fd76373 --- /dev/null +++ b/.scalafmt.conf @@ -0,0 +1,2 @@ +runner.dialect = scala3 +version = 3.7.3 diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 0000000..af19266 --- /dev/null +++ b/.tool-versions @@ -0,0 +1 @@ +java openjdk-20 diff --git a/build.sbt b/build.sbt index ad0691b..6b08025 100644 --- a/build.sbt +++ b/build.sbt @@ -1,12 +1,75 @@ +import sys.process._ +import java.io.File +import sbt.nio.file.FileTreeView + +Global / onChangedBuildSource := ReloadOnSourceChanges + val scala3Version = "3.2.2" +val cargoBuild = taskKey[Unit]("cd ./toad-java-glue-rs; cargo build") +val ejectHeaders = taskKey[Unit]("Generate C headers for FFI") +val fullBuild = taskKey[Unit]("cargoBuild > ejectHeaders") +val glob = settingKey[Map[String, Glob]]("globs") +val path = settingKey[Map[String, String]]("paths") + +fork := true + +javaOptions += "--enable-preview" +javacOptions ++= Seq("--enable-preview", "--release", "20", "-Xlint:preview") lazy val root = project .in(file(".")) .settings( name := "toad", version := "0.1.0-SNAPSHOT", - scalaVersion := scala3Version, + libraryDependencies += "org.scalameta" %% "munit" % "0.7.29" % Test, + glob := Map( + "java.sources" -> baseDirectory.value.toGlob / "src" / "main" / "java" / ** / "*.java", + "glue.sources" -> baseDirectory.value.toGlob / "toad-java-glue-rs" / "src" / ** / "*.rs" + ), + path := Map( + "glue.base" -> (baseDirectory.value / "toad-java-glue-rs").toString, + "glue.target" -> (baseDirectory.value / "toad-java-glue-rs" / "target" / "debug").toString, + "java.classTarget" -> (baseDirectory.value / "target" / "scala-3.2.2" / "classes").toString + ), + // Test / compile / javacOptions ++= Seq("--enable-preview", "--release", "20", "-Xlint:preview"), + // Test / run / javaOptions ++= Seq( + // "-Djava.library.path=" + path.value("glue.target"), + // "--enable-preview" + // ), + // Compile / doc / javacOptions ++= Seq("--enable-preview", "--release", "20", "-Xlint:preview"), + // Compile / compile / javacOptions ++= Seq("--enable-preview", "--release", "20", "-Xlint:preview"), + // Compile / run / javaOptions ++= Seq( + // "-Djava.library.path=" + path.value("glue.target"), + // "--enable-preview" + // ), + ejectHeaders := { + val files = + FileTreeView.default.iterator(glob.value("java.sources")).foldLeft("") { + (s, fd) => s + " " + fd._1.toString + } + val cmd = + Seq( + "javac", + "--enable-preview", + "--release 20", + "-h " + path.value("glue.target"), + "-d " + path.value("java.classTarget"), + files + ) + .foldLeft("")((s, a) => s + " " + a) - libraryDependencies += "org.scalameta" %% "munit" % "0.7.29" % Test + println(Seq("sh", "-c", cmd) !!) + }, + cargoBuild := { + val cmd = + Seq("sh", "-c", "cd toad-java-glue-rs; cargo rustc -- -Awarnings") + println(cmd !!) + }, + fullBuild := { + cargoBuild.value + ejectHeaders.value + }, + Compile / compile := (Compile / compile dependsOn fullBuild).value, + Compile / compile / watchTriggers += glob.value("glue.sources") ) diff --git a/src/main/java/dev.toad/RetryStrategy.java b/src/main/java/dev.toad/RetryStrategy.java new file mode 100644 index 0000000..3b33972 --- /dev/null +++ b/src/main/java/dev.toad/RetryStrategy.java @@ -0,0 +1,47 @@ +package dev.toad; + +import java.time.Duration; +import java.util.Optional; + +public abstract sealed class RetryStrategy { + @Override + public boolean equals(Object other) { + return switch (this) { + case Exponential self -> switch (other) { + case Exponential e -> e.initMin == self.initMin && e.initMax == self.initMax; + default -> false; + }; + case Linear self -> switch (other) { + case Linear e -> e.min == self.min && e.max == self.max; + default -> false; + }; + default -> false; + }; + } + + public final class Exponential extends RetryStrategy { + public final Duration initMin; + public final Duration initMax; + + private static native Exponential fromRust(byte[] mem); + private native byte[] toRust(); + + public Exponential(Duration initMin, Duration initMax) { + this.initMin = initMin; + this.initMax = initMax; + } + } + + public final class Linear extends RetryStrategy { + public final Duration min; + public final Duration max; + + private static native Linear fromRust(byte[] mem); + private native byte[] toRust(); + + public Linear(Duration min, Duration max) { + this.min = min; + this.max = max; + } + } +} diff --git a/src/main/java/dev.toad/Runtime.java b/src/main/java/dev.toad/Runtime.java new file mode 100644 index 0000000..c2a0bd1 --- /dev/null +++ b/src/main/java/dev.toad/Runtime.java @@ -0,0 +1,7 @@ +package dev.toad; + +public class Runtime { + public static native void init(RuntimeOptions o); + + private Runtime() {} +} diff --git a/src/main/java/dev.toad/RuntimeOptions.java b/src/main/java/dev.toad/RuntimeOptions.java new file mode 100644 index 0000000..3f1da9f --- /dev/null +++ b/src/main/java/dev.toad/RuntimeOptions.java @@ -0,0 +1,318 @@ +package dev.toad; + +import java.time.Duration; +import java.util.Optional; +import java.util.function.Function; + +public final class RuntimeOptions implements Cloneable { + + private Net net; + + public RuntimeOptions() { + this.net = new Net(); + } + + @Override + public boolean equals(Object other) { + return switch (other) { + case RuntimeOptions o -> o.net == this.net; + default -> false; + }; + } + + public Net net() { + return this.net; + } + + private RuntimeOptions with(Function f) { + return f.apply(this.clone()); + } + + public RuntimeOptions withNet(Function f) { + return this.with(self -> { + self.net = f.apply(self.net); + return self; + }); + } + + @Override + public RuntimeOptions clone() { + RuntimeOptions self = new RuntimeOptions(); + self.net = this.net.clone(); + return self; + } + + public final class Net implements Cloneable { + + private short port; + private short concurrency; + private Msg msg; + + public Net() { + this.port = 5683; + this.concurrency = 1; + this.msg = new Msg(); + } + + @Override + public boolean equals(Object other) { + return switch (other) { + case Net o -> o.port == this.port && + o.concurrency == this.concurrency && + o.msg == this.msg; + default -> false; + }; + } + + private Net with(Function f) { + return f.apply(this.clone()); + } + + @Override + public Net clone() { + Net self = new Net(); + self.port = this.port; + self.concurrency = this.concurrency; + self.msg = this.msg.clone(); + return self; + } + + public short port() { + return this.port; + } + + public short concurrency() { + return this.concurrency; + } + + public Msg msg() { + return this.msg; + } + + public Net withPort(short port) { + return this.with(self -> { + self.port = port; + return self; + }); + } + + public Net withConcurrency(short conc) { + return this.with(self -> { + self.concurrency = conc; + return self; + }); + } + + public Net withMsg(Function f) { + return this.with(self -> { + self.msg = f.apply(self.msg); + return self; + }); + } + } + + public final class Msg implements Cloneable { + + private Optional tokenSeed = Optional.empty(); + private Optional probingRateBytesPerSecond = Optional.empty(); + private Optional multicastResponseLeisure = Optional.empty(); + private Con con; + private Non non; + + public Msg() { + this.con = new Con(); + this.non = new Non(); + } + + private Msg with(Function f) { + return f.apply(this.clone()); + } + + @Override + public boolean equals(Object other) { + return switch (other) { + case Msg o -> o.tokenSeed == this.tokenSeed && + o.probingRateBytesPerSecond == this.probingRateBytesPerSecond && + o.multicastResponseLeisure == this.multicastResponseLeisure && + o.con == this.con && + o.non == this.non; + default -> false; + }; + } + + @Override + public Msg clone() { + Msg self = new Msg(); + self.tokenSeed = this.tokenSeed; + self.probingRateBytesPerSecond = this.probingRateBytesPerSecond; + self.multicastResponseLeisure = this.multicastResponseLeisure; + self.con = this.con.clone(); + self.non = this.non.clone(); + return self; + } + + public Optional tokenSeed() { + return this.tokenSeed; + } + + public Optional probingRateBytesPerSecond() { + return this.probingRateBytesPerSecond; + } + + public Optional multicastResponseLeisure() { + return this.multicastResponseLeisure; + } + + public Con con() { + return this.con; + } + + public Non non() { + return this.non; + } + + public Msg withTokenSeed(int tokenSeed) { + return this.with(self -> { + self.tokenSeed = Optional.of(tokenSeed); + return self; + }); + } + + public Msg withProbingRateBytesBerSecond(int bps) { + return this.with(m -> { + m.probingRateBytesPerSecond = Optional.of(bps); + return m; + }); + } + + public Msg withMulticastResponseLeisure(Duration dur) { + return this.with(m -> { + m.multicastResponseLeisure = Optional.of(dur); + return m; + }); + } + + public Msg withCon(Function f) { + return this.with(m -> { + m.con = f.apply(m.con); + return m; + }); + } + + public Msg withNon(Function f) { + return this.with(m -> { + m.non = f.apply(m.non); + return m; + }); + } + + public final class Con implements Cloneable { + + private Optional ackedRetryStrategy = Optional.empty(); + private Optional unackedRetryStrategy = Optional.empty(); + private Optional maxAttempts = Optional.empty(); + + public Con() {} + + private Con with(Function f) { + return f.apply(this.clone()); + } + + @Override + public boolean equals(Object other) { + return switch (other) { + case Con o -> this.ackedRetryStrategy == o.ackedRetryStrategy && + this.unackedRetryStrategy == o.unackedRetryStrategy && + this.maxAttempts == o.maxAttempts; + default -> false; + }; + } + + public Optional ackedRetryStrategy() { + return this.ackedRetryStrategy; + } + + public Optional unackedRetryStrategy() { + return this.unackedRetryStrategy; + } + + public Optional maxAttempts() { + return this.maxAttempts; + } + + public Con withAckedRetryStrategy(RetryStrategy r) { + return this.with(s -> { + s.ackedRetryStrategy = Optional.of(r); + return s; + }); + } + + public Con withUnackedRetryStrategy(RetryStrategy r) { + return this.with(s -> { + s.unackedRetryStrategy = Optional.of(r); + return s; + }); + } + + public Con withMaxAttempts(int a) { + return this.with(s -> { + s.maxAttempts = Optional.of(a); + return s; + }); + } + + @Override + public Con clone() { + return this; + } + } + + public final class Non implements Cloneable { + + private Optional retryStrategy = Optional.empty(); + private Optional maxAttempts = Optional.empty(); + + public Non() {} + + @Override + public boolean equals(Object other) { + return switch (other) { + case Non o -> this.retryStrategy == o.retryStrategy && + this.maxAttempts == o.maxAttempts; + default -> false; + }; + } + + private Non with(Function f) { + return f.apply(this.clone()); + } + + public Optional retryStrategy() { + return this.retryStrategy; + } + + public Optional maxAttempts() { + return this.maxAttempts; + } + + public Non withRetryStrategy(RetryStrategy r) { + return this.with(s -> { + s.retryStrategy = Optional.of(r); + return s; + }); + } + + public Non withMaxAttempts(int a) { + return this.with(s -> { + s.maxAttempts = Optional.of(a); + return s; + }); + } + + @Override + public Non clone() { + return this; + } + } + } +} diff --git a/src/main/java/dev.toad/msg/Message.java b/src/main/java/dev.toad/msg/Message.java new file mode 100644 index 0000000..2e56879 --- /dev/null +++ b/src/main/java/dev.toad/msg/Message.java @@ -0,0 +1,13 @@ +package dev.toad.msg; + +import java.util.List; + +public interface Message { + public int id(); + public byte[] token(); + public MessageCode code(); + public MessageType type(); + public List options(); + public byte[] payloadBytes(); + public String payloadString(); +} diff --git a/src/main/java/dev.toad/msg/MessageCode.java b/src/main/java/dev.toad/msg/MessageCode.java new file mode 100644 index 0000000..75b9854 --- /dev/null +++ b/src/main/java/dev.toad/msg/MessageCode.java @@ -0,0 +1,44 @@ +package dev.toad.msg; + +public class MessageCode { + + private final int clazz; + private final int detail; + + public MessageCode(int clazz, int detail) { + this.clazz = clazz; + this.detail = detail; + } + + @Override + public String toString() { + if (this.isRequest()) { + switch (this.detail) { + case 1: + return "GET"; + case 2: + return "PUT"; + case 3: + return "POST"; + case 4: + return "DELETE"; + default: + throw new Error(); + } + } else { + return String.format("%d.%d", this.clazz, this.detail); + } + } + + public boolean isRequest() { + return this.clazz == 0 && this.detail > 0; + } + + public boolean isResponse() { + return this.clazz > 1; + } + + public boolean isEmpty() { + return this.clazz == 0 && this.detail == 0; + } +} diff --git a/src/main/java/dev.toad/msg/MessageOption.java b/src/main/java/dev.toad/msg/MessageOption.java new file mode 100644 index 0000000..8b2e410 --- /dev/null +++ b/src/main/java/dev.toad/msg/MessageOption.java @@ -0,0 +1,8 @@ +package dev.toad.msg; + +import java.util.List; + +public interface MessageOption { + public long number(); + public List values(); +} diff --git a/src/main/java/dev.toad/msg/MessageOptionOwned.java b/src/main/java/dev.toad/msg/MessageOptionOwned.java new file mode 100644 index 0000000..ea34222 --- /dev/null +++ b/src/main/java/dev.toad/msg/MessageOptionOwned.java @@ -0,0 +1,22 @@ +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 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 values() {return this.values;} +} diff --git a/src/main/java/dev.toad/msg/MessageOptionRef.java b/src/main/java/dev.toad/msg/MessageOptionRef.java new file mode 100644 index 0000000..175caa9 --- /dev/null +++ b/src/main/java/dev.toad/msg/MessageOptionRef.java @@ -0,0 +1,32 @@ +package dev.toad.msg; + +import java.util.Arrays; +import java.util.List; + +public class MessageOptionRef implements MessageOption { + private final long addr; + private final long number; + + private native MessageOptionValueRef[] values(long addr); + + public MessageOptionRef(long addr, long number) { + this.addr = addr; + this.number = number; + } + + public long number() { + return this.number; + } + + public MessageOptionValueRef[] valueRefs() { + return this.values(this.addr); + } + + public List values() { + return Arrays.asList(this.values(this.addr)); + } + + public MessageOption clone() { + return new MessageOptionOwned(this); + } +} diff --git a/src/main/java/dev.toad/msg/MessageOptionValue.java b/src/main/java/dev.toad/msg/MessageOptionValue.java new file mode 100644 index 0000000..bb8a878 --- /dev/null +++ b/src/main/java/dev.toad/msg/MessageOptionValue.java @@ -0,0 +1,6 @@ +package dev.toad.msg; + +public interface MessageOptionValue { + public byte[] asBytes(); + public String asString(); +} diff --git a/src/main/java/dev.toad/msg/MessageOptionValueOwned.java b/src/main/java/dev.toad/msg/MessageOptionValueOwned.java new file mode 100644 index 0000000..bcdf0e5 --- /dev/null +++ b/src/main/java/dev.toad/msg/MessageOptionValueOwned.java @@ -0,0 +1,22 @@ +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()); + } +} diff --git a/src/main/java/dev.toad/msg/MessageOptionValueRef.java b/src/main/java/dev.toad/msg/MessageOptionValueRef.java new file mode 100644 index 0000000..500aa68 --- /dev/null +++ b/src/main/java/dev.toad/msg/MessageOptionValueRef.java @@ -0,0 +1,22 @@ +package dev.toad.msg; + +public class MessageOptionValueRef implements MessageOptionValue { + private final long addr; + private native byte[] bytes(long addr); + + public MessageOptionValueRef(long addr) { + this.addr = addr; + } + + public byte[] asBytes() { + return this.bytes(this.addr); + } + + public String asString() { + return new String(this.bytes(this.addr)); + } + + public MessageOptionValue clone() { + return this; + } +} diff --git a/src/main/java/dev.toad/msg/MessageOwned.java b/src/main/java/dev.toad/msg/MessageOwned.java new file mode 100644 index 0000000..f15d9f4 --- /dev/null +++ b/src/main/java/dev.toad/msg/MessageOwned.java @@ -0,0 +1,56 @@ +package dev.toad.msg; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class MessageOwned implements Message { + private static int id; + private static byte[] token; + private static byte[] payload; + private static MessageCode code; + private static MessageType type; + private static List 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.opts = Arrays.asList(ref.optionRefs()) + .stream() + .map(MessageOptionRef::clone) + .collect(Collectors.toList()); + } + + 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 options() { + return this.opts; + } + + public byte[] payloadBytes() { + return this.payload; + } + + public String payloadString() { + return new String(this.payload); + } +} diff --git a/src/main/java/dev.toad/msg/MessageRef.java b/src/main/java/dev.toad/msg/MessageRef.java new file mode 100644 index 0000000..c3d3b12 --- /dev/null +++ b/src/main/java/dev.toad/msg/MessageRef.java @@ -0,0 +1,62 @@ +package dev.toad.msg; + +import java.util.Arrays; +import java.util.List; + +/** + * A pointer to a [`toad_msg::Message`](https://docs.rs/toad-msg/latest/toad_msg/struct.Message.html) + * + * Note that the pointer is not guaranteed to continue to be valid once + * 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 { + private final long addr; + + private static native int id(long addr); + private static native byte[] token(long addr); + private static native byte[] payload(long addr); + private static native MessageCode code(long addr); + private static native MessageType type(long addr); + private static native MessageOptionRef[] opts(long addr); + + public MessageRef(long addr) { + this.addr = addr; + } + + public Message clone() { + return new MessageOwned(this); + } + + public int id() { + return this.id(this.addr); + } + + public byte[] token() { + return this.token(this.addr); + } + + public MessageCode code() { + return this.code(this.addr); + } + + public MessageType type() { + return this.type(this.addr); + } + + public MessageOptionRef[] optionRefs() { + return this.opts(this.addr); + } + + public List options() { + return Arrays.asList(this.opts(this.addr)); + } + + public byte[] payloadBytes() { + return this.payload(this.addr); + } + + public String payloadString() { + return new String(this.payload(this.addr)); + } +} diff --git a/src/main/java/dev.toad/msg/MessageType.java b/src/main/java/dev.toad/msg/MessageType.java new file mode 100644 index 0000000..6425202 --- /dev/null +++ b/src/main/java/dev.toad/msg/MessageType.java @@ -0,0 +1,27 @@ +package dev.toad.msg; + +public enum MessageType { + CON(1), NON(2), ACK(3), RESET(4); + + private MessageType(int val) {} + + public String toString() { + switch(this) { + case CON: return "CON"; + case NON: return "NON"; + case ACK: return "ACK"; + case RESET: return "RESET"; + default: throw new Error(); + } + } + + public static MessageType fromString(String s) { + switch(s.toLowerCase().trim()) { + case "con": return CON; + case "non": return NON; + case "ack": return ACK; + case "reset": return RESET; + default: throw new Error(); + } + } +} diff --git a/src/main/scala/Main.scala b/src/main/scala/Main.scala deleted file mode 100644 index b51644b..0000000 --- a/src/main/scala/Main.scala +++ /dev/null @@ -1,5 +0,0 @@ -@main def hello: Unit = - println("Hello world!") - println(msg) - -def msg = "I was compiled by Scala 3. :)" diff --git a/toad-java-glue-rs/Cargo.lock b/toad-java-glue-rs/Cargo.lock new file mode 100644 index 0000000..a0aa473 --- /dev/null +++ b/toad-java-glue-rs/Cargo.lock @@ -0,0 +1,792 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +dependencies = [ + "memchr", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bytes" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "combine" +version = "4.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "embedded-time" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a4b4d10ac48d08bfe3db7688c402baadb244721f30a77ce360bd24c3dffe58" +dependencies = [ + "num", +] + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "itoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" + +[[package]] +name = "java-locator" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72cb7c9d00a642469deceff95ca37d0da9ce72d7f8b863edbebdf0aac75093da" +dependencies = [ + "glob", + "lazy_static", +] + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "java-locator", + "jni-sys", + "libloading", + "log", + "thiserror", + "walkdir", + "windows-sys", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.141" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "naan" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6154b19920bf4498afaf169c5d619d5b351de6d83f8061c114e17061c1ebc612" + +[[package]] +name = "nb" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" + +[[package]] +name = "no-std-net" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" + +[[package]] +name = "num" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b7a8e9be5e039e2ff869df49155f1c06bd01ade2117ec783e56ab0932b67a8f" +dependencies = [ + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "747d632c0c558b87dbabbe6a82f3b4ae03720d0646ac5b7b4dae89394be5f2c5" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" + +[[package]] +name = "openssl" +version = "0.10.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d2f106ab837a24e03672c59b1239669a0596406ff657c3c0835b6b7f0f35a33" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.13", +] + +[[package]] +name = "openssl-sys" +version = "0.9.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a20eace9dc2d82904039cb76dcf50fb1a0bba071cfd1629720b5d6f1ddba0fa" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "paste" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" + +[[package]] +name = "pkg-config" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d0dd4be24fcdcfeaa12a432d588dc59bbad6cad3510c67e74a2b6b2fc950564" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "regex" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "ryu" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "serde" +version = "1.0.159" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065" + +[[package]] +name = "serde_json" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.13", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" + +[[package]] +name = "toad" +version = "0.17.2" +dependencies = [ + "embedded-time", + "log", + "naan", + "nb", + "no-std-net", + "openssl", + "paste", + "rand", + "rand_chacha", + "serde", + "serde_json", + "tinyvec", + "toad-array 0.2.3", + "toad-hash", + "toad-len", + "toad-macros", + "toad-map", + "toad-msg 0.15.1", + "toad-stem", + "toad-writable", +] + +[[package]] +name = "toad-array" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc3f25d13b8cbfe71fe854ff3c9a8f3f9729a5bd008089bb8dc8378b4ef3578f" +dependencies = [ + "tinyvec", + "toad-len", +] + +[[package]] +name = "toad-array" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "684a00a1501494fb37b8af23bfdf7b5f0a19ef71963abdf5e19eb4afb505f55a" +dependencies = [ + "tinyvec", + "toad-len", +] + +[[package]] +name = "toad-cursor" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dee8dde5a719faedaf8509f68a8ae1b72e6f0d96bcdbcd59b92de074fe7c33e" + +[[package]] +name = "toad-hash" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df947fa0b5724bb3c4e76d04b318a9466bf78a4880aea21a24f9c313d16b643b" +dependencies = [ + "blake2", +] + +[[package]] +name = "toad-java-glue" +version = "0.1.0" +dependencies = [ + "jni", + "tinyvec", + "toad", + "toad-jni", + "toad-msg 0.18.1", +] + +[[package]] +name = "toad-jni" +version = "0.1.0" +dependencies = [ + "jni", + "toad-array 0.5.0", + "toad-len", + "toad-stem", +] + +[[package]] +name = "toad-len" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819ba7124b9324c03a7043145430b0df5b10374543785d3cc5f773b9c0e36b37" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "toad-macros" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7496069c25b7e13b920d5293629d9e285d7a4ed9cd51ebfd2ce94690af779a" +dependencies = [ + "quote", + "regex", + "syn 1.0.109", +] + +[[package]] +name = "toad-map" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "423d547a014a817ea38dc677ca5e8488edf6aeeda36d69bdfcce5adf7b2a0918" +dependencies = [ + "tinyvec", + "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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78ad790094eefd8146fab35178e23b224285fe9b275132a31872c0f74b1a8ff" +dependencies = [ + "blake2", + "tinyvec", + "toad-array 0.2.3", + "toad-cursor", + "toad-hash", + "toad-len", + "toad-macros", + "toad-map", +] + +[[package]] +name = "toad-stem" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "834a7cc46ed626b24dfb861d3de19cdd666fa945f5bd1b4d2d675551afef927c" + +[[package]] +name = "toad-writable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe82c1076c85774b389e86cb2a2dbb846e35e599e9b42c8f2fc6628593cd0a9" +dependencies = [ + "toad-array 0.2.3", +] + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" diff --git a/toad-java-glue-rs/Cargo.toml b/toad-java-glue-rs/Cargo.toml new file mode 100644 index 0000000..4e82b82 --- /dev/null +++ b/toad-java-glue-rs/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "toad-java-glue" +version = "0.1.0" +edition = "2021" +publish = false + +[lib] +crate_type = ["cdylib"] + +[dependencies] +jni = "*" +toad = {path = "../../toad/toad"} +toad-jni = {path = "../../toad/toad-jni"} +toad-msg = "*" +tinyvec = {version = "1.5", default_features = false, features = ["rustc_1_55"]} diff --git a/toad-java-glue-rs/compile_commands.json b/toad-java-glue-rs/compile_commands.json new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/toad-java-glue-rs/compile_commands.json @@ -0,0 +1 @@ +[] diff --git a/toad-java-glue-rs/rust-toolchain.toml b/toad-java-glue-rs/rust-toolchain.toml new file mode 100644 index 0000000..5d56faf --- /dev/null +++ b/toad-java-glue-rs/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" diff --git a/toad-java-glue-rs/rustfmt.toml b/toad-java-glue-rs/rustfmt.toml new file mode 100644 index 0000000..9523d3e --- /dev/null +++ b/toad-java-glue-rs/rustfmt.toml @@ -0,0 +1,24 @@ +# General +max_width = 100 +newline_style = "Unix" +tab_spaces = 2 +indent_style = "Visual" +format_code_in_doc_comments = true +format_macro_bodies = true + +# Match statements +match_arm_leading_pipes = "Always" +match_block_trailing_comma = true + +# Structs +use_field_init_shorthand = true +struct_field_align_threshold = 0 + +# Enums +enum_discrim_align_threshold = 0 + +# Imports +group_imports = "StdExternalCrate" +imports_granularity = "Module" +imports_indent = "Visual" +imports_layout = "HorizontalVertical" diff --git a/toad-java-glue-rs/src/lib.rs b/toad-java-glue-rs/src/lib.rs new file mode 100644 index 0000000..1d509ec --- /dev/null +++ b/toad-java-glue-rs/src/lib.rs @@ -0,0 +1,68 @@ +#![feature(strict_provenance)] + +use jni::objects::{JClass, JObject}; +use jni::JNIEnv; +use toad::std::{dtls, Platform as Std}; +use toad::step::runtime::std::Runtime; + +pub static mut RUNTIME: *const Std> = std::ptr::null(); + +pub unsafe fn with_runtime_provenance(addr: i64) -> *mut T { + RUNTIME.with_addr(addr as usize).cast::().cast_mut() +} + +#[macro_export] +macro_rules! package { + // allows global compile-time refactoring if the package name ever changes + (dev.toad.$($thing:ident).+) => {$crate::package!(ext dev.toad.$($thing).+)}; + (ext $start:ident.$($thing:ident).+) => {concat!(stringify!($start), $("/", stringify!($thing)),+)}; +} + +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_config; + +// Class: dev_toad_Runtime +// Method: init +// Signature: (Ldev/toad/RuntimeOptions;)V +// JNIEXPORT void JNICALL Java_dev_toad_Runtime_init +// (JNIEnv *, jclass, jobject); +pub unsafe extern "system" fn Java_dev_toad_Runtime_init<'local>(mut env: JNIEnv<'local>, + _: JClass<'local>, + cfg: JObject<'local>) { +} + +#[cfg(test)] +mod tests { + use jni::{InitArgsBuilder, JavaVM}; + + use crate::runtime_config::RuntimeConfig; + + #[test] + fn package() { + assert_eq!(package!(dev.toad.msg.Foo.Bar.Baz), + "dev/toad/msg/Foo/Bar/Baz"); + assert_eq!(package!(ext java.lang.String), "java/lang/String"); + } + + #[test] + fn jvm_tests() { + let jvm = + JavaVM::new(InitArgsBuilder::new().option("--enable-preview") + .option("-Djava.class.path=../target/scala-3.2.2/classes/") + .build() + .unwrap()).unwrap(); + jvm.attach_current_thread_permanently(); + toad_jni::global::init_with(jvm); + + let mut e = toad_jni::global::env(); + let e = &mut e; + + let r = RuntimeConfig::new(e); + assert_eq!(r.to_toad(e), Default::default()); + } +} diff --git a/toad-java-glue-rs/src/message_code.rs b/toad-java-glue-rs/src/message_code.rs new file mode 100644 index 0000000..31e782e --- /dev/null +++ b/toad-java-glue-rs/src/message_code.rs @@ -0,0 +1,19 @@ +use jni::objects::{JClass, JObject}; +use jni::sys::jobject; +use jni::JNIEnv; +use toad_jni::Sig; +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 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) + } +} diff --git a/toad-java-glue-rs/src/message_opt_ref.rs b/toad-java-glue-rs/src/message_opt_ref.rs new file mode 100644 index 0000000..4d824b1 --- /dev/null +++ b/toad-java-glue-rs/src/message_opt_ref.rs @@ -0,0 +1,67 @@ +use jni::objects::{JClass, JObject}; +use jni::sys::jobject; +use jni::JNIEnv; +use toad_jni::Sig; +use toad_msg::{OptNumber, OptValue}; + +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); + + const NUMBER: &'static str = "number"; + + pub fn class(env: &mut JNIEnv<'local>) -> JClass<'local> { + env.find_class(Self::ID).unwrap() + } + + 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 unsafe fn values_ptr<'a>(addr: i64) -> &'a mut Vec>> { + with_runtime_provenance::>>>(addr).as_mut() + .unwrap() + } +} + +#[no_mangle] +pub unsafe extern "system" fn Java_dev_toad_msg_MessageOptionRef_number<'local>(mut env: JNIEnv<'local>, + o: JObject<'local>, + p: i64) + -> i64 { + MessageOptRef(o).number(&mut env).0 as i64 +} + +#[no_mangle] +pub unsafe extern "system" fn Java_dev_toad_msg_MessageOptionRef_values<'local>(mut env: JNIEnv<'local>, + _: JClass<'local>, + p: i64) + -> jobject { + let o = &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(); + + 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() +} diff --git a/toad-java-glue-rs/src/message_opt_value_ref.rs b/toad-java-glue-rs/src/message_opt_value_ref.rs new file mode 100644 index 0000000..bb4005b --- /dev/null +++ b/toad-java-glue-rs/src/message_opt_value_ref.rs @@ -0,0 +1,38 @@ +use jni::objects::{JClass, JObject}; +use jni::sys::jobject; +use jni::JNIEnv; +use toad_jni::Sig; +use toad_msg::{OptNumber, OptValue}; + +use crate::with_runtime_provenance; + +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 fn class(env: &mut JNIEnv<'local>) -> JClass<'local> { + env.find_class(Self::ID).unwrap() + } + + pub fn new(env: &mut JNIEnv<'local>, addr: i64) -> Self { + let o = env.new_object(Self::ID, Self::CTOR, &[addr.into()]) + .unwrap(); + Self(o) + } + + pub unsafe fn ptr<'a>(addr: i64) -> &'a mut OptValue> { + with_runtime_provenance::>>(addr).as_mut() + .unwrap() + } +} + +#[no_mangle] +pub unsafe extern "system" fn Java_dev_toad_msg_MessageOptionValueRef_bytes<'local>(mut env: JNIEnv<'local>, + _: JClass<'local>, + p: i64) + -> jobject { + env.byte_array_from_slice(MessageOptValueRef::ptr(p).as_bytes()) + .unwrap() + .as_raw() +} diff --git a/toad-java-glue-rs/src/message_ref.rs b/toad-java-glue-rs/src/message_ref.rs new file mode 100644 index 0000000..e5ad51a --- /dev/null +++ b/toad-java-glue-rs/src/message_ref.rs @@ -0,0 +1,91 @@ +use jni::objects::{JClass, JObject}; +use jni::sys::jobject; +use jni::JNIEnv; +use toad_jni::Sig; +use toad_msg::alloc::Message; + +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 fn new(env: &mut JNIEnv<'local>, addr: i64) -> Self { + let o = env.new_object(Self::ID, Self::CTOR, &[addr.into()]) + .unwrap(); + Self(o) + } + + pub unsafe fn ptr<'a>(addr: i64) -> &'a mut Message { + with_runtime_provenance::(addr).as_mut().unwrap() + } +} + +#[no_mangle] +pub unsafe extern "system" fn Java_dev_toad_msg_MessageRef_id<'local>(mut env: JNIEnv<'local>, + _: JClass<'local>, + addr: i64) + -> i32 { + MessageRef::ptr(addr).id.0 as i32 +} + +#[no_mangle] +pub unsafe extern "system" fn Java_dev_toad_msg_MessageRef_token<'local>(mut env: JNIEnv<'local>, + _: JClass<'local>, + addr: i64) + -> jobject { + env.byte_array_from_slice(&MessageRef::ptr(addr).token.0) + .unwrap() + .as_raw() +} + +#[no_mangle] +pub unsafe extern "system" fn Java_dev_toad_msg_MessageRef_payload<'local>(mut env: JNIEnv<'local>, + _: JClass<'local>, + addr: i64) + -> jobject { + env.byte_array_from_slice(&MessageRef::ptr(addr).payload.0) + .unwrap() + .as_raw() +} + +#[no_mangle] +pub unsafe extern "system" fn Java_dev_toad_msg_MessageRef_type<'local>(mut env: JNIEnv<'local>, + _: JClass<'local>, + addr: i64) + -> jobject { + MessageType::new(&mut env, MessageRef::ptr(addr).ty).0 + .into_raw() +} + +#[no_mangle] +pub unsafe extern "system" fn Java_dev_toad_msg_MessageRef_code<'local>(mut env: JNIEnv<'local>, + _: JClass<'local>, + addr: i64) + -> jobject { + MessageCode::new(&mut env, MessageRef::ptr(addr).code).0 + .into_raw() +} + +#[no_mangle] +pub unsafe extern "system" fn Java_dev_toad_msg_MessageRef_opts<'local>(mut env: JNIEnv<'local>, + _: JClass<'local>, + addr: i64) + -> jobject { + let opts = &MessageRef::ptr(addr).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(); + + 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() +} diff --git a/toad-java-glue-rs/src/message_type.rs b/toad-java-glue-rs/src/message_type.rs new file mode 100644 index 0000000..4a291e6 --- /dev/null +++ b/toad-java-glue-rs/src/message_type.rs @@ -0,0 +1,32 @@ +use jni::objects::{JObject, JString, JValueGen}; +use jni::sys::jstring; +use jni::JNIEnv; +use toad_jni::Sig; +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 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(); + + let o = env.call_static_method(Self::ID, + "fromString", + Self::FROM_STRING, + &[JValueGen::Object(&str)]) + .unwrap() + .l() + .unwrap(); + + Self(o) + } +} diff --git a/toad-java-glue-rs/src/retry_strategy.rs b/toad-java-glue-rs/src/retry_strategy.rs new file mode 100644 index 0000000..05ec932 --- /dev/null +++ b/toad-java-glue-rs/src/retry_strategy.rs @@ -0,0 +1,52 @@ +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; + +pub struct RetryStrategy(GlobalRef); + +impl RetryStrategy { + pub const PATH: &'static str = package!(dev.toad.RetryStrategy); + pub const EXPONENTIAL: &'static str = package!(dev.toad.RetryStrategy.Exponential); + pub const LINEAR: &'static str = package!(dev.toad.RetryStrategy.Linear); + + 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, "initMax", Sig::class(java::time::Duration::PATH)) + .unwrap() + .l() + .unwrap(); + let g = e.new_global_ref(o).unwrap(); + let d = java::time::Duration::from_java(g); + Millis::new(d.to_millis(e) as u64) + } + + 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") } + } else { + Strategy::Delay { min: self.millis_field(e, "min"), + max: self.millis_field(e, "max") } + } + } +} + +impl Object for RetryStrategy { + fn from_java(jobj: GlobalRef) -> Self { + Self(jobj) + } + + fn to_java(self) -> GlobalRef { + self.0 + } +} diff --git a/toad-java-glue-rs/src/runtime_config.rs b/toad-java-glue-rs/src/runtime_config.rs new file mode 100644 index 0000000..5d361e7 --- /dev/null +++ b/toad-java-glue-rs/src/runtime_config.rs @@ -0,0 +1,259 @@ +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 crate::retry_strategy::RetryStrategy; + +pub struct RuntimeConfig<'a>(JObject<'a>); + +impl<'a> RuntimeConfig<'a> { + pub 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) + } + + 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 to_toad(&self, e: &mut JNIEnv<'a>) -> config::Config { + let def = config::Config::default(); + + let net = self.net(e); + let msg = net.msg(e); + let con = msg.con(e); + let non = msg.non(e); + + config::Config { max_concurrent_requests: net.concurrency(e) as u8, + msg: config::Msg { token_seed: msg.token_seed(e) + .map(|i| i as u16) + .unwrap_or(def.msg.token_seed), + probing_rate: msg.probing_rate(e) + .map(|i| BytesPerSecond(i as u16)) + .unwrap_or(def.msg.probing_rate), + multicast_response_leisure: + msg.multicast_response_leisure(e) + .unwrap_or(def.msg.multicast_response_leisure), + con: + config::Con { unacked_retry_strategy: + con.unacked_retry_strategy(e) + .unwrap_or(def.msg + .con + .unacked_retry_strategy), + acked_retry_strategy: + con.acked_retry_strategy(e) + .unwrap_or(def.msg + .con + .acked_retry_strategy), + max_attempts: + con.max_attempts(e) + .map(|i| Attempts(i as u16)) + .unwrap_or(def.msg.con.max_attempts) }, + non: config::Non { retry_strategy: + non.retry_strategy(e) + .unwrap_or(def.msg + .non + .retry_strategy), + max_attempts: + non.max_attempts(e) + .map(|i| Attempts(i as u16)) + .unwrap_or(def.msg.non.max_attempts) } } } + } +} + +pub struct Net<'a>(JObject<'a>); +impl<'a> Net<'a> { + pub 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() + } + + 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 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 struct Msg<'a>(JObject<'a>); +impl<'a> Msg<'a> { + pub const PATH: &'static str = concat!(package!(dev.toad.RuntimeOptions), "$Msg"); + + pub const TOKEN_SEED: Sig = Sig::new().returning(Sig::class(java::util::Optional::::PATH)); + pub const PROBING_RATE: Sig = + Sig::new().returning(Sig::class(java::util::Optional::::PATH)); + pub const MULTICAST_RESP_LEISURE: Sig = + Sig::new().returning(Sig::class(java::util::Optional::::PATH)); + pub const CON: Sig = Sig::new().returning(Sig::class(Con::PATH)); + pub const NON: Sig = Sig::new().returning(Sig::class(Non::PATH)); + + pub fn token_seed(&self, e: &mut JNIEnv<'a>) -> Option { + let o = e.call_method(&self.0, "tokenSeed", Self::TOKEN_SEED, &[]) + .unwrap() + .l() + .unwrap(); + let g = e.new_global_ref(o).unwrap(); + java::util::Optional::::from_java(g).to_option(e) + } + + pub fn probing_rate(&self, e: &mut JNIEnv<'a>) -> Option { + let o = e.call_method(&self.0, + "probingRateBytesPerSecond", + Self::PROBING_RATE, + &[]) + .unwrap() + .l() + .unwrap(); + let g = e.new_global_ref(o).unwrap(); + java::util::Optional::::from_java(g).to_option(e) + } + + pub fn multicast_response_leisure(&self, e: &mut JNIEnv<'a>) -> Option { + let o = e.call_method(&self.0, + "multicastResponseLeisure", + Self::MULTICAST_RESP_LEISURE, + &[]) + .unwrap() + .l() + .unwrap(); + let g = e.new_global_ref(o).unwrap(); + java::util::Optional::::from_java(g).to_option(e) + .map(java::time::Duration::from_java) + .map(|d| Millis::new(d.to_millis(e) as u64)) + } + + pub fn 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 non(&self, e: &mut JNIEnv<'a>) -> Non<'a> { + let o = e.call_method(&self.0, "non", Self::NON, &[]) + .unwrap() + .l() + .unwrap(); + Non(o) + } +} + +pub struct Con<'a>(JObject<'a>); +impl<'a> Con<'a> { + pub const PATH: &'static str = concat!(package!(dev.toad.RuntimeOptions), "$Msg$Con"); + + pub const ACKED_RETRY_STRATEGY: Sig = + Sig::new().returning(Sig::class(java::util::Optional::::PATH)); + pub const UNACKED_RETRY_STRATEGY: Sig = + Sig::new().returning(Sig::class(java::util::Optional::::PATH)); + pub const MAX_ATTEMPTS: Sig = + Sig::new().returning(Sig::class(java::util::Optional::::PATH)); + + pub fn acked_retry_strategy(&self, e: &mut JNIEnv<'a>) -> Option { + let o = e.call_method(&self.0, + "ackedRetryStrategy", + Self::ACKED_RETRY_STRATEGY, + &[]) + .unwrap() + .l() + .unwrap(); + let g = e.new_global_ref(o).unwrap(); + java::util::Optional::::from_java(g).to_option(e) + .map(RetryStrategy::from_java) + .map(|j| j.to_toad(e)) + } + + pub fn unacked_retry_strategy(&self, e: &mut JNIEnv<'a>) -> Option { + let o = e.call_method(&self.0, + "unackedRetryStrategy", + Self::UNACKED_RETRY_STRATEGY, + &[]) + .unwrap() + .l() + .unwrap(); + let g = e.new_global_ref(o).unwrap(); + java::util::Optional::::from_java(g).to_option(e) + .map(RetryStrategy::from_java) + .map(|j| j.to_toad(e)) + } + + pub fn max_attempts(&self, e: &mut JNIEnv<'a>) -> Option { + let o = e.call_method(&self.0, "maxAttempts", Self::MAX_ATTEMPTS, &[]) + .unwrap() + .l() + .unwrap(); + let g = e.new_global_ref(o).unwrap(); + java::util::Optional::::from_java(g).to_option(e) + .map(java::lang::Integer::from_java) + .map(Primitive::dewrap) + } +} + +pub struct Non<'a>(JObject<'a>); +impl<'a> Non<'a> { + pub const PATH: &'static str = concat!(package!(dev.toad.RuntimeOptions), "$Msg$Non"); + + pub const RETRY_STRATEGY: Sig = + Sig::new().returning(Sig::class(java::util::Optional::::PATH)); + pub const MAX_ATTEMPTS: Sig = + Sig::new().returning(Sig::class(java::util::Optional::::PATH)); + + pub fn retry_strategy(&self, e: &mut JNIEnv<'a>) -> Option { + let o = e.call_method(&self.0, "retryStrategy", Self::RETRY_STRATEGY, &[]) + .unwrap() + .l() + .unwrap(); + let g = e.new_global_ref(o).unwrap(); + java::util::Optional::::from_java(g).to_option(e) + .map(RetryStrategy::from_java) + .map(|j| j.to_toad(e)) + } + + pub fn max_attempts(&self, e: &mut JNIEnv<'a>) -> Option { + let o = e.call_method(&self.0, "maxAttempts", Self::MAX_ATTEMPTS, &[]) + .unwrap() + .l() + .unwrap(); + let g = e.new_global_ref(o).unwrap(); + java::util::Optional::::from_java(g).to_option(e) + .map(java::lang::Integer::from_java) + .map(Primitive::dewrap) + } +}