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