pyo3_stub_gen_derive/gen_stub/
member.rs

1use super::{escape_return_type, parse_pyo3_attrs, Attr};
2
3use proc_macro2::TokenStream as TokenStream2;
4use quote::{quote, ToTokens, TokenStreamExt};
5use syn::{Error, Field, ImplItemFn, Result, Type};
6
7#[derive(Debug)]
8pub struct MemberInfo {
9    name: String,
10    r#type: Type,
11}
12
13impl MemberInfo {
14    pub fn is_candidate_item(item: &ImplItemFn) -> Result<bool> {
15        let attrs = parse_pyo3_attrs(&item.attrs)?;
16        Ok(attrs.iter().any(|attr| matches!(attr, Attr::Getter(_))))
17    }
18
19    pub fn is_candidate_field(field: &Field) -> Result<bool> {
20        let Field { attrs, .. } = field;
21        Ok(parse_pyo3_attrs(attrs)?
22            .iter()
23            .any(|attr| matches!(attr, Attr::Get)))
24    }
25}
26
27impl TryFrom<ImplItemFn> for MemberInfo {
28    type Error = Error;
29    fn try_from(item: ImplItemFn) -> Result<Self> {
30        assert!(Self::is_candidate_item(&item)?);
31        let ImplItemFn { attrs, sig, .. } = &item;
32        let attrs = parse_pyo3_attrs(attrs)?;
33        for attr in attrs {
34            if let Attr::Getter(name) = attr {
35                return Ok(MemberInfo {
36                    name: name.unwrap_or(sig.ident.to_string()),
37                    r#type: escape_return_type(&sig.output).expect("Getter must return a type"),
38                });
39            }
40        }
41        unreachable!("Not a getter: {:?}", item)
42    }
43}
44
45impl TryFrom<Field> for MemberInfo {
46    type Error = Error;
47    fn try_from(field: Field) -> Result<Self> {
48        let Field {
49            ident, ty, attrs, ..
50        } = field;
51        let mut field_name = None;
52        for attr in parse_pyo3_attrs(&attrs)? {
53            if let Attr::Name(name) = attr {
54                field_name = Some(name);
55            }
56        }
57        Ok(Self {
58            name: field_name.unwrap_or(ident.unwrap().to_string()),
59            r#type: ty,
60        })
61    }
62}
63
64impl ToTokens for MemberInfo {
65    fn to_tokens(&self, tokens: &mut TokenStream2) {
66        let Self { name, r#type: ty } = self;
67        let name = name.strip_prefix("get_").unwrap_or(name);
68        tokens.append_all(quote! {
69            ::pyo3_stub_gen::type_info::MemberInfo {
70                name: #name,
71                r#type: <#ty as ::pyo3_stub_gen::PyStubType>::type_output
72            }
73        })
74    }
75}