From 1d00db264828a51649f4bf0949caffb930efd356 Mon Sep 17 00:00:00 2001 From: alemi Date: Sun, 22 Sep 2024 01:37:28 +0200 Subject: [PATCH] fix: return type void in result --- macro/src/ret.rs | 30 ++++++++++++++++++++++++++---- macro/src/wrapper.rs | 26 ++++++++++++++++++++------ 2 files changed, 46 insertions(+), 10 deletions(-) diff --git a/macro/src/ret.rs b/macro/src/ret.rs index 6605d2e..f642fe2 100644 --- a/macro/src/ret.rs +++ b/macro/src/ret.rs @@ -6,12 +6,13 @@ use syn::{ReturnType, Type}; pub(crate) struct ReturnOptions { pub(crate) ty: Option>, pub(crate) result: bool, + pub(crate) void: bool, } impl ReturnOptions { pub(crate) fn parse_signature(ret: &ReturnType) -> Result { match ret { - syn::ReturnType::Default => Ok(Self { ty: None, result: false }), + syn::ReturnType::Default => Ok(Self { ty: None, result: false, void: true }), syn::ReturnType::Type(_tok, ty) => match *ty.clone() { syn::Type::Path(path) => { let Some(last) = path.path.segments.last() else { @@ -25,14 +26,14 @@ impl ReturnOptions { syn::PathArguments::AngleBracketed(ref generics) => for generic in generics.args.iter() { match generic { syn::GenericArgument::Lifetime(_) => continue, - syn::GenericArgument::Type(ty) => return Ok(Self { ty: Some(Box::new(ty.clone())), result: true }), + syn::GenericArgument::Type(ty) => return Ok(Self { ty: Some(Box::new(ty.clone())), result: true, void: is_void(ty) }), _ => return Err(syn::Error::new(Span::call_site(), "unexpected type in Result")), } } } } - Ok(Self { ty: Some(Box::new(Type::Path(path.clone()))), result: false }) + Ok(Self { ty: Some(Box::new(Type::Path(path.clone()))), result: false, void: false }) }, _ => Err(syn::Error::new(Span::call_site(), "unsupported return type")), }, @@ -41,8 +42,29 @@ impl ReturnOptions { pub(crate) fn tokens(&self) -> TokenStream { match &self.ty { // TODO why do we need to invoke syn::Token! macro ??? - Some(t) => ReturnType::Type(syn::Token![->](Span::call_site()), t.clone()).to_token_stream(), + Some(t) => quote::quote!( -> <#t as jni_toolbox::IntoJava<'local>>::T ), None => ReturnType::Default.to_token_stream(), } } } + +fn is_void(ty: &syn::Type) -> bool { + match ty { + Type::Array(_) => false, + Type::BareFn(_) => false, + Type::Group(g) => is_void(&g.elem), + Type::ImplTrait(_) => false, + Type::Infer(_) => false, + Type::Macro(_) => false, + Type::Never(_) => true, + Type::Paren(p) => is_void(&p.elem), + Type::Path(p) => p.path.segments.is_empty(), + Type::Ptr(_) => false, + Type::Reference(_) => false, + Type::Slice(_) => false, + Type::TraitObject(_) => false, + Type::Tuple(x) => x.elems.is_empty(), + Type::Verbatim(_) => false, + _ => todo!(), + } +} diff --git a/macro/src/wrapper.rs b/macro/src/wrapper.rs index 2b90a56..5bdaa89 100644 --- a/macro/src/wrapper.rs +++ b/macro/src/wrapper.rs @@ -13,7 +13,7 @@ pub(crate) fn generate_jni_wrapper(attrs: TokenStream, input: TokenStream) -> Re let attrs = AttrsOptions::parse_attr(attrs)?; let ret = ReturnOptions::parse_signature(&fn_item.sig.output)?; - let return_expr = if ret.ty.is_none() { + let return_expr = if ret.void { quote::quote!( () ) } else if attrs.return_pointer { quote::quote!( std::ptr::null_mut() ) @@ -49,7 +49,7 @@ pub(crate) fn generate_jni_wrapper(attrs: TokenStream, input: TokenStream) -> Re // V----------------------------------V quote::quote! { { - use jni_toolbox::{JniToolboxError, FromJava}; + use jni_toolbox::{JniToolboxError, FromJava, IntoJava}; #transforming match #fn_name_inner(#forwarding) { Ok(ret) => ret, @@ -65,7 +65,7 @@ pub(crate) fn generate_jni_wrapper(attrs: TokenStream, input: TokenStream) -> Re // V----------------------------------V quote::quote! { { - use jni_toolbox::{JniToolboxError, FromJava}; + use jni_toolbox::{JniToolboxError, FromJava, IntoJava}; // NOTE: this should be SAFE! the cloned env reference lives less than the actual one, we just lack a // way to get it back from the called function and thus resort to unsafe cloning let mut env_copy = unsafe { #env_ident.unsafe_clone() }; @@ -84,7 +84,14 @@ pub(crate) fn generate_jni_wrapper(attrs: TokenStream, input: TokenStream) -> Re }, }, } - Ok(ret) => ret, + Ok(ret) => match ret.into_java(&mut env_copy) { + Ok(fin) => return fin, + Err(e) => { + // TODO should we panic instead? + let _ = env_copy.throw_new("java/lang/RuntimeException", format!("{e:?}")); + return #return_expr; + } + }, } } } @@ -93,9 +100,16 @@ pub(crate) fn generate_jni_wrapper(attrs: TokenStream, input: TokenStream) -> Re // V----------------------------------V quote::quote! { { - use jni_toolbox::{JniToolboxError, FromJava}; + use jni_toolbox::{JniToolboxError, FromJava, IntoJava}; #transforming - #fn_name_inner(#forwarding) + match #fn_name_inner(#forwarding).into_java(&mut #env_ident) { + Ok(res) => return res, + Err(e) => { + // TODO should we panic instead? + let _ = #env_ident.throw_new("java/lang/RuntimeException", format!("{e:?}")); + return #return_expr; + }, + } } } // ^----------------------------------^