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