2024-09-21 20:46:48 +02:00
|
|
|
use proc_macro2::{Span, TokenStream};
|
|
|
|
use quote::ToTokens;
|
|
|
|
use syn::{ReturnType, Type};
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub(crate) struct ReturnOptions {
|
|
|
|
pub(crate) ty: Option<Box<Type>>,
|
|
|
|
pub(crate) result: bool,
|
2024-09-22 01:37:28 +02:00
|
|
|
pub(crate) void: bool,
|
2024-09-21 20:46:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ReturnOptions {
|
2024-09-21 23:03:02 +02:00
|
|
|
pub(crate) fn parse_signature(ret: &ReturnType) -> Result<Self, syn::Error> {
|
2024-09-21 20:46:48 +02:00
|
|
|
match ret {
|
2024-09-22 01:37:28 +02:00
|
|
|
syn::ReturnType::Default => Ok(Self { ty: None, result: false, void: true }),
|
2024-09-21 23:03:02 +02:00
|
|
|
syn::ReturnType::Type(_tok, ty) => match *ty.clone() {
|
|
|
|
syn::Type::Path(path) => {
|
2024-09-21 20:46:48 +02:00
|
|
|
let Some(last) = path.path.segments.last() else {
|
|
|
|
return Err(syn::Error::new(Span::call_site(), "empty Result type is not valid"));
|
|
|
|
};
|
|
|
|
|
|
|
|
if last.ident == "Result" {
|
|
|
|
match &last.arguments {
|
|
|
|
syn::PathArguments::None => return Err(syn::Error::new(Span::call_site(), "Result without generics is not valid")),
|
|
|
|
syn::PathArguments::Parenthesized(_) => return Err(syn::Error::new(Span::call_site(), "Parenthesized Result is not valid")),
|
|
|
|
syn::PathArguments::AngleBracketed(ref generics) => for generic in generics.args.iter() {
|
|
|
|
match generic {
|
|
|
|
syn::GenericArgument::Lifetime(_) => continue,
|
2024-09-22 01:37:28 +02:00
|
|
|
syn::GenericArgument::Type(ty) => return Ok(Self { ty: Some(Box::new(ty.clone())), result: true, void: is_void(ty) }),
|
2024-09-21 20:46:48 +02:00
|
|
|
_ => return Err(syn::Error::new(Span::call_site(), "unexpected type in Result")),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-22 01:37:28 +02:00
|
|
|
Ok(Self { ty: Some(Box::new(Type::Path(path.clone()))), result: false, void: false })
|
2024-09-21 20:46:48 +02:00
|
|
|
},
|
|
|
|
_ => Err(syn::Error::new(Span::call_site(), "unsupported return type")),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-21 23:03:02 +02:00
|
|
|
pub(crate) fn tokens(&self) -> TokenStream {
|
|
|
|
match &self.ty { // TODO why do we need to invoke syn::Token! macro ???
|
2024-09-21 20:46:48 +02:00
|
|
|
None => ReturnType::Default.to_token_stream(),
|
2024-09-23 00:23:42 +02:00
|
|
|
Some(t) => {
|
|
|
|
if t.to_token_stream().to_string() == "bool" {// TODO: there DEFINITELY is a better way
|
|
|
|
quote::quote!( -> jni::sys::jboolean )
|
|
|
|
} else {
|
|
|
|
quote::quote!( -> <#t as jni_toolbox::IntoJavaRaw>::T )
|
|
|
|
}
|
|
|
|
}
|
2024-09-21 20:46:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-09-22 01:37:28 +02:00
|
|
|
|
|
|
|
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!(),
|
|
|
|
}
|
|
|
|
}
|