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 | |
62 | mod arg; |
63 | mod attr; |
64 | mod member; |
65 | mod method; |
66 | mod new; |
67 | mod pyclass; |
68 | mod pyclass_enum; |
69 | mod pyfunction; |
70 | mod pymethods; |
71 | mod signature; |
72 | mod stub_type; |
73 | mod util; |
74 | |
75 | use arg::*; |
76 | use attr::*; |
77 | use member::*; |
78 | use method::*; |
79 | use new::*; |
80 | use pyclass::*; |
81 | use pyclass_enum::*; |
82 | use pyfunction::*; |
83 | use pymethods::*; |
84 | use signature::*; |
85 | use stub_type::*; |
86 | use util::*; |
87 | |
88 | use proc_macro2::TokenStream as TokenStream2; |
89 | use quote::quote; |
90 | use syn::{parse2, ItemEnum, ItemFn, ItemImpl, ItemStruct, Result}; |
91 | |
92 | pub 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 | |
104 | pub 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 | |
116 | pub 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 | |
127 | pub 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 | |