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