chore: rename toad-java-glue-rs -> glue, WIP ffi package with uint types
This commit is contained in:
parent
4c981c9c9a
commit
42c30b84dd
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,5 +1,3 @@
|
|||||||
toad-jni.so
|
|
||||||
|
|
||||||
# macOS
|
# macOS
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
|
12
build.sbt
12
build.sbt
@ -5,7 +5,7 @@ import sbt.nio.file.FileTreeView
|
|||||||
Global / onChangedBuildSource := ReloadOnSourceChanges
|
Global / onChangedBuildSource := ReloadOnSourceChanges
|
||||||
|
|
||||||
val scala3Version = "3.2.2"
|
val scala3Version = "3.2.2"
|
||||||
val cargoBuild = taskKey[Unit]("cd ./toad-java-glue-rs; cargo build")
|
val cargoBuild = taskKey[Unit]("cd ./glue; cargo build")
|
||||||
val ejectHeaders = taskKey[Unit]("Generate C headers for FFI")
|
val ejectHeaders = taskKey[Unit]("Generate C headers for FFI")
|
||||||
val fullBuild = taskKey[Unit]("cargoBuild > ejectHeaders")
|
val fullBuild = taskKey[Unit]("cargoBuild > ejectHeaders")
|
||||||
val glob = settingKey[Map[String, Glob]]("globs")
|
val glob = settingKey[Map[String, Glob]]("globs")
|
||||||
@ -14,7 +14,7 @@ val path = settingKey[Map[String, String]]("paths")
|
|||||||
fork := true
|
fork := true
|
||||||
|
|
||||||
javaOptions += "--enable-preview"
|
javaOptions += "--enable-preview"
|
||||||
javacOptions ++= Seq("--enable-preview", "--release", "20", "-Xlint:preview")
|
javacOptions ++= Seq("--enable-preview", "--release", "20")
|
||||||
|
|
||||||
lazy val root = project
|
lazy val root = project
|
||||||
.in(file("."))
|
.in(file("."))
|
||||||
@ -25,11 +25,11 @@ lazy val root = project
|
|||||||
libraryDependencies += "org.scalameta" %% "munit" % "0.7.29" % Test,
|
libraryDependencies += "org.scalameta" %% "munit" % "0.7.29" % Test,
|
||||||
glob := Map(
|
glob := Map(
|
||||||
"java.sources" -> baseDirectory.value.toGlob / "src" / "main" / "java" / ** / "*.java",
|
"java.sources" -> baseDirectory.value.toGlob / "src" / "main" / "java" / ** / "*.java",
|
||||||
"glue.sources" -> baseDirectory.value.toGlob / "toad-java-glue-rs" / "src" / ** / "*.rs"
|
"glue.sources" -> baseDirectory.value.toGlob / "glue" / "src" / ** / "*.rs"
|
||||||
),
|
),
|
||||||
path := Map(
|
path := Map(
|
||||||
"glue.base" -> (baseDirectory.value / "toad-java-glue-rs").toString,
|
"glue.base" -> (baseDirectory.value / "glue").toString,
|
||||||
"glue.target" -> (baseDirectory.value / "toad-java-glue-rs" / "target" / "debug").toString,
|
"glue.target" -> (baseDirectory.value / "target" / "glue" / "debug").toString,
|
||||||
"java.classTarget" -> (baseDirectory.value / "target" / "scala-3.2.2" / "classes").toString
|
"java.classTarget" -> (baseDirectory.value / "target" / "scala-3.2.2" / "classes").toString
|
||||||
),
|
),
|
||||||
ejectHeaders := {
|
ejectHeaders := {
|
||||||
@ -52,7 +52,7 @@ lazy val root = project
|
|||||||
},
|
},
|
||||||
cargoBuild := {
|
cargoBuild := {
|
||||||
val cmd =
|
val cmd =
|
||||||
Seq("sh", "-c", "cd toad-java-glue-rs; cargo rustc -- -Awarnings")
|
Seq("sh", "-c", "cd glue; cargo rustc -- -Awarnings")
|
||||||
println(cmd !!)
|
println(cmd !!)
|
||||||
},
|
},
|
||||||
fullBuild := {
|
fullBuild := {
|
||||||
|
2
glue/.cargo/config.toml
Normal file
2
glue/.cargo/config.toml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[build]
|
||||||
|
target-dir = "../target/native"
|
6
toad-java-glue-rs/Cargo.lock → glue/Cargo.lock
generated
6
toad-java-glue-rs/Cargo.lock → glue/Cargo.lock
generated
@ -505,6 +505,8 @@ checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "toad"
|
name = "toad"
|
||||||
version = "0.17.2"
|
version = "0.17.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a6e3e3216e542ea3b2da0d2200e498b016907b68acb288b47a487cb9fd681b42"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"embedded-time",
|
"embedded-time",
|
||||||
"log",
|
"log",
|
||||||
@ -576,7 +578,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toad-jni"
|
name = "toad-jni"
|
||||||
version = "0.1.0"
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8211cccf8f1dce2768a85b6f42b1d232542ecb616584bc9915da1cfc50c3d3d1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jni",
|
"jni",
|
||||||
"toad-array 0.5.0",
|
"toad-array 0.5.0",
|
@ -9,7 +9,7 @@ crate_type = ["cdylib"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
jni = "*"
|
jni = "*"
|
||||||
toad = {path = "../../toad/toad"}
|
toad = "0.17.2"
|
||||||
toad-jni = {path = "../../toad/toad-jni"}
|
toad-jni = "0.4.0"
|
||||||
toad-msg = "*"
|
toad-msg = "0.18.1"
|
||||||
tinyvec = {version = "1.5", default_features = false, features = ["rustc_1_55"]}
|
tinyvec = {version = "1.5", default_features = false, features = ["rustc_1_55"]}
|
@ -18,6 +18,7 @@ macro_rules! package {
|
|||||||
(ext $start:ident.$($thing:ident).+) => {concat!(stringify!($start), $("/", stringify!($thing)),+)};
|
(ext $start:ident.$($thing:ident).+) => {concat!(stringify!($start), $("/", stringify!($thing)),+)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod uint;
|
||||||
pub mod message_code;
|
pub mod message_code;
|
||||||
pub mod message_opt_ref;
|
pub mod message_opt_ref;
|
||||||
pub mod message_opt_value_ref;
|
pub mod message_opt_value_ref;
|
||||||
@ -39,7 +40,10 @@ pub unsafe extern "system" fn Java_dev_toad_Runtime_init<'local>(mut env: JNIEnv
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use jni::{InitArgsBuilder, JavaVM};
|
use jni::{InitArgsBuilder, JavaVM};
|
||||||
|
use toad::retry::Strategy;
|
||||||
|
use toad::time::Millis;
|
||||||
|
|
||||||
|
use crate::retry_strategy::RetryStrategy;
|
||||||
use crate::runtime_config::RuntimeConfig;
|
use crate::runtime_config::RuntimeConfig;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -64,5 +68,13 @@ mod tests {
|
|||||||
|
|
||||||
let r = RuntimeConfig::new(e);
|
let r = RuntimeConfig::new(e);
|
||||||
assert_eq!(r.to_toad(e), Default::default());
|
assert_eq!(r.to_toad(e), Default::default());
|
||||||
|
|
||||||
|
let r = Strategy::Exponential { init_min: Millis::new(0),
|
||||||
|
init_max: Millis::new(100) };
|
||||||
|
assert_eq!(RetryStrategy::from_toad(e, r).to_toad(e), r);
|
||||||
|
|
||||||
|
let r = Strategy::Delay { min: Millis::new(0),
|
||||||
|
max: Millis::new(100) };
|
||||||
|
assert_eq!(RetryStrategy::from_toad(e, r).to_toad(e), r);
|
||||||
}
|
}
|
||||||
}
|
}
|
87
glue/src/retry_strategy.rs
Normal file
87
glue/src/retry_strategy.rs
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
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.RetryStrategyExponential);
|
||||||
|
pub const EXPONENTIAL_CTOR: Sig = Sig::new().arg(Sig::class(java::time::Duration::PATH))
|
||||||
|
.arg(Sig::class(java::time::Duration::PATH))
|
||||||
|
.returning(Sig::VOID);
|
||||||
|
|
||||||
|
pub const DELAY: &'static str = package!(dev.toad.RetryStrategyDelay);
|
||||||
|
pub const DELAY_CTOR: Sig = Sig::new().arg(Sig::class(java::time::Duration::PATH))
|
||||||
|
.arg(Sig::class(java::time::Duration::PATH))
|
||||||
|
.returning(Sig::VOID);
|
||||||
|
|
||||||
|
pub fn exp<'a>(&self, e: &mut JNIEnv<'a>) -> Self {
|
||||||
|
let o = e.new_object(Self::PATH, Sig::new().returning(Sig::VOID), &[])
|
||||||
|
.unwrap();
|
||||||
|
let g = e.new_global_ref(o).unwrap();
|
||||||
|
Self(g)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn millis_field<'a>(&self, e: &mut JNIEnv<'a>, key: &str) -> Millis {
|
||||||
|
let o = e.get_field(&self.0, key, Sig::class(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") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_toad<'a>(e: &mut JNIEnv<'a>, s: Strategy) -> Self {
|
||||||
|
let g = match s {
|
||||||
|
| Strategy::Delay { min, max } => {
|
||||||
|
let (min, max) = (java::time::Duration::of_millis(e, min.0 as i64),
|
||||||
|
java::time::Duration::of_millis(e, max.0 as i64));
|
||||||
|
let (min, max) = (min.to_java(), max.to_java());
|
||||||
|
let o = e.new_object(Self::DELAY,
|
||||||
|
Self::DELAY_CTOR,
|
||||||
|
&[min.as_obj().into(), max.as_obj().into()])
|
||||||
|
.unwrap();
|
||||||
|
e.new_global_ref(o).unwrap()
|
||||||
|
},
|
||||||
|
| Strategy::Exponential { init_min, init_max } => {
|
||||||
|
let (init_min, init_max) = (java::time::Duration::of_millis(e, init_min.0 as i64),
|
||||||
|
java::time::Duration::of_millis(e, init_max.0 as i64));
|
||||||
|
let (init_min, init_max) = (init_min.to_java(), init_max.to_java());
|
||||||
|
let o = e.new_object(Self::EXPONENTIAL,
|
||||||
|
Self::EXPONENTIAL_CTOR,
|
||||||
|
&[init_min.as_obj().into(), init_max.as_obj().into()])
|
||||||
|
.unwrap();
|
||||||
|
e.new_global_ref(o).unwrap()
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Self(g)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Object for RetryStrategy {
|
||||||
|
fn from_java(jobj: GlobalRef) -> Self {
|
||||||
|
Self(jobj)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_java(self) -> GlobalRef {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
58
glue/src/uint.rs
Normal file
58
glue/src/uint.rs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
use jni::{JNIEnv, objects::{JObject, JByteArray}};
|
||||||
|
use toad_jni::Sig;
|
||||||
|
|
||||||
|
pub mod path {
|
||||||
|
pub const U64: &'static str = package!(dev.toad.ffi.u64);
|
||||||
|
pub const U32: &'static str = package!(dev.toad.ffi.u32);
|
||||||
|
pub const U16: &'static str = package!(dev.toad.ffi.u16);
|
||||||
|
pub const U8: &'static str = package!(dev.toad.ffi.u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn u64<'a>(e: &mut JNIEnv<'a>, o: JObject<'a>) -> u64 {
|
||||||
|
let bi = e.call_method(o, "bigintValue", Sig::new().returning(Sig::class("java.math.BigInteger")), &[]).unwrap().l().unwrap();
|
||||||
|
let barr: JByteArray<'a> = e.call_method(bi, "toByteArray", Sig::new().returning(Sig::array_of(Sig::BYTE)), &[]).unwrap().l().unwrap().try_into().unwrap();
|
||||||
|
|
||||||
|
let mut bytes = [0i8; 8];
|
||||||
|
|
||||||
|
// BigInteger is a growable two's complement integer
|
||||||
|
//
|
||||||
|
// the "growable" comes from its backing structure being a simple
|
||||||
|
// int array `int[]`, where bytes are added as needed to afford capacity.
|
||||||
|
//
|
||||||
|
// two's-complement means the most significant bit (the first bit of the first byte)
|
||||||
|
// indicates the sign of the integer, where 0 is positive and 1 is negative.
|
||||||
|
//
|
||||||
|
// The rest of the bits are unchanged, meaning the range is from `-(2^(n - 1))`
|
||||||
|
// to `2^(n - 1) - 1`.
|
||||||
|
//
|
||||||
|
// For example, a two's complement i8 would be able to represent `-128` (`0b11111111`),
|
||||||
|
// `0` (`0b00000000`) to `127` (`0b01111111`). for positive integers, the representation is
|
||||||
|
// the same as unsigned integers, meaning we simply need to make sure we don't accidentally
|
||||||
|
// interpret the first bit as part of the integer.
|
||||||
|
//
|
||||||
|
// Here we assume whoever is responsible for BigInteger made sure that it's positive,
|
||||||
|
// so converting the big-endian two's complement int
|
||||||
|
e.get_byte_array_region(&barr, 0, &mut bytes).unwrap();
|
||||||
|
|
||||||
|
// https://docs.oracle.com/en/java/javase/19/docs/api/java.base/java/math/BigInteger.html#toByteArray()
|
||||||
|
//
|
||||||
|
// BigInt.toByteArray actually returns the raw byte representation of the integer, NOT
|
||||||
|
// two's complement `byte`s as the type signature would lead you to believe.
|
||||||
|
//
|
||||||
|
// To interpret these bytes as i8 is incorrect.
|
||||||
|
let bytes = bytes.map(|i| i8::to_be_bytes(i)[0]);
|
||||||
|
|
||||||
|
u64::from_be_bytes(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn u32<'a>(e: &mut JNIEnv<'a>, o: JObject<'a>) -> u32 {
|
||||||
|
e.call_method(o, "longValue", Sig::new().returning(Sig::LONG), &[]).unwrap().j().unwrap() as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn u16<'a>(e: &mut JNIEnv<'a>, o: JObject<'a>) -> u16 {
|
||||||
|
e.call_method(o, "intValue", Sig::new().returning(Sig::INT), &[]).unwrap().i().unwrap() as u16
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn u8<'a>(e: &mut JNIEnv<'a>, o: JObject<'a>) -> u8 {
|
||||||
|
e.call_method(o, "shortValue", Sig::new().returning(Sig::SHORT), &[]).unwrap().s().unwrap() as u8
|
||||||
|
}
|
@ -1,53 +1,3 @@
|
|||||||
package dev.toad;
|
package dev.toad;
|
||||||
|
|
||||||
import java.time.Duration;
|
public abstract sealed class RetryStrategy permits RetryStrategyDelay, RetryStrategyExponential { }
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
27
src/main/java/dev.toad/RetryStrategyDelay.java
Normal file
27
src/main/java/dev.toad/RetryStrategyDelay.java
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package dev.toad;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public final class RetryStrategyDelay extends RetryStrategy {
|
||||||
|
|
||||||
|
public final Duration min;
|
||||||
|
public final Duration max;
|
||||||
|
|
||||||
|
private static native RetryStrategyDelay fromRust(byte[] mem);
|
||||||
|
|
||||||
|
private native byte[] toRust();
|
||||||
|
|
||||||
|
public RetryStrategyDelay(Duration min, Duration max) {
|
||||||
|
this.min = min;
|
||||||
|
this.max = max;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object other) {
|
||||||
|
return switch (other) {
|
||||||
|
case RetryStrategyDelay e -> e.min == this.min && e.max == this.max;
|
||||||
|
default -> false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
27
src/main/java/dev.toad/RetryStrategyExponential.java
Normal file
27
src/main/java/dev.toad/RetryStrategyExponential.java
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package dev.toad;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public final class RetryStrategyExponential extends RetryStrategy {
|
||||||
|
|
||||||
|
public final Duration initMin;
|
||||||
|
public final Duration initMax;
|
||||||
|
|
||||||
|
private static native RetryStrategyExponential fromRust(byte[] mem);
|
||||||
|
|
||||||
|
private native byte[] toRust();
|
||||||
|
|
||||||
|
public RetryStrategyExponential(Duration initMin, Duration initMax) {
|
||||||
|
this.initMin = initMin;
|
||||||
|
this.initMax = initMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object other) {
|
||||||
|
return switch (other) {
|
||||||
|
case RetryStrategyExponential e -> e.initMin == this.initMin && e.initMax == this.initMax;
|
||||||
|
default -> false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package dev.toad;
|
package dev.toad;
|
||||||
|
|
||||||
|
import dev.toad.ffi.*;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
@ -44,13 +45,13 @@ public final class RuntimeOptions implements Cloneable {
|
|||||||
|
|
||||||
public final class Net implements Cloneable {
|
public final class Net implements Cloneable {
|
||||||
|
|
||||||
private short port;
|
private u16 port;
|
||||||
private short concurrency;
|
private u8 concurrency;
|
||||||
private Msg msg;
|
private Msg msg;
|
||||||
|
|
||||||
public Net() {
|
public Net() {
|
||||||
this.port = 5683;
|
this.port = new u16(5683);
|
||||||
this.concurrency = 1;
|
this.concurrency = new u8((short)1);
|
||||||
this.msg = new Msg();
|
this.msg = new Msg();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,12 +78,12 @@ public final class RuntimeOptions implements Cloneable {
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
public short port() {
|
public int port() {
|
||||||
return this.port;
|
return this.port.intValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public short concurrency() {
|
public short concurrency() {
|
||||||
return this.concurrency;
|
return this.concurrency.shortValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Msg msg() {
|
public Msg msg() {
|
||||||
@ -91,14 +92,14 @@ public final class RuntimeOptions implements Cloneable {
|
|||||||
|
|
||||||
public Net withPort(short port) {
|
public Net withPort(short port) {
|
||||||
return this.with(self -> {
|
return this.with(self -> {
|
||||||
self.port = port;
|
self.port = new u16(port);
|
||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public Net withConcurrency(short conc) {
|
public Net withConcurrency(short conc) {
|
||||||
return this.with(self -> {
|
return this.with(self -> {
|
||||||
self.concurrency = conc;
|
self.concurrency = new u8(conc);
|
||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -113,8 +114,8 @@ public final class RuntimeOptions implements Cloneable {
|
|||||||
|
|
||||||
public final class Msg implements Cloneable {
|
public final class Msg implements Cloneable {
|
||||||
|
|
||||||
private Optional<Integer> tokenSeed = Optional.empty();
|
private Optional<u16> tokenSeed = Optional.empty();
|
||||||
private Optional<Integer> probingRateBytesPerSecond = Optional.empty();
|
private Optional<u16> probingRateBytesPerSecond = Optional.empty();
|
||||||
private Optional<Duration> multicastResponseLeisure = Optional.empty();
|
private Optional<Duration> multicastResponseLeisure = Optional.empty();
|
||||||
private Con con;
|
private Con con;
|
||||||
private Non non;
|
private Non non;
|
||||||
@ -152,11 +153,11 @@ public final class RuntimeOptions implements Cloneable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Optional<Integer> tokenSeed() {
|
public Optional<Integer> tokenSeed() {
|
||||||
return this.tokenSeed;
|
return this.tokenSeed.map(u16 -> u16.intValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<Integer> probingRateBytesPerSecond() {
|
public Optional<Integer> probingRateBytesPerSecond() {
|
||||||
return this.probingRateBytesPerSecond;
|
return this.probingRateBytesPerSecond.map(u16 -> u16.intValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<Duration> multicastResponseLeisure() {
|
public Optional<Duration> multicastResponseLeisure() {
|
||||||
@ -173,14 +174,14 @@ public final class RuntimeOptions implements Cloneable {
|
|||||||
|
|
||||||
public Msg withTokenSeed(int tokenSeed) {
|
public Msg withTokenSeed(int tokenSeed) {
|
||||||
return this.with(self -> {
|
return this.with(self -> {
|
||||||
self.tokenSeed = Optional.of(tokenSeed);
|
self.tokenSeed = Optional.of(new u16(tokenSeed));
|
||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public Msg withProbingRateBytesBerSecond(int bps) {
|
public Msg withProbingRateBytesBerSecond(int bps) {
|
||||||
return this.with(m -> {
|
return this.with(m -> {
|
||||||
m.probingRateBytesPerSecond = Optional.of(bps);
|
m.probingRateBytesPerSecond = Optional.of(new u16(bps));
|
||||||
return m;
|
return m;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -210,7 +211,7 @@ public final class RuntimeOptions implements Cloneable {
|
|||||||
|
|
||||||
private Optional<RetryStrategy> ackedRetryStrategy = Optional.empty();
|
private Optional<RetryStrategy> ackedRetryStrategy = Optional.empty();
|
||||||
private Optional<RetryStrategy> unackedRetryStrategy = Optional.empty();
|
private Optional<RetryStrategy> unackedRetryStrategy = Optional.empty();
|
||||||
private Optional<Integer> maxAttempts = Optional.empty();
|
private Optional<u16> maxAttempts = Optional.empty();
|
||||||
|
|
||||||
public Con() {}
|
public Con() {}
|
||||||
|
|
||||||
@ -237,7 +238,7 @@ public final class RuntimeOptions implements Cloneable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Optional<Integer> maxAttempts() {
|
public Optional<Integer> maxAttempts() {
|
||||||
return this.maxAttempts;
|
return this.maxAttempts.map(u16 -> u16.intValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Con withAckedRetryStrategy(RetryStrategy r) {
|
public Con withAckedRetryStrategy(RetryStrategy r) {
|
||||||
@ -256,7 +257,7 @@ public final class RuntimeOptions implements Cloneable {
|
|||||||
|
|
||||||
public Con withMaxAttempts(int a) {
|
public Con withMaxAttempts(int a) {
|
||||||
return this.with(s -> {
|
return this.with(s -> {
|
||||||
s.maxAttempts = Optional.of(a);
|
s.maxAttempts = Optional.of(new u16(a));
|
||||||
return s;
|
return s;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -270,7 +271,7 @@ public final class RuntimeOptions implements Cloneable {
|
|||||||
public final class Non implements Cloneable {
|
public final class Non implements Cloneable {
|
||||||
|
|
||||||
private Optional<RetryStrategy> retryStrategy = Optional.empty();
|
private Optional<RetryStrategy> retryStrategy = Optional.empty();
|
||||||
private Optional<Integer> maxAttempts = Optional.empty();
|
private Optional<u16> maxAttempts = Optional.empty();
|
||||||
|
|
||||||
public Non() {}
|
public Non() {}
|
||||||
|
|
||||||
@ -292,7 +293,7 @@ public final class RuntimeOptions implements Cloneable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Optional<Integer> maxAttempts() {
|
public Optional<Integer> maxAttempts() {
|
||||||
return this.maxAttempts;
|
return this.maxAttempts.map(u16 -> u16.intValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Non withRetryStrategy(RetryStrategy r) {
|
public Non withRetryStrategy(RetryStrategy r) {
|
||||||
@ -304,7 +305,7 @@ public final class RuntimeOptions implements Cloneable {
|
|||||||
|
|
||||||
public Non withMaxAttempts(int a) {
|
public Non withMaxAttempts(int a) {
|
||||||
return this.with(s -> {
|
return this.with(s -> {
|
||||||
s.maxAttempts = Optional.of(a);
|
s.maxAttempts = Optional.of(new u16(a));
|
||||||
return s;
|
return s;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
15
src/main/java/dev.toad/ffi/u16.java
Normal file
15
src/main/java/dev.toad/ffi/u16.java
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package dev.toad.ffi;
|
||||||
|
|
||||||
|
public final class u16 {
|
||||||
|
public static final int MAX = (int)(Math.pow(2, 16) - 1);
|
||||||
|
private final int l;
|
||||||
|
|
||||||
|
public u16(int l) {
|
||||||
|
uint.assertWithinRange(this.MAX, l);
|
||||||
|
this.l = l;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int intValue() {
|
||||||
|
return this.l;
|
||||||
|
}
|
||||||
|
}
|
15
src/main/java/dev.toad/ffi/u32.java
Normal file
15
src/main/java/dev.toad/ffi/u32.java
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package dev.toad.ffi;
|
||||||
|
|
||||||
|
public final class u32 {
|
||||||
|
public static final long MAX = (long)(Math.pow(2, 32) - 1);
|
||||||
|
private final long l;
|
||||||
|
|
||||||
|
public u32(long l) {
|
||||||
|
uint.assertWithinRange(this.MAX, l);
|
||||||
|
this.l = l;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long longValue() {
|
||||||
|
return this.l;
|
||||||
|
}
|
||||||
|
}
|
17
src/main/java/dev.toad/ffi/u64.java
Normal file
17
src/main/java/dev.toad/ffi/u64.java
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package dev.toad.ffi;
|
||||||
|
|
||||||
|
public final class u64 {
|
||||||
|
public static final double MAX = Math.pow(2, 64) - 1;
|
||||||
|
private final double l;
|
||||||
|
|
||||||
|
public u64(double l) {
|
||||||
|
uint.assertWithinRange(this.MAX, l);
|
||||||
|
uint.assertNatural(l);
|
||||||
|
|
||||||
|
this.l = l;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double doubleValue() {
|
||||||
|
return this.l;
|
||||||
|
}
|
||||||
|
}
|
15
src/main/java/dev.toad/ffi/u8.java
Normal file
15
src/main/java/dev.toad/ffi/u8.java
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package dev.toad.ffi;
|
||||||
|
|
||||||
|
public final class u8 {
|
||||||
|
public static final short MAX = (short)(Math.pow(2, 8) - 1);
|
||||||
|
private final short l;
|
||||||
|
|
||||||
|
public u8(short l) {
|
||||||
|
uint.assertWithinRange(this.MAX, l);
|
||||||
|
this.l = l;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short shortValue() {
|
||||||
|
return this.l;
|
||||||
|
}
|
||||||
|
}
|
15
src/main/java/dev.toad/ffi/uint.java
Normal file
15
src/main/java/dev.toad/ffi/uint.java
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package dev.toad.ffi;
|
||||||
|
|
||||||
|
public class uint {
|
||||||
|
public static void assertWithinRange(double max, double n) {
|
||||||
|
if (n < 0 || n > max) {
|
||||||
|
throw new IllegalArgumentException(String.format("% must be between 0 and %", n, max));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void assertNatural(double n) {
|
||||||
|
if (n % 1 > 0.0) {
|
||||||
|
throw new IllegalArgumentException(String.format("% must be a whole integer", n));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,52 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user