pyo3_stub_gen_derive/
gen_stub.rs

1//! Code generation for embedding metadata for generating Python stub file.
2//!
3//! These metadata are embedded as `inventory::submit!` block like:
4//!
5//! ```rust
6//! # use pyo3::*;
7//! # use pyo3_stub_gen::type_info::*;
8//! # struct PyPlaceholder;
9//! inventory::submit!{
10//!     PyClassInfo {
11//!         pyclass_name: "Placeholder",
12//!         module: Some("my_module"),
13//!         struct_id: std::any::TypeId::of::<PyPlaceholder>,
14//!         getters: &[
15//!             MemberInfo {
16//!                 name: "name",
17//!                 r#type: <String as ::pyo3_stub_gen::PyStubType>::type_output,
18//!                 doc: "",
19//!                 default: None,
20//!                 deprecated: None,
21//!             },
22//!             MemberInfo {
23//!                 name: "ndim",
24//!                 r#type: <usize as ::pyo3_stub_gen::PyStubType>::type_output,
25//!                 doc: "",
26//!                 default: None,
27//!                 deprecated: None,
28//!             },
29//!             MemberInfo {
30//!                 name: "description",
31//!                 r#type: <Option<String> as ::pyo3_stub_gen::PyStubType>::type_output,
32//!                 doc: "",
33//!                 default: None,
34//!                 deprecated: None,
35//!             },
36//!         ],
37//!         setters: &[],
38//!         doc: "",
39//!         bases: &[],
40//!         has_eq: false,
41//!         has_ord: false,
42//!         has_hash: false,
43//!         has_str: false,
44//!     }
45//! }
46//! ```
47//!
48//! and this submodule responsible for generating such codes from Rust code like
49//!
50//! ```rust
51//! # use pyo3::*;
52//! #[pyclass(mapping, module = "my_module", name = "Placeholder")]
53//! #[derive(Debug, Clone)]
54//! pub struct PyPlaceholder {
55//!     #[pyo3(get)]
56//!     pub name: String,
57//!     #[pyo3(get)]
58//!     pub ndim: usize,
59//!     #[pyo3(get)]
60//!     pub description: Option<String>,
61//!     pub custom_latex: Option<String>,
62//! }
63//! ```
64//!
65//! Mechanism
66//! ----------
67//! Code generation will take three steps:
68//!
69//! 1. Parse input [proc_macro2::TokenStream] into corresponding syntax tree component in [syn],
70//!    - e.g. [ItemStruct] for `#[pyclass]`, [ItemImpl] for `#[pymethods]`, and so on.
71//! 2. Convert syntax tree components into `*Info` struct using [TryInto].
72//!    - e.g. [PyClassInfo] is converted from [ItemStruct], [PyMethodsInfo] is converted from [ItemImpl], and so on.
73//! 3. Generate token streams using implementation of [quote::ToTokens] trait for `*Info` structs.
74//!    - [quote::quote!] macro uses this trait.
75//!
76
77mod arg;
78mod attr;
79mod member;
80mod method;
81mod pyclass;
82mod pyclass_complex_enum;
83mod pyclass_enum;
84mod pyfunction;
85mod pymethods;
86mod renaming;
87mod signature;
88mod stub_type;
89mod util;
90mod variant;
91
92use arg::*;
93use attr::*;
94use member::*;
95use method::*;
96use pyclass::*;
97use pyclass_complex_enum::*;
98use pyclass_enum::*;
99use pyfunction::*;
100use pymethods::*;
101use renaming::*;
102use signature::*;
103use stub_type::*;
104use util::*;
105
106use proc_macro2::TokenStream as TokenStream2;
107use quote::quote;
108use syn::{parse2, ItemEnum, ItemFn, ItemImpl, ItemStruct, Result};
109
110pub fn pyclass(item: TokenStream2) -> Result<TokenStream2> {
111    let mut item_struct = parse2::<ItemStruct>(item)?;
112    let inner = PyClassInfo::try_from(item_struct.clone())?;
113    let derive_stub_type = StubType::from(&inner);
114    pyclass::prune_attrs(&mut item_struct);
115    Ok(quote! {
116        #item_struct
117        #derive_stub_type
118        pyo3_stub_gen::inventory::submit! {
119            #inner
120        }
121    })
122}
123
124pub fn pyclass_enum(item: TokenStream2) -> Result<TokenStream2> {
125    let inner = PyEnumInfo::try_from(parse2::<ItemEnum>(item.clone())?)?;
126    let derive_stub_type = StubType::from(&inner);
127    Ok(quote! {
128        #item
129        #derive_stub_type
130        pyo3_stub_gen::inventory::submit! {
131            #inner
132        }
133    })
134}
135
136pub fn pyclass_complex_enum(item: TokenStream2) -> Result<TokenStream2> {
137    let inner = PyComplexEnumInfo::try_from(parse2::<ItemEnum>(item.clone())?)?;
138    let derive_stub_type = StubType::from(&inner);
139    Ok(quote! {
140        #item
141        #derive_stub_type
142        pyo3_stub_gen::inventory::submit! {
143            #inner
144        }
145    })
146}
147
148pub fn pymethods(item: TokenStream2) -> Result<TokenStream2> {
149    let mut item_impl = parse2::<ItemImpl>(item)?;
150    let inner = PyMethodsInfo::try_from(item_impl.clone())?;
151    pymethods::prune_attrs(&mut item_impl);
152    Ok(quote! {
153        #item_impl
154        #[automatically_derived]
155        pyo3_stub_gen::inventory::submit! {
156            #inner
157        }
158    })
159}
160
161pub fn pyfunction(attr: TokenStream2, item: TokenStream2) -> Result<TokenStream2> {
162    let mut item_fn = parse2::<ItemFn>(item)?;
163    let mut inner = PyFunctionInfo::try_from(item_fn.clone())?;
164    inner.parse_attr(attr)?;
165    pyfunction::prune_attrs(&mut item_fn);
166    Ok(quote! {
167        #item_fn
168        #[automatically_derived]
169        pyo3_stub_gen::inventory::submit! {
170            #inner
171        }
172    })
173}