feat: handle more complex return types

This commit is contained in:
əlemi 2024-10-12 22:25:57 +02:00
parent 1775ea2adf
commit 78713a1b4e
Signed by: alemi
GPG key ID: A4895B84D311642C
4 changed files with 29 additions and 24 deletions

View file

@ -2,6 +2,8 @@ use proc_macro2::{Span, TokenStream};
use quote::TokenStreamExt; use quote::TokenStreamExt;
use syn::Ident; use syn::Ident;
use crate::ext::bare_type;
pub(crate) struct ArgumentOptions { pub(crate) struct ArgumentOptions {
pub(crate) incoming: TokenStream, pub(crate) incoming: TokenStream,
pub(crate) transforming: TokenStream, pub(crate) transforming: TokenStream,
@ -22,27 +24,6 @@ fn unpack_pat(pat: syn::Pat) -> Result<TokenStream, syn::Error> {
} }
} }
fn bare_type(ty: Box<syn::Type>) -> Option<syn::TypePath> {
match *ty {
syn::Type::Array(a) => bare_type(a.elem),
syn::Type::BareFn(_) => None,
syn::Type::ImplTrait(_) => None,
syn::Type::Infer(_) => None,
syn::Type::Macro(_) => None,
syn::Type::Never(_) => None,
syn::Type::TraitObject(_) => None,
syn::Type::Verbatim(_) => None,
syn::Type::Ptr(p) => bare_type(p.elem),
syn::Type::Slice(s) => bare_type(s.elem),
syn::Type::Tuple(t) => bare_type(Box::new(t.elems.first()?.clone())), // TODO
syn::Type::Group(g) => bare_type(g.elem),
syn::Type::Paren(p) => bare_type(p.elem),
syn::Type::Reference(r) => bare_type(r.elem),
syn::Type::Path(ty) => Some(ty),
_ => todo!(),
}
}
fn type_equals(ty: Box<syn::Type>, search: impl AsRef<str>) -> bool { fn type_equals(ty: Box<syn::Type>, search: impl AsRef<str>) -> bool {
let Some(ty) = bare_type(ty) else { return false }; let Some(ty) = bare_type(ty) else { return false };
let Some(last) = ty.path.segments.last() else { return false }; let Some(last) = ty.path.segments.last() else { return false };

21
macro/src/ext.rs Normal file
View file

@ -0,0 +1,21 @@
pub(crate) fn bare_type(ty: Box<syn::Type>) -> Option<syn::TypePath> {
match *ty {
syn::Type::Array(a) => bare_type(a.elem),
syn::Type::BareFn(_) => None,
syn::Type::ImplTrait(_) => None,
syn::Type::Infer(_) => None,
syn::Type::Macro(_) => None,
syn::Type::Never(_) => None,
syn::Type::TraitObject(_) => None,
syn::Type::Verbatim(_) => None,
syn::Type::Ptr(p) => bare_type(p.elem),
syn::Type::Slice(s) => bare_type(s.elem),
syn::Type::Tuple(t) => bare_type(Box::new(t.elems.first()?.clone())), // TODO
syn::Type::Group(g) => bare_type(g.elem),
syn::Type::Paren(p) => bare_type(p.elem),
syn::Type::Reference(r) => bare_type(r.elem),
syn::Type::Path(ty) => Some(ty),
_ => todo!(),
}
}

View file

@ -2,6 +2,7 @@ mod attrs;
mod wrapper; mod wrapper;
mod args; mod args;
mod ret; mod ret;
mod ext;
/// Wrap this function in in a JNI exported fn. /// Wrap this function in in a JNI exported fn.
#[proc_macro_attribute] #[proc_macro_attribute]

View file

@ -2,6 +2,8 @@ use proc_macro2::{Span, TokenStream};
use quote::ToTokens; use quote::ToTokens;
use syn::{ReturnType, Type}; use syn::{ReturnType, Type};
use crate::ext::bare_type;
#[derive(Clone)] #[derive(Clone)]
pub(crate) struct ReturnOptions { pub(crate) struct ReturnOptions {
pub(crate) ty: Option<Box<Type>>, pub(crate) ty: Option<Box<Type>>,
@ -16,8 +18,8 @@ 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, void: true, pointer: false }), syn::ReturnType::Default => Ok(Self { ty: None, result: false, void: true, pointer: false }),
syn::ReturnType::Type(_tok, ty) => match *ty.clone() { syn::ReturnType::Type(_tok, ty) => match bare_type(ty.clone()) {
syn::Type::Path(path) => { Some(path) => {
let Some(last) = path.path.segments.last() else { let Some(last) = path.path.segments.last() else {
return Err(syn::Error::new(Span::call_site(), "empty Result type is not valid")); return Err(syn::Error::new(Span::call_site(), "empty Result type is not valid"));
}; };
@ -43,7 +45,7 @@ impl ReturnOptions {
let pointer = !PRIMITIVE_TYPES.iter().any(|t| last.ident == t); let pointer = !PRIMITIVE_TYPES.iter().any(|t| last.ident == t);
Ok(Self { ty: Some(Box::new(Type::Path(path.clone()))), result: false, void: false, pointer }) Ok(Self { ty: Some(Box::new(Type::Path(path.clone()))), result: false, void: false, pointer })
}, },
_ => Err(syn::Error::new(Span::call_site(), "unsupported return type")), None => Err(syn::Error::new(Span::call_site(), "unsupported return type")),
}, },
} }
} }