| 1 | use proc_macro2::TokenStream as TokenStream2; |
| 2 | use quote::{quote, ToTokens, TokenStreamExt}; |
| 3 | use syn::{ |
| 4 | parse::{Parse, ParseStream}, |
| 5 | Error, ItemFn, Result, Type, |
| 6 | }; |
| 7 | |
| 8 | use super::{ |
| 9 | escape_return_type, extract_documents, parse_args, parse_pyo3_attrs, quote_option, ArgInfo, |
| 10 | ArgsWithSignature, Attr, Signature, |
| 11 | }; |
| 12 | |
| 13 | pub struct PyFunctionInfo { |
| 14 | name: String, |
| 15 | args: Vec<ArgInfo>, |
| 16 | r#return: Option<Type>, |
| 17 | sig: Option<Signature>, |
| 18 | doc: String, |
| 19 | module: Option<String>, |
| 20 | } |
| 21 | |
| 22 | struct ModuleAttr { |
| 23 | _module: syn::Ident, |
| 24 | _eq_token: syn::token::Eq, |
| 25 | name: syn::LitStr, |
| 26 | } |
| 27 | |
| 28 | impl Parse for ModuleAttr { |
| 29 | fn parse(input: ParseStream) -> Result<Self> { |
| 30 | Ok(Self { |
| 31 | _module: input.parse()?, |
| 32 | _eq_token: input.parse()?, |
| 33 | name: input.parse()?, |
| 34 | }) |
| 35 | } |
| 36 | } |
| 37 | |
| 38 | impl PyFunctionInfo { |
| 39 | pub fn parse_attr(&mut self, attr: TokenStream2) -> Result<()> { |
| 40 | if attr.is_empty() { |
| 41 | return Ok(()); |
| 42 | } |
| 43 | let attr: ModuleAttr = syn::parse2(tokens:attr)?; |
| 44 | self.module = Some(attr.name.value()); |
| 45 | Ok(()) |
| 46 | } |
| 47 | } |
| 48 | |
| 49 | impl TryFrom<ItemFn> for PyFunctionInfo { |
| 50 | type Error = Error; |
| 51 | fn try_from(item: ItemFn) -> Result<Self> { |
| 52 | let doc = extract_documents(&item.attrs).join(" \n" ); |
| 53 | let args = parse_args(item.sig.inputs)?; |
| 54 | let r#return = escape_return_type(&item.sig.output); |
| 55 | let mut name = None; |
| 56 | let mut sig = None; |
| 57 | for attr in parse_pyo3_attrs(&item.attrs)? { |
| 58 | match attr { |
| 59 | Attr::Name(function_name) => name = Some(function_name), |
| 60 | Attr::Signature(signature) => sig = Some(signature), |
| 61 | _ => {} |
| 62 | } |
| 63 | } |
| 64 | let name = name.unwrap_or_else(|| item.sig.ident.to_string()); |
| 65 | Ok(Self { |
| 66 | args, |
| 67 | sig, |
| 68 | r#return, |
| 69 | name, |
| 70 | doc, |
| 71 | module: None, |
| 72 | }) |
| 73 | } |
| 74 | } |
| 75 | |
| 76 | impl ToTokens for PyFunctionInfo { |
| 77 | fn to_tokens(&self, tokens: &mut TokenStream2) { |
| 78 | let Self { |
| 79 | args, |
| 80 | r#return: ret, |
| 81 | name, |
| 82 | doc, |
| 83 | sig, |
| 84 | module, |
| 85 | } = self; |
| 86 | let ret_tt = if let Some(ret) = ret { |
| 87 | quote! { <#ret as pyo3_stub_gen::PyStubType>::type_output } |
| 88 | } else { |
| 89 | quote! { ::pyo3_stub_gen::type_info::no_return_type_output } |
| 90 | }; |
| 91 | // let sig_tt = quote_option(sig); |
| 92 | let module_tt = quote_option(module); |
| 93 | let args_with_sig = ArgsWithSignature { args, sig }; |
| 94 | tokens.append_all(quote! { |
| 95 | ::pyo3_stub_gen::type_info::PyFunctionInfo { |
| 96 | name: #name, |
| 97 | args: #args_with_sig, |
| 98 | r#return: #ret_tt, |
| 99 | doc: #doc, |
| 100 | module: #module_tt, |
| 101 | } |
| 102 | }) |
| 103 | } |
| 104 | } |
| 105 | |