| 1 | //! Store of metadata for generating Python stub file |
| 2 | //! |
| 3 | //! Stub file generation takes two steps: |
| 4 | //! |
| 5 | //! Store metadata (compile time) |
| 6 | //! ------------------------------ |
| 7 | //! Embed compile-time information about Rust types and PyO3 macro arguments |
| 8 | //! using [inventory::submit!](https://docs.rs/inventory/latest/inventory/macro.submit.html) macro into source codes, |
| 9 | //! and these information will be gathered by [inventory::iter](https://docs.rs/inventory/latest/inventory/struct.iter.html). |
| 10 | //! This submodule is responsible for this process. |
| 11 | //! |
| 12 | //! - [PyClassInfo] stores information obtained from `#[pyclass]` macro |
| 13 | //! - [PyMethodsInfo] stores information obtained from `#[pymethods]` macro |
| 14 | //! |
| 15 | //! and others are their components. |
| 16 | //! |
| 17 | //! Gathering metadata and generating stub file (runtime) |
| 18 | //! ------------------------------------------------------- |
| 19 | //! Since `#[pyclass]` and `#[pymethods]` definitions are not bundled in a single block, |
| 20 | //! we have to reconstruct these information corresponding to a Python `class`. |
| 21 | //! This process is done at runtime in [gen_stub](../../gen_stub) executable. |
| 22 | //! |
| 23 | |
| 24 | use crate::{PyStubType, TypeInfo}; |
| 25 | use std::any::TypeId; |
| 26 | |
| 27 | /// Work around for `CompareOp` for `__richcmp__` argument, |
| 28 | /// which does not implements `FromPyObject` |
| 29 | pub fn compare_op_type_input() -> TypeInfo { |
| 30 | <isize as PyStubType>::type_input() |
| 31 | } |
| 32 | |
| 33 | pub fn no_return_type_output() -> TypeInfo { |
| 34 | TypeInfo::none() |
| 35 | } |
| 36 | |
| 37 | /// Info of method argument appears in `#[pymethods]` |
| 38 | #[derive (Debug)] |
| 39 | pub struct ArgInfo { |
| 40 | pub name: &'static str, |
| 41 | pub r#type: fn() -> TypeInfo, |
| 42 | pub signature: Option<SignatureArg>, |
| 43 | } |
| 44 | #[derive (Debug, Clone)] |
| 45 | pub enum SignatureArg { |
| 46 | Ident, |
| 47 | Assign { |
| 48 | default: &'static std::sync::LazyLock<String>, |
| 49 | }, |
| 50 | Star, |
| 51 | Args, |
| 52 | Keywords, |
| 53 | } |
| 54 | |
| 55 | impl PartialEq for SignatureArg { |
| 56 | #[inline ] |
| 57 | fn eq(&self, other: &Self) -> bool { |
| 58 | match (self, other) { |
| 59 | (Self::Assign { default: l_default: &&'static LazyLock }, Self::Assign { default: r_default: &&'static LazyLock }) => { |
| 60 | let l_default: &String = l_default; |
| 61 | let r_default: &String = r_default; |
| 62 | l_default.eq(r_default) |
| 63 | } |
| 64 | _ => core::mem::discriminant(self) == core::mem::discriminant(other), |
| 65 | } |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | /// Info of usual method appears in `#[pymethod]` |
| 70 | #[derive (Debug)] |
| 71 | pub struct MethodInfo { |
| 72 | pub name: &'static str, |
| 73 | pub args: &'static [ArgInfo], |
| 74 | pub r#return: fn() -> TypeInfo, |
| 75 | pub doc: &'static str, |
| 76 | pub is_static: bool, |
| 77 | pub is_class: bool, |
| 78 | } |
| 79 | |
| 80 | /// Info of getter method decorated with `#[getter]` or `#[pyo3(get, set)]` appears in `#[pyclass]` |
| 81 | #[derive (Debug)] |
| 82 | pub struct MemberInfo { |
| 83 | pub name: &'static str, |
| 84 | pub r#type: fn() -> TypeInfo, |
| 85 | } |
| 86 | |
| 87 | /// Info of `#[new]`-attributed methods appears in `#[pymethods]` |
| 88 | #[derive (Debug)] |
| 89 | pub struct NewInfo { |
| 90 | pub args: &'static [ArgInfo], |
| 91 | } |
| 92 | |
| 93 | /// Info of `#[pymethod]` |
| 94 | #[derive (Debug)] |
| 95 | pub struct PyMethodsInfo { |
| 96 | // The Rust struct type-id of `impl` block where `#[pymethod]` acts on |
| 97 | pub struct_id: fn() -> TypeId, |
| 98 | /// Method specified `#[new]` attribute |
| 99 | pub new: Option<NewInfo>, |
| 100 | /// Methods decorated with `#[getter]` |
| 101 | pub getters: &'static [MemberInfo], |
| 102 | /// Other usual methods |
| 103 | pub methods: &'static [MethodInfo], |
| 104 | } |
| 105 | |
| 106 | inventory::collect!(PyMethodsInfo); |
| 107 | |
| 108 | /// Info of `#[pyclass]` with Rust struct |
| 109 | #[derive (Debug)] |
| 110 | pub struct PyClassInfo { |
| 111 | // Rust struct type-id |
| 112 | pub struct_id: fn() -> TypeId, |
| 113 | // The name exposed to Python |
| 114 | pub pyclass_name: &'static str, |
| 115 | /// Module name specified by `#[pyclass(module = "foo.bar")]` |
| 116 | pub module: Option<&'static str>, |
| 117 | /// Docstring |
| 118 | pub doc: &'static str, |
| 119 | /// static members by `#[pyo3(get, set)]` |
| 120 | pub members: &'static [MemberInfo], |
| 121 | } |
| 122 | |
| 123 | inventory::collect!(PyClassInfo); |
| 124 | |
| 125 | /// Info of `#[pyclass]` with Rust enum |
| 126 | #[derive (Debug)] |
| 127 | pub struct PyEnumInfo { |
| 128 | // Rust struct type-id |
| 129 | pub enum_id: fn() -> TypeId, |
| 130 | // The name exposed to Python |
| 131 | pub pyclass_name: &'static str, |
| 132 | /// Module name specified by `#[pyclass(module = "foo.bar")]` |
| 133 | pub module: Option<&'static str>, |
| 134 | /// Docstring |
| 135 | pub doc: &'static str, |
| 136 | /// Variants of enum |
| 137 | pub variants: &'static [&'static str], |
| 138 | } |
| 139 | |
| 140 | inventory::collect!(PyEnumInfo); |
| 141 | |
| 142 | /// Info of `#[pyfunction]` |
| 143 | #[derive (Debug)] |
| 144 | pub struct PyFunctionInfo { |
| 145 | pub name: &'static str, |
| 146 | pub args: &'static [ArgInfo], |
| 147 | pub r#return: fn() -> TypeInfo, |
| 148 | pub doc: &'static str, |
| 149 | pub module: Option<&'static str>, |
| 150 | } |
| 151 | |
| 152 | inventory::collect!(PyFunctionInfo); |
| 153 | |
| 154 | #[derive (Debug)] |
| 155 | pub struct PyErrorInfo { |
| 156 | pub name: &'static str, |
| 157 | pub module: &'static str, |
| 158 | pub base: fn() -> &'static str, |
| 159 | } |
| 160 | |
| 161 | inventory::collect!(PyErrorInfo); |
| 162 | |
| 163 | #[derive (Debug)] |
| 164 | pub struct PyVariableInfo { |
| 165 | pub name: &'static str, |
| 166 | pub module: &'static str, |
| 167 | pub r#type: fn() -> TypeInfo, |
| 168 | } |
| 169 | |
| 170 | inventory::collect!(PyVariableInfo); |
| 171 | |