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