pyo3_derive_backend/
pyimpl.rs

1// Copyright (c) 2017-present PyO3 Project and Contributors
2
3use crate::pymethod;
4use proc_macro2::TokenStream;
5use quote::quote;
6
7pub fn build_py_methods(ast: &mut syn::ItemImpl) -> syn::Result<TokenStream> {
8    if let Some((_, ref path, _)) = ast.trait_ {
9        Err(syn::Error::new_spanned(
10            path,
11            "#[pymethods] cannot be used on trait impl blocks",
12        ))
13    } else if ast.generics != Default::default() {
14        Err(syn::Error::new_spanned(
15            ast.generics.clone(),
16            "#[pymethods] cannot be used with lifetime parameters or generics",
17        ))
18    } else {
19        impl_methods(&ast.self_ty, &mut ast.items)
20    }
21}
22
23pub fn impl_methods(ty: &syn::Type, impls: &mut Vec<syn::ImplItem>) -> syn::Result<TokenStream> {
24    let mut methods = Vec::new();
25    let mut cfg_attributes = Vec::new();
26    for iimpl in impls.iter_mut() {
27        match iimpl {
28            syn::ImplItem::Method(meth) => {
29                methods.push(pymethod::gen_py_method(ty, &mut meth.sig, &mut meth.attrs)?);
30                cfg_attributes.push(get_cfg_attributes(&meth.attrs));
31            }
32            syn::ImplItem::Const(konst) => {
33                if let Some(meth) = pymethod::gen_py_const(ty, &konst.ident, &mut konst.attrs)? {
34                    methods.push(meth);
35                }
36                cfg_attributes.push(get_cfg_attributes(&konst.attrs));
37            }
38            _ => (),
39        }
40    }
41
42    Ok(quote! {
43       pyo3::inventory::submit! {
44            #![crate = pyo3] {
45                type Inventory = <#ty as pyo3::class::methods::HasMethodsInventory>::Methods;
46                <Inventory as pyo3::class::methods::PyMethodsInventory>::new(vec![#(
47                    #(#cfg_attributes)*
48                    #methods
49                ),*])
50            }
51        }
52    })
53}
54
55fn get_cfg_attributes(attrs: &[syn::Attribute]) -> Vec<&syn::Attribute> {
56    attrs
57        .iter()
58        .filter(|attr| attr.path.is_ident("cfg"))
59        .collect()
60}