Merge pull request #2019 from davidhewitt/inventory-0.2.0

inventory: update to 0.2
This commit is contained in:
David Hewitt 2021-11-23 07:39:05 +00:00 committed by GitHub
commit a0d3ab0de1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
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)
- 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)
- Update `inventory` optional dependency to 0.2. [#2019](https://github.com/PyO3/pyo3/pull/2019)
### Added

View File

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

View File

@ -594,7 +594,6 @@ impl<'a> PyClassImplsBuilder<'a> {
self.impl_pyclass(),
self.impl_extractext(),
self.impl_into_py(),
self.impl_methods_inventory(),
self.impl_pyclassimpl(),
self.impl_freelist(),
self.impl_gc(),
@ -667,48 +666,6 @@ impl<'a> PyClassImplsBuilder<'a> {
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 {
let cls = self.cls;
let doc = self.doc.as_ref().map_or(quote! {"\0"}, |doc| quote! {#doc});
@ -727,26 +684,37 @@ impl<'a> PyClassImplsBuilder<'a> {
quote! { ::pyo3::class::impl_::ThreadCheckerStub<#cls> }
};
let methods_protos = match self.methods_type {
PyClassMethodsType::Specialization => {
quote! { visitor(collector.methods_protocol_slots()); }
}
let (for_each_py_method, methods_protos, inventory, inventory_class) = match self
.methods_type
{
PyClassMethodsType::Specialization => (
quote! { visitor(collector.py_methods()); },
quote! { visitor(collector.methods_protocol_slots()); },
None,
None,
),
PyClassMethodsType::Inventory => {
quote! {
for inventory in ::pyo3::inventory::iter::<<Self as ::pyo3::class::impl_::HasMethodsInventory>::Methods>() {
visitor(::pyo3::class::impl_::PyMethodsInventory::slots(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! {
for inventory in ::pyo3::inventory::iter::<<Self as ::pyo3::class::impl_::PyClassImpl>::Inventory>() {
visitor(::pyo3::class::impl_::PyClassInventory::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)),
)
}
};
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! {
impl ::pyo3::class::impl_::PyClassImpl for #cls {
const DOC: &'static str = #doc;
@ -757,6 +725,7 @@ impl<'a> PyClassImplsBuilder<'a> {
type Layout = ::pyo3::PyCell<Self>;
type BaseType = #base;
type ThreadChecker = #thread_checker;
#inventory
fn for_each_method_def(visitor: &mut dyn ::std::ops::FnMut(&[::pyo3::class::PyMethodDefType])) {
use ::pyo3::class::impl_::*;
@ -807,6 +776,8 @@ impl<'a> PyClassImplsBuilder<'a> {
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 {
quote! {
::pyo3::inventory::submit! {
#![crate = ::pyo3] {
type Inventory = <#ty as ::pyo3::class::impl_::HasMethodsInventory>::Methods;
<Inventory as ::pyo3::class::impl_::PyMethodsInventory>::new(::std::vec![#(#methods),*], ::std::vec![#(#proto_impls),*])
}
type Inventory = <#ty as ::pyo3::class::impl_::PyClassImpl>::Inventory;
Inventory::new(&[#(#methods),*], &[#(#proto_impls),*])
}
}
}

View File

@ -67,6 +67,9 @@ pub trait PyClassImpl: Sized {
/// can be accessed by multiple threads by `threading` module.
type ThreadChecker: PyClassThreadChecker<Self>;
#[cfg(feature = "multiple-pymethods")]
type Inventory: PyClassInventory;
fn for_each_method_def(_visitor: &mut dyn FnMut(&[PyMethodDefType])) {}
fn get_new() -> Option<ffi::newfunc> {
None
@ -607,11 +610,8 @@ macro_rules! methods_trait {
/// Method storage for `#[pyclass]`.
/// Allows arbitrary `#[pymethod]` blocks to submit their methods,
/// which are eventually collected by `#[pyclass]`.
#[cfg(all(feature = "macros", feature = "multiple-pymethods"))]
pub trait PyMethodsInventory: inventory::Collect {
/// Create a new instance
fn new(methods: Vec<PyMethodDefType>, slots: Vec<ffi::PyType_Slot>) -> Self;
#[cfg(feature = "multiple-pymethods")]
pub trait PyClassInventory: inventory::Collect {
/// Returns the methods for a single `#[pymethods] impl` block
fn methods(&'static self) -> &'static [PyMethodDefType];
@ -619,13 +619,6 @@ pub trait PyMethodsInventory: inventory::Collect {
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_trait!(PyClassDescriptors, py_class_descriptors);