refactor: improve android_fn! lifetime support (#780)

* refactor: improve android_fn! lifetime support

* take ownership in setup function

* Update tao-macros/src/lib.rs

Co-authored-by: Lucas Fernandes Nogueira <lucas@tauri.studio>

---------

Co-authored-by: Lucas Fernandes Nogueira <lucas@tauri.studio>
This commit is contained in:
Amr Bashir
2023-08-11 15:33:47 +03:00
committed by GitHub
parent 448ec06c0f
commit 2295f0b3aa
3 changed files with 85 additions and 30 deletions

View File

@@ -749,7 +749,7 @@ impl MonitorHandle {
.l()
.unwrap();
let rect = env
.call_method(metrics, "getBounds", "()Landroid/graphics/Rect;", &[])
.call_method(&metrics, "getBounds", "()Landroid/graphics/Rect;", &[])
.unwrap()
.l()
.unwrap();
@@ -759,7 +759,7 @@ impl MonitorHandle {
.i()
.unwrap();
let height = env
.call_method(rect, "height", "()I", &[])
.call_method(&rect, "height", "()I", &[])
.unwrap()
.i()
.unwrap();

View File

@@ -1,7 +1,14 @@
use std::marker::PhantomData;
use tao_macros::android_fn;
struct JNIEnv;
struct JClass;
struct JNIEnv<'a> {
_marker: &'a PhantomData<()>,
}
#[repr(C)]
struct JClass<'a> {
_marker: &'a PhantomData<()>,
}
android_fn![com_example, tao_app, SomeClass, add, []];
unsafe fn add(_env: JNIEnv, _class: JClass) {}
@@ -53,15 +60,21 @@ unsafe fn add8(_env: JNIEnv, _class: JClass, _a: i32, _b: i32) -> i32 {
0
}
android_fn!(
android_fn![
com_example,
tao_app,
SomeClass,
add9,
[i32, i32],
__VOID__,
[],
);
unsafe fn add9(_env: JNIEnv, _class: JClass, _a: i32, _b: i32) {}
add10,
[JClass<'local>, i32],
JClass<'local>
];
unsafe fn add10<'local>(
_env: JNIEnv<'local>,
_class: JClass<'local>,
a: JClass<'local>,
_b: i32,
) -> JClass<'local> {
a
}
fn main() {}

View File

