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