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//! }
41//! }
42//! ```
43//!
44//! and this submodule responsible for generating such codes from Rust code like
45//!
46//! ```rust
47//! # use pyo3::*;
48//! #[pyclass(mapping, module = "my_module", name = "Placeholder")]
49//! #[derive(Debug, Clone)]
50//! pub struct PyPlaceholder {
51//! #[pyo3(get)]
52//! pub name: String,
53//! #[pyo3(get)]
54//! pub ndim: usize,
55//! #[pyo3(get)]
56//! pub description: Option<String>,
57//! pub custom_latex: Option<String>,
58//! }
59//! ```
60//!
61//! Mechanism
62//! ----------
63//! Code generation will take three steps:
64//!
65//! 1. Parse input [proc_macro2::TokenStream] into corresponding syntax tree component in [syn],
66//! - e.g. [ItemStruct] for `#[pyclass]`, [ItemImpl] for `#[pymethods]`, and so on.
67//! 2. Convert syntax tree components into `*Info` struct using [TryInto].
68//! - e.g. [PyClassInfo] is converted from [ItemStruct], [PyMethodsInfo] is converted from [ItemImpl], and so on.
69//! 3. Generate token streams using implementation of [quote::ToTokens] trait for `*Info` structs.
70//! - [quote::quote!] macro uses this trait.
71//!
72
73mod arg;
74mod attr;
75mod member;
76mod method;
77mod pyclass;
78mod pyclass_complex_enum;
79mod pyclass_enum;
80mod pyfunction;
81mod pymethods;
82mod renaming;
83mod signature;
84mod stub_type;
85mod util;
86mod variant;
87
88use arg::*;
89use attr::*;
90use member::*;
91use method::*;
92use pyclass::*;
93use pyclass_complex_enum::*;
94use pyclass_enum::*;
95use pyfunction::*;
96use pymethods::*;
97use renaming::*;
98use signature::*;
99use stub_type::*;
100use util::*;
101
102use proc_macro2::TokenStream as TokenStream2;
103use quote::quote;
104use syn::{parse2, ItemEnum, ItemFn, ItemImpl, ItemStruct, Result};
105
106pub fn pyclass(item: TokenStream2) -> Result<TokenStream2> {
107 let mut item_struct = parse2::<ItemStruct>(item)?;
108 let inner = PyClassInfo::try_from(item_struct.clone())?;
109 let derive_stub_type = StubType::from(&inner);
110 pyclass::prune_attrs(&mut item_struct);
111 Ok(quote! {
112 #item_struct
113 #derive_stub_type
114 pyo3_stub_gen::inventory::submit! {
115 #inner
116 }
117 })
118}
119
120pub fn pyclass_enum(item: TokenStream2) -> Result<TokenStream2> {
121 let inner = PyEnumInfo::try_from(parse2::<ItemEnum>(item.clone())?)?;
122 let derive_stub_type = StubType::from(&inner);
123 Ok(quote! {
124 #item
125 #derive_stub_type
126 pyo3_stub_gen::inventory::submit! {
127 #inner
128 }
129 })
130}
131
132pub fn pyclass_complex_enum(item: TokenStream2) -> Result<TokenStream2> {
133 let inner = PyComplexEnumInfo::try_from(parse2::<ItemEnum>(item.clone())?)?;
134 let derive_stub_type = StubType::from(&inner);
135 Ok(quote! {
136 #item
137 #derive_stub_type
138 pyo3_stub_gen::inventory::submit! {
139 #inner
140 }
141 })
142}
143
144pub fn pymethods(item: TokenStream2) -> Result<TokenStream2> {
145 let mut item_impl = parse2::<ItemImpl>(item)?;
146 let inner = PyMethodsInfo::try_from(item_impl.clone())?;
147 pymethods::prune_attrs(&mut item_impl);
148 Ok(quote! {
149 #item_impl
150 #[automatically_derived]
151 pyo3_stub_gen::inventory::submit! {
152 #inner
153 }
154 })
155}
156
157pub fn pyfunction(attr: TokenStream2, item: TokenStream2) -> Result<TokenStream2> {
158 let mut item_fn = parse2::<ItemFn>(item)?;
159 let mut inner = PyFunctionInfo::try_from(item_fn.clone())?;
160 inner.parse_attr(attr)?;
161 pyfunction::prune_attrs(&mut item_fn);
162 Ok(quote! {
163 #item_fn
164 #[automatically_derived]
165 pyo3_stub_gen::inventory::submit! {
166 #inner
167 }
168 })
169}