fix: return type void in result

This commit is contained in:
əlemi 2024-09-22 01:37:28 +02:00
parent 3a09386878
commit 1d00db2648
Signed by: alemi
GPG key ID: A4895B84D311642C
2 changed files with 46 additions and 10 deletions

View file

@ -6,12 +6,13 @@ use syn::{ReturnType, Type};
pub(crate) struct ReturnOptions { pub(crate) struct ReturnOptions {
pub(crate) ty: Option<Box<Type>>, pub(crate) ty: Option<Box<Type>>,
pub(crate) result: bool, pub(crate) result: bool,
pub(crate) void: bool,
} }
impl ReturnOptions { impl ReturnOptions {
pub(crate) fn parse_signature(ret: &ReturnType) -> Result<Self, syn::Error> { pub(crate) fn parse_signature(ret: &ReturnType) -> Result<Self, syn::Error> {
match ret { 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::ReturnType::Type(_tok, ty) => match *ty.clone() {
syn::Type::Path(path) => { syn::Type::Path(path) => {
let Some(last) = path.path.segments.last() else { 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() { syn::PathArguments::AngleBracketed(ref generics) => for generic in generics.args.iter() {
match generic { match generic {
syn::GenericArgument::Lifetime(_) => continue, 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")), _ => 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")), _ => Err(syn::Error::new(Span::call_site(), "unsupported return type")),
}, },
@ -41,8 +42,29 @@ impl ReturnOptions {
pub(crate) fn tokens(&self) -> TokenStream { pub(crate) fn tokens(&self) -> TokenStream {
match &self.ty { // TODO why do we need to invoke syn::Token! macro ??? 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(), 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!(),
}
}

View file

@ -13,7 +13,7 @@ pub(crate) fn generate_jni_wrapper(attrs: TokenStream, input: TokenStream) -> Re
let attrs = AttrsOptions::parse_attr(attrs)?; let attrs = AttrsOptions::parse_attr(attrs)?;
let ret = ReturnOptions::parse_signature(&fn_item.sig.output)?; 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!( () ) quote::quote!( () )
} else if attrs.return_pointer { } else if attrs.return_pointer {
quote::quote!( std::ptr::null_mut() ) quote::quote!( std::ptr::null_mut() )
@ -49,7 +49,7 @@ pub(crate) fn generate_jni_wrapper(attrs: TokenStream, input: TokenStream) -> Re
// V----------------------------------V // V----------------------------------V
quote::quote! { quote::quote! {
{ {
use jni_toolbox::{JniToolboxError, FromJava}; use jni_toolbox::{JniToolboxError, FromJava, IntoJava};
#transforming #transforming
match #fn_name_inner(#forwarding) { match #fn_name_inner(#forwarding) {
Ok(ret) => ret, Ok(ret) => ret,
@ -65,7 +65,7 @@ pub(crate) fn generate_jni_wrapper(attrs: TokenStream, input: TokenStream) -> Re
// V----------------------------------V // V----------------------------------V
quote::quote! { 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 // 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 // way to get it back from the called function and thus resort to unsafe cloning
let mut env_copy = unsafe { #env_ident.unsafe_clone() }; 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 // V----------------------------------V
quote::quote! { quote::quote! {
{ {
use jni_toolbox::{JniToolboxError, FromJava}; use jni_toolbox::{JniToolboxError, FromJava, IntoJava};
#transforming #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;
},
}
} }
} }
// ^----------------------------------^ // ^----------------------------------^