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}