pyo3_stub_gen_derive/gen_stub/
member.rs

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