@@ -99,19 +99,24 @@ impl Parse for AndroidFnInput {
/// 3. Java/Kotlin class name.
/// 4. Rust function name (`ident`).
/// 5. List of extra types your Rust function expects. Pass empty array if the function doesn't need any arugments.
/// - If your function takes an arguments as reference with a lifetime tied to the [`JNIEnv`], it should use `'local` as the lifetime name as it is the
/// lifetime name generated by the macro.
/// Note that all rust functions should expect the first two parameters to be [`JNIEnv`] and [`JClass`] so make sure they are imported into scope).
/// 6. (Optional) Return type of your rust function.
/// if you want to use the next parameter you need to provide a type or just pass `__VOID__` if the function doesn't return anything.
/// 7. (Optional) List of `ident`s to pass to the rust function when invoked (This mostly exists for internal usages).
/// 8. (Optional) Function to be invoked right before invoking the rust function (This mostly exists for internal usages).
/// - If your function returns a reference with a lifetime tied to the [`JNIEnv`], it should use `'local` as the lifetime name as it is the
/// lifetime name generated by the macro.
/// - if you want to use the next macro parameter you need to provide a type or just pass `__VOID__` if the function doesn't return anything.
/// 7. (Optional) List of `ident`s to pass to the rust function when invoked (This mostly exists for internal usage by `tao` crate).
/// 8. (Optional) Function to be invoked right before invoking the rust function (This mostly exists for internal usage by `tao` crate).
///
/// ## Example
/// ## Example 1: Basic
///
/// ```
/// # use tao_macros::android_fn;
/// # struct JNIEnv;
/// # struct JClass;
///
/// # struct JNIEnv<'a> {
/// # _marker: &'a std::marker::PhantomData<()>,
/// # }
/// # type JClass<'a> = JNIEnv<'a>;
/// android_fn![com_example, tao, OperationsClass, add, [i32, i32], i32];
/// unsafe fn add(_env: JNIEnv, _class: JClass, a: i32, b: i32) -> i32 {
/// a + b
@@ -119,19 +124,21 @@ impl Parse for AndroidFnInput {
/// ```
/// which will expand into:
/// ```
/// # struct JNIEnv;
/// # struct JClass;
/// # struct JNIEnv<'a> {
/// # _marker: &'a std::marker::PhantomData<()>,
/// # }
/// # type JClass<'a> = JNIEnv<'a>;
/// #[no_mangle]
/// unsafe extern "C" fn Java_com_example_tao_OperationsClass_add(
/// env: JNIEnv,
/// class: JClass,
/// unsafe extern "C" fn Java_com_example_tao_OperationsClass_add<'local>(
/// env: JNIEnv<'local>,
/// class: JClass<'local>,
/// a_1: i32,
/// a_2: i32
/// ) -> i32 {
/// add(env, class, a_1, a_2)
/// }
///
/// unsafe fn add(_env: JNIEnv, _class: JClass, a: i32, b: i32) -> i32 {
/// unsafe fn add<'local>(_env: JNIEnv<'local>, _class: JClass<'local>, a: i32, b: i32) -> i32 {
/// a + b
/// }
/// ```
@@ -143,6 +150,41 @@ impl Parse for AndroidFnInput {
/// }
/// ```
///
/// ## Example 2: Return a reference with a lifetime
///
/// ```
/// # use tao_macros::android_fn;
/// # struct JNIEnv<'a> {
/// # _marker: &'a std::marker::PhantomData<()>,
/// # }
/// # type JClass<'a> = JNIEnv<'a>;
/// # type JObject<'a> = JNIEnv<'a>;
/// android_fn![com_example, tao, OperationsClass, add, [JObject<'local>], JClass<'local>];
/// unsafe fn add<'local>(mut _env: JNIEnv<'local>, class: JClass<'local>, obj: JObject<'local>) -> JClass<'local> {
/// class
/// }
/// ```
/// which will expand into:
/// ```
/// # struct JNIEnv<'a> {
/// # _marker: &'a std::marker::PhantomData<()>,
/// # }
/// # type JClass<'a> = JNIEnv<'a>;
/// # type JObject<'a> = JNIEnv<'a>;
/// #[no_mangle]
/// unsafe extern "C" fn Java_com_example_tao_OperationsClass_add<'local>(
/// env: JNIEnv<'local>,
/// class: JClass<'local>,
/// a_1: JObject<'local>,
/// ) -> JClass<'local> {
/// add(env, class, a_1)
/// }
///
/// unsafe fn add<'local>(mut _env: JNIEnv<'local>, class: JClass<'local>, obj: JObject<'local>) -> JClass<'local> {
/// class
/// }
/// ```
///
/// - [`JNIEnv`]: https://docs.rs/jni/latest/jni/struct.JNIEnv.html
/// - [`JClass`]: https://docs.rs/jni/latest/jni/objects/struct.JClass.html
#[proc_macro]
@@ -160,7 +202,7 @@ pub fn android_fn(tokens: TokenStream) -> TokenStream {
} = tokens;
let domain = domain.to_string();
let package = package.to_string().replace("_", "_1").replace("-", "_1");
let package = package.to_string().replace('_', "_1").replace('-', "_1");
let class = class.to_string();
let args = args
.into_iter()
@@ -196,9 +238,9 @@ pub fn android_fn(tokens: TokenStream) -> TokenStream {
quote! {
#[no_mangle]
unsafe extern "C" fn #java_fn_name(
env: JNIEnv,
class: JClass,
unsafe extern "C" fn #java_fn_name<'local>(
env: JNIEnv<'local>,
class: JClass<'local>,
#(#args),*
) #ret {
#function_before();
@@ -253,8 +295,8 @@ pub fn generate_package_name(tokens: TokenStream) -> TokenStream {
let tokens = parse_macro_input!(tokens as GeneratePackageNameInput);
let GeneratePackageNameInput { domain, package } = tokens;
let domain = domain.to_string().replace("_", "/");
let package = package.to_string().replace("-", "_");
let domain = domain.to_string().replace('_', "/");
let package = package.to_string().replace('-', "_");
let path = format!("{}/{}", domain, package);
let litstr = LitStr::new(&path, proc_macro2::Span::call_site());