pyo3_stub_gen_derive/gen_stub/
member.rs1use 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}