mirror of
https://github.com/signalapp/libsignal.git
synced 2024-09-20 03:52:17 +02:00
Java: Teach gen_java_decl about Futures for type-safety.
This commit is contained in:
parent
2c295f68c9
commit
a15fffd058
@ -50,13 +50,13 @@ public class FutureTest {
|
||||
|
||||
@Test
|
||||
public void testSuccessFromRust() throws Exception {
|
||||
Future<Integer> future = (Future<Integer>)Native.Future_success();
|
||||
Future<Integer> future = Native.Future_success();
|
||||
assertEquals(42, (int) future.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailureFromRust() throws Exception {
|
||||
Future<Integer> future = (Future<Integer>)Native.Future_failure();
|
||||
Future<Integer> future = Native.Future_failure();
|
||||
ExecutionException e = assertThrows(ExecutionException.class, () -> future.get());
|
||||
assertTrue(e.getCause() instanceof IllegalArgumentException);
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.UUID;
|
||||
import java.util.Map;
|
||||
|
||||
@ -199,8 +200,8 @@ public final class Native {
|
||||
public static native void ExpiringProfileKeyCredential_CheckValidContents(byte[] buffer);
|
||||
public static native long ExpiringProfileKeyCredential_GetExpirationTime(byte[] credential);
|
||||
|
||||
public static native Object Future_failure();
|
||||
public static native Object Future_success();
|
||||
public static native Future<Integer> Future_failure();
|
||||
public static native Future<Integer> Future_success();
|
||||
|
||||
public static native void GenericServerPublicParams_CheckValidContents(byte[] paramsBytes);
|
||||
|
||||
|
@ -23,6 +23,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.UUID;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -40,7 +40,8 @@ ignore_this_warning = re.compile(
|
||||
r"WARN: Can't find .*\. This usually means that this type was incompatible or not found\.|"
|
||||
r"WARN: Missing `\[defines\]` entry for `feature = \".*\"` in cbindgen config\.|"
|
||||
r"WARN: Skip libsignal-bridge::.+ - \(not `(?:pub|no_mangle)`\)\.|"
|
||||
r"WARN: Couldn't find path for Array\(Path\(GenericPath \{ .+ \}\), Name\(\"LEN\"\)\), skipping associated constants"
|
||||
r"WARN: Couldn't find path for Array\(Path\(GenericPath \{ .+ \}\), Name\(\"LEN\"\)\), skipping associated constants|"
|
||||
r"WARN: Cannot find a mangling for generic path GenericPath { path: Path { name: \"JavaFuture\" }.+"
|
||||
")")
|
||||
|
||||
unknown_warning = False
|
||||
@ -58,7 +59,23 @@ for l in stderr.split('\n'):
|
||||
if unknown_warning:
|
||||
sys.exit(1)
|
||||
|
||||
java_decl = re.compile(r'([a-zA-Z]+) Java_org_signal_libsignal_internal_Native_([A-Z][a-zA-Z0-9]+)_1([A-Za-z0-9]+)\(JNIEnv .?env, JClass class_(, .*)?\);')
|
||||
java_decl = re.compile(r'([a-zA-Z]+(?:<.+>)?) Java_org_signal_libsignal_internal_Native_([A-Z][a-zA-Z0-9]+)_1([A-Za-z0-9]+)\(JNIEnv .?env, JClass class_(, .*)?\);')
|
||||
|
||||
|
||||
def box_primitives(typ):
|
||||
type_map = {
|
||||
"void": "Void",
|
||||
"boolean": "Boolean",
|
||||
"char": "Character",
|
||||
"byte": "Byte",
|
||||
"short": "Short",
|
||||
"int": "Integer",
|
||||
"long": "Long",
|
||||
"float": "Float",
|
||||
"double": "Double",
|
||||
}
|
||||
|
||||
return type_map.get(typ, typ)
|
||||
|
||||
|
||||
def translate_to_java(typ):
|
||||
@ -78,7 +95,11 @@ def translate_to_java(typ):
|
||||
if typ in type_map:
|
||||
return type_map[typ]
|
||||
|
||||
# Assume anything prefixed with "Java" refers to an object
|
||||
if typ.startswith('JavaFuture<'):
|
||||
assert typ.endswith('>')
|
||||
return 'Future<' + box_primitives(translate_to_java(typ[11:-1])) + '>'
|
||||
|
||||
# Assume anything else prefixed with "Java" refers to an object
|
||||
if typ.startswith('Java'):
|
||||
return typ[4:]
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#![deny(clippy::unwrap_used)]
|
||||
|
||||
use jni::objects::{JByteArray, JClass, JLongArray, JObject};
|
||||
use jni::sys::jint;
|
||||
use jni::JNIEnv;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
@ -53,7 +54,7 @@ pub unsafe extern "C" fn Java_org_signal_libsignal_internal_Native_keepAlive(
|
||||
pub unsafe extern "C" fn Java_org_signal_libsignal_internal_Native_Future_1success<'local>(
|
||||
mut env: JNIEnv<'local>,
|
||||
_class: JClass,
|
||||
) -> JObject<'local> {
|
||||
) -> JavaFuture<'local, jint> {
|
||||
run_ffi_safe(&mut env, |env| {
|
||||
let future = new_object(
|
||||
env,
|
||||
@ -62,7 +63,7 @@ pub unsafe extern "C" fn Java_org_signal_libsignal_internal_Native_Future_1succe
|
||||
)?;
|
||||
let completer = FutureCompleter::new(env, &future)?;
|
||||
std::thread::spawn(move || completer.complete(42));
|
||||
Ok(future)
|
||||
Ok(future.into())
|
||||
})
|
||||
}
|
||||
|
||||
@ -70,7 +71,7 @@ pub unsafe extern "C" fn Java_org_signal_libsignal_internal_Native_Future_1succe
|
||||
pub unsafe extern "C" fn Java_org_signal_libsignal_internal_Native_Future_1failure<'local>(
|
||||
mut env: JNIEnv<'local>,
|
||||
_class: JClass,
|
||||
) -> JObject<'local> {
|
||||
) -> JavaFuture<'local, jint> {
|
||||
run_ffi_safe(&mut env, |env| {
|
||||
let future = new_object(
|
||||
env,
|
||||
@ -83,6 +84,6 @@ pub unsafe extern "C" fn Java_org_signal_libsignal_internal_Native_Future_1failu
|
||||
"failure".to_string(),
|
||||
)))
|
||||
});
|
||||
Ok(future)
|
||||
Ok(future.into())
|
||||
})
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ use signal_pin::Error as PinError;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::error::Error;
|
||||
use std::fmt::Display;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub(crate) use jni::objects::{
|
||||
AutoElements, JByteArray, JClass, JLongArray, JObject, JString, ReleaseMode,
|
||||
@ -49,6 +50,28 @@ pub type JavaUUID<'a> = JObject<'a>;
|
||||
pub type JavaCiphertextMessage<'a> = JObject<'a>;
|
||||
pub type JavaMap<'a> = JObject<'a>;
|
||||
|
||||
#[derive(Default)]
|
||||
#[repr(transparent)] // This ensures that JavaFuture has the same representation as JObject.
|
||||
pub struct JavaFuture<'a, T> {
|
||||
future_object: JObject<'a>,
|
||||
result: PhantomData<fn(T)>,
|
||||
}
|
||||
|
||||
impl<'a, T> From<JObject<'a>> for JavaFuture<'a, T> {
|
||||
fn from(future_object: JObject<'a>) -> Self {
|
||||
Self {
|
||||
future_object,
|
||||
result: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> From<JavaFuture<'a, T>> for JObject<'a> {
|
||||
fn from(value: JavaFuture<'a, T>) -> Self {
|
||||
value.future_object
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_to_exception<'a, F>(env: &mut JNIEnv<'a>, error: SignalJniError, consume: F)
|
||||
where
|
||||
F: FnOnce(&mut JNIEnv<'a>, SignalJniResult<JThrowable<'a>>, &dyn Display),
|
||||
|
Loading…
Reference in New Issue
Block a user