inventory: update to 0.2

This commit is contained in:
David Hewitt 2021-11-22 19:49:56 +00:00
parent af27fd373b
commit f17e0d35cd
5 changed files with 73 additions and 78 deletions

View File

@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Update `paste` optional dependency to 1.0. [#2004](https://github.com/PyO3/pyo3/pull/2004) - Update `paste` optional dependency to 1.0. [#2004](https://github.com/PyO3/pyo3/pull/2004)
- Drop support for Python 3.6, remove `abi3-py36` feature. [#2006](https://github.com/PyO3/pyo3/pull/2006) - Drop support for Python 3.6, remove `abi3-py36` feature. [#2006](https://github.com/PyO3/pyo3/pull/2006)
- `pyo3-build-config` no longer enables the `resolve-config` feature by default. [#2008](https://github.com/PyO3/pyo3/pull/2008) - `pyo3-build-config` no longer enables the `resolve-config` feature by default. [#2008](https://github.com/PyO3/pyo3/pull/2008)
- Update `inventory` optional dependency to 0.2. [#2019](https://github.com/PyO3/pyo3/pull/2019)
### Added ### Added

View File

@ -26,8 +26,7 @@ paste = { version = "1.0.6", optional = true }
unindent = { version = "0.1.4", optional = true } unindent = { version = "0.1.4", optional = true }
# support crate for multiple-pymethods feature # support crate for multiple-pymethods feature
# must stay at 0.1.x for Rust 1.41 compatibility inventory = { version = "0.2.0", optional = true }
inventory = { version = "0.1.4", optional = true }
# crate integrations that can be added using the eponymous features # crate integrations that can be added using the eponymous features
anyhow = { version = "1.0", optional = true } anyhow = { version = "1.0", optional = true }

View File

@ -594,7 +594,6 @@ impl<'a> PyClassImplsBuilder<'a> {
self.impl_pyclass(), self.impl_pyclass(),
self.impl_extractext(), self.impl_extractext(),
self.impl_into_py(), self.impl_into_py(),
self.impl_methods_inventory(),
self.impl_pyclassimpl(), self.impl_pyclassimpl(),
self.impl_freelist(), self.impl_freelist(),
self.impl_gc(), self.impl_gc(),
@ -667,48 +666,6 @@ impl<'a> PyClassImplsBuilder<'a> {
quote! {} quote! {}
} }
} }
/// To allow multiple #[pymethods] block, we define inventory types.
fn impl_methods_inventory(&self) -> TokenStream {
let cls = self.cls;
let methods_type = self.methods_type;
match methods_type {
PyClassMethodsType::Specialization => quote! {},
PyClassMethodsType::Inventory => {
// Try to build a unique type for better error messages
let name = format!("Pyo3MethodsInventoryFor{}", cls.unraw());
let inventory_cls = syn::Ident::new(&name, Span::call_site());
quote! {
#[doc(hidden)]
pub struct #inventory_cls {
methods: ::std::vec::Vec<::pyo3::class::PyMethodDefType>,
slots: ::std::vec::Vec<::pyo3::ffi::PyType_Slot>,
}
impl ::pyo3::class::impl_::PyMethodsInventory for #inventory_cls {
fn new(
methods: ::std::vec::Vec<::pyo3::class::PyMethodDefType>,
slots: ::std::vec::Vec<::pyo3::ffi::PyType_Slot>,
) -> Self {
Self { methods, slots }
}
fn methods(&'static self) -> &'static [::pyo3::class::PyMethodDefType] {
&self.methods
}
fn slots(&'static self) -> &'static [::pyo3::ffi::PyType_Slot] {
&self.slots
}
}
impl ::pyo3::class::impl_::HasMethodsInventory for #cls {
type Methods = #inventory_cls;
}
::pyo3::inventory::collect!(#inventory_cls);
}
}
}
}
fn impl_pyclassimpl(&self) -> TokenStream { fn impl_pyclassimpl(&self) -> TokenStream {
let cls = self.cls; let cls = self.cls;
let doc = self.doc.as_ref().map_or(quote! {"\0"}, |doc| quote! {#doc}); let doc = self.doc.as_ref().map_or(quote! {"\0"}, |doc| quote! {#doc});
@ -727,25 +684,36 @@ impl<'a> PyClassImplsBuilder<'a> {
quote! { ::pyo3::class::impl_::ThreadCheckerStub<#cls> } quote! { ::pyo3::class::impl_::ThreadCheckerStub<#cls> }
}; };
let methods_protos = match self.methods_type { let (for_each_py_method, methods_protos, inventory, inventory_class) = match self
PyClassMethodsType::Specialization => { .methods_type
quote! { visitor(collector.methods_protocol_slots()); } {
} PyClassMethodsType::Specialization => (
quote! { visitor(collector.py_methods()); },
quote! { visitor(collector.methods_protocol_slots()); },
None,
None,
),
PyClassMethodsType::Inventory => { PyClassMethodsType::Inventory => {
// To allow multiple #[pymethods] block, we define inventory types.
let inventory_class_name = syn::Ident::new(
&format!("Pyo3MethodsInventoryFor{}", cls.unraw()),
Span::call_site(),
);
(
quote! { quote! {
for inventory in ::pyo3::inventory::iter::<<Self as ::pyo3::class::impl_::HasMethodsInventory>::Methods>() { for inventory in ::pyo3::inventory::iter::<<Self as ::pyo3::class::impl_::PyClassImpl>::Inventory>() {
visitor(::pyo3::class::impl_::PyMethodsInventory::slots(inventory)); visitor(::pyo3::class::impl_::PyClassInventory::methods(inventory));
}
}
}
};
let for_each_py_method = match self.methods_type {
PyClassMethodsType::Specialization => quote! { visitor(collector.py_methods()); },
PyClassMethodsType::Inventory => quote! {
for inventory in ::pyo3::inventory::iter::<<Self as ::pyo3::class::impl_::HasMethodsInventory>::Methods>() {
visitor(::pyo3::class::impl_::PyMethodsInventory::methods(inventory));
} }
}, },
quote! {
for inventory in ::pyo3::inventory::iter::<<Self as ::pyo3::class::impl_::PyClassImpl>::Inventory>() {
visitor(::pyo3::class::impl_::PyClassInventory::slots(inventory));
}
},
Some(quote! { type Inventory = #inventory_class_name; }),
Some(define_inventory_class(&inventory_class_name)),
)
}
}; };
quote! { quote! {
impl ::pyo3::class::impl_::PyClassImpl for #cls { impl ::pyo3::class::impl_::PyClassImpl for #cls {
@ -757,6 +725,7 @@ impl<'a> PyClassImplsBuilder<'a> {
type Layout = ::pyo3::PyCell<Self>; type Layout = ::pyo3::PyCell<Self>;
type BaseType = #base; type BaseType = #base;
type ThreadChecker = #thread_checker; type ThreadChecker = #thread_checker;
#inventory
fn for_each_method_def(visitor: &mut dyn ::std::ops::FnMut(&[::pyo3::class::PyMethodDefType])) { fn for_each_method_def(visitor: &mut dyn ::std::ops::FnMut(&[::pyo3::class::PyMethodDefType])) {
use ::pyo3::class::impl_::*; use ::pyo3::class::impl_::*;
@ -807,6 +776,8 @@ impl<'a> PyClassImplsBuilder<'a> {
collector.buffer_procs() collector.buffer_procs()
} }
} }
#inventory_class
} }
} }
@ -865,3 +836,36 @@ impl<'a> PyClassImplsBuilder<'a> {
} }
} }
} }
fn define_inventory_class(inventory_class_name: &syn::Ident) -> TokenStream {
quote! {
#[doc(hidden)]
pub struct #inventory_class_name {
methods: &'static [::pyo3::class::PyMethodDefType],
slots: &'static [::pyo3::ffi::PyType_Slot],
}
impl #inventory_class_name {
const fn new(
methods: &'static [::pyo3::class::PyMethodDefType],
slots: &'static [::pyo3::ffi::PyType_Slot],
) -> Self {
Self { methods, slots }
}
}
impl ::pyo3::class::impl_::PyClassInventory for #inventory_class_name {
fn methods(&'static self) -> &'static [::pyo3::class::PyMethodDefType] {
self.methods
}
fn slots(&'static self) -> &'static [::pyo3::ffi::PyType_Slot] {
self.slots
}
}
// inventory requires these bounds
unsafe impl ::std::marker::Send for #inventory_class_name {}
unsafe impl ::std::marker::Sync for #inventory_class_name {}
::pyo3::inventory::collect!(#inventory_class_name);
}
}

View File

@ -211,10 +211,8 @@ fn submit_methods_inventory(
) -> TokenStream { ) -> TokenStream {
quote! { quote! {
::pyo3::inventory::submit! { ::pyo3::inventory::submit! {
#![crate = ::pyo3] { type Inventory = <#ty as ::pyo3::class::impl_::PyClassImpl>::Inventory;
type Inventory = <#ty as ::pyo3::class::impl_::HasMethodsInventory>::Methods; Inventory::new(&[#(#methods),*], &[#(#proto_impls),*])
<Inventory as ::pyo3::class::impl_::PyMethodsInventory>::new(::std::vec![#(#methods),*], ::std::vec![#(#proto_impls),*])
}
} }
} }
} }

View File

@ -67,6 +67,9 @@ pub trait PyClassImpl: Sized {
/// can be accessed by multiple threads by `threading` module. /// can be accessed by multiple threads by `threading` module.
type ThreadChecker: PyClassThreadChecker<Self>; type ThreadChecker: PyClassThreadChecker<Self>;
#[cfg(feature = "multiple-pymethods")]
type Inventory: PyClassInventory;
fn for_each_method_def(_visitor: &mut dyn FnMut(&[PyMethodDefType])) {} fn for_each_method_def(_visitor: &mut dyn FnMut(&[PyMethodDefType])) {}
fn get_new() -> Option<ffi::newfunc> { fn get_new() -> Option<ffi::newfunc> {
None None
@ -607,11 +610,8 @@ macro_rules! methods_trait {
/// Method storage for `#[pyclass]`. /// Method storage for `#[pyclass]`.
/// Allows arbitrary `#[pymethod]` blocks to submit their methods, /// Allows arbitrary `#[pymethod]` blocks to submit their methods,
/// which are eventually collected by `#[pyclass]`. /// which are eventually collected by `#[pyclass]`.
#[cfg(all(feature = "macros", feature = "multiple-pymethods"))] #[cfg(feature = "multiple-pymethods")]
pub trait PyMethodsInventory: inventory::Collect { pub trait PyClassInventory: inventory::Collect {
/// Create a new instance
fn new(methods: Vec<PyMethodDefType>, slots: Vec<ffi::PyType_Slot>) -> Self;
/// Returns the methods for a single `#[pymethods] impl` block /// Returns the methods for a single `#[pymethods] impl` block
fn methods(&'static self) -> &'static [PyMethodDefType]; fn methods(&'static self) -> &'static [PyMethodDefType];
@ -619,13 +619,6 @@ pub trait PyMethodsInventory: inventory::Collect {
fn slots(&'static self) -> &'static [ffi::PyType_Slot]; fn slots(&'static self) -> &'static [ffi::PyType_Slot];
} }
/// Implemented for `#[pyclass]` in our proc macro code.
/// Indicates that the pyclass has its own method storage.
#[cfg(all(feature = "macros", feature = "multiple-pymethods"))]
pub trait HasMethodsInventory {
type Methods: PyMethodsInventory;
}
// Methods from #[pyo3(get, set)] on struct fields. // Methods from #[pyo3(get, set)] on struct fields.
methods_trait!(PyClassDescriptors, py_class_descriptors); methods_trait!(PyClassDescriptors, py_class_descriptors);