pyclass: simplify generated code for PyClassImpl
This commit is contained in:
parent
558549e1c2
commit
ecfd2c2434
|
@ -858,16 +858,11 @@ impl pyo3::impl_::pyclass::PyClassImpl for MyClass {
|
||||||
type BaseType = PyAny;
|
type BaseType = PyAny;
|
||||||
type ThreadChecker = pyo3::impl_::pyclass::ThreadCheckerStub<MyClass>;
|
type ThreadChecker = pyo3::impl_::pyclass::ThreadCheckerStub<MyClass>;
|
||||||
|
|
||||||
fn for_each_method_def(visitor: &mut dyn FnMut(&[pyo3::class::PyMethodDefType])) {
|
fn for_all_items(visitor: &mut dyn FnMut(&pyo3::impl_::pyclass::PyClassItems)) {
|
||||||
use pyo3::impl_::pyclass::*;
|
use pyo3::impl_::pyclass::*;
|
||||||
let collector = PyClassImplCollector::<MyClass>::new();
|
let collector = PyClassImplCollector::<MyClass>::new();
|
||||||
visitor(collector.py_methods());
|
visitor(collector.py_methods());
|
||||||
visitor(collector.py_class_descriptors());
|
visitor(collector.pyclass_intrinsic_items());
|
||||||
visitor(collector.object_protocol_methods());
|
|
||||||
visitor(collector.async_protocol_methods());
|
|
||||||
visitor(collector.descr_protocol_methods());
|
|
||||||
visitor(collector.mapping_protocol_methods());
|
|
||||||
visitor(collector.number_protocol_methods());
|
|
||||||
}
|
}
|
||||||
fn get_new() -> Option<pyo3::ffi::newfunc> {
|
fn get_new() -> Option<pyo3::ffi::newfunc> {
|
||||||
use pyo3::impl_::pyclass::*;
|
use pyo3::impl_::pyclass::*;
|
||||||
|
@ -884,21 +879,6 @@ impl pyo3::impl_::pyclass::PyClassImpl for MyClass {
|
||||||
let collector = PyClassImplCollector::<Self>::new();
|
let collector = PyClassImplCollector::<Self>::new();
|
||||||
collector.free_impl()
|
collector.free_impl()
|
||||||
}
|
}
|
||||||
fn for_each_proto_slot(visitor: &mut dyn FnMut(&[pyo3::ffi::PyType_Slot])) {
|
|
||||||
// Implementation which uses dtolnay specialization to load all slots.
|
|
||||||
use pyo3::impl_::pyclass::*;
|
|
||||||
let collector = PyClassImplCollector::<Self>::new();
|
|
||||||
visitor(collector.object_protocol_slots());
|
|
||||||
visitor(collector.number_protocol_slots());
|
|
||||||
visitor(collector.iter_protocol_slots());
|
|
||||||
visitor(collector.gc_protocol_slots());
|
|
||||||
visitor(collector.descr_protocol_slots());
|
|
||||||
visitor(collector.mapping_protocol_slots());
|
|
||||||
visitor(collector.sequence_protocol_slots());
|
|
||||||
visitor(collector.async_protocol_slots());
|
|
||||||
visitor(collector.buffer_protocol_slots());
|
|
||||||
visitor(collector.methods_protocol_slots());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
# Python::with_gil(|py| {
|
# Python::with_gil(|py| {
|
||||||
# let cls = py.get_type::<MyClass>();
|
# let cls = py.get_type::<MyClass>();
|
||||||
|
|
|
@ -64,27 +64,13 @@ impl Proto {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn slots_trait(&self) -> syn::Ident {
|
pub(crate) fn items_trait(&self) -> syn::Ident {
|
||||||
syn::Ident::new(&format!("Py{}ProtocolSlots", self.name), Span::call_site())
|
syn::Ident::new(&format!("Py{}ProtocolItems", self.name), Span::call_site())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn slots_trait_slots(&self) -> syn::Ident {
|
pub(crate) fn items_trait_items(&self) -> syn::Ident {
|
||||||
syn::Ident::new(
|
syn::Ident::new(
|
||||||
&format!("{}_protocol_slots", self.name.to_ascii_lowercase()),
|
&format!("{}_protocol_items", self.name.to_ascii_lowercase()),
|
||||||
Span::call_site(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn methods_trait(&self) -> syn::Ident {
|
|
||||||
syn::Ident::new(
|
|
||||||
&format!("Py{}ProtocolMethods", self.name),
|
|
||||||
Span::call_site(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn methods_trait_methods(&self) -> syn::Ident {
|
|
||||||
syn::Ident::new(
|
|
||||||
&format!("{}_protocol_methods", self.name.to_ascii_lowercase()),
|
|
||||||
Span::call_site(),
|
Span::call_site(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use crate::attributes::{
|
||||||
};
|
};
|
||||||
use crate::deprecations::Deprecations;
|
use crate::deprecations::Deprecations;
|
||||||
use crate::konst::{ConstAttributes, ConstSpec};
|
use crate::konst::{ConstAttributes, ConstSpec};
|
||||||
use crate::pyimpl::{gen_default_slot_impls, gen_py_const, PyClassMethodsType};
|
use crate::pyimpl::{gen_default_items, gen_py_const, PyClassMethodsType};
|
||||||
use crate::pymethod::{impl_py_getter_def, impl_py_setter_def, PropertyType};
|
use crate::pymethod::{impl_py_getter_def, impl_py_setter_def, PropertyType};
|
||||||
use crate::utils::{self, get_pyo3_crate, unwrap_group, PythonDoc};
|
use crate::utils::{self, get_pyo3_crate, unwrap_group, PythonDoc};
|
||||||
use proc_macro2::{Span, TokenStream};
|
use proc_macro2::{Span, TokenStream};
|
||||||
|
@ -477,7 +477,7 @@ fn impl_enum_class(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let default_impls = gen_default_slot_impls(cls, vec![default_repr_impl]);
|
let default_impls = gen_default_items(cls, vec![default_repr_impl]);
|
||||||
Ok(quote! {
|
Ok(quote! {
|
||||||
const _: () = {
|
const _: () = {
|
||||||
use #krate as _pyo3;
|
use #krate as _pyo3;
|
||||||
|
@ -511,12 +511,15 @@ fn unit_variants_as_descriptors<'a>(
|
||||||
.map(|var| gen_py_const(&cls_type, &variant_to_attribute(var)));
|
.map(|var| gen_py_const(&cls_type, &variant_to_attribute(var)));
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
impl _pyo3::impl_::pyclass::PyClassDescriptors<#cls>
|
impl _pyo3::impl_::pyclass::PyClassIntrinsicItems<#cls>
|
||||||
for _pyo3::impl_::pyclass::PyClassImplCollector<#cls>
|
for _pyo3::impl_::pyclass::PyClassImplCollector<#cls>
|
||||||
{
|
{
|
||||||
fn py_class_descriptors(self) -> &'static [_pyo3::impl_::pymethods::PyMethodDefType] {
|
fn pyclass_intrinsic_items(self) -> &'static _pyo3::impl_::pyclass::PyClassItems {
|
||||||
static METHODS: &[_pyo3::impl_::pymethods::PyMethodDefType] = &[#(#py_methods),*];
|
static ITEMS: _pyo3::impl_::pyclass::PyClassItems = _pyo3::impl_::pyclass::PyClassItems {
|
||||||
METHODS
|
methods: &[#(#py_methods),*],
|
||||||
|
slots: &[]
|
||||||
|
};
|
||||||
|
&ITEMS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -574,12 +577,15 @@ fn impl_descriptors(
|
||||||
.collect::<syn::Result<_>>()?;
|
.collect::<syn::Result<_>>()?;
|
||||||
|
|
||||||
Ok(quote! {
|
Ok(quote! {
|
||||||
impl _pyo3::impl_::pyclass::PyClassDescriptors<#cls>
|
impl _pyo3::impl_::pyclass::PyClassIntrinsicItems<#cls>
|
||||||
for _pyo3::impl_::pyclass::PyClassImplCollector<#cls>
|
for _pyo3::impl_::pyclass::PyClassImplCollector<#cls>
|
||||||
{
|
{
|
||||||
fn py_class_descriptors(self) -> &'static [_pyo3::impl_::pymethods::PyMethodDefType] {
|
fn pyclass_intrinsic_items(self) -> &'static _pyo3::impl_::pyclass::PyClassItems {
|
||||||
static METHODS: &[_pyo3::impl_::pymethods::PyMethodDefType] = &[#(#py_methods),*];
|
static ITEMS: _pyo3::impl_::pyclass::PyClassItems = _pyo3::impl_::pyclass::PyClassItems {
|
||||||
METHODS
|
methods: &[#(#py_methods),*],
|
||||||
|
slots: &[]
|
||||||
|
};
|
||||||
|
&ITEMS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -758,15 +764,10 @@ impl<'a> PyClassImplsBuilder<'a> {
|
||||||
quote! { _pyo3::impl_::pyclass::ThreadCheckerStub<#cls> }
|
quote! { _pyo3::impl_::pyclass::ThreadCheckerStub<#cls> }
|
||||||
};
|
};
|
||||||
|
|
||||||
let (for_each_py_method, methods_protos, inventory, inventory_class) = match self
|
let (pymethods_items, inventory, inventory_class) = match self.methods_type {
|
||||||
.methods_type
|
PyClassMethodsType::Specialization => {
|
||||||
{
|
(quote! { visitor(collector.py_methods()); }, None, None)
|
||||||
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.
|
// To allow multiple #[pymethods] block, we define inventory types.
|
||||||
let inventory_class_name = syn::Ident::new(
|
let inventory_class_name = syn::Ident::new(
|
||||||
|
@ -776,12 +777,7 @@ impl<'a> PyClassImplsBuilder<'a> {
|
||||||
(
|
(
|
||||||
quote! {
|
quote! {
|
||||||
for inventory in _pyo3::inventory::iter::<<Self as _pyo3::impl_::pyclass::PyClassImpl>::Inventory>() {
|
for inventory in _pyo3::inventory::iter::<<Self as _pyo3::impl_::pyclass::PyClassImpl>::Inventory>() {
|
||||||
visitor(_pyo3::impl_::pyclass::PyClassInventory::methods(inventory));
|
visitor(_pyo3::impl_::pyclass::PyClassInventory::items(inventory));
|
||||||
}
|
|
||||||
},
|
|
||||||
quote! {
|
|
||||||
for inventory in _pyo3::inventory::iter::<<Self as _pyo3::impl_::pyclass::PyClassImpl>::Inventory>() {
|
|
||||||
visitor(_pyo3::impl_::pyclass::PyClassInventory::slots(inventory));
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Some(quote! { type Inventory = #inventory_class_name; }),
|
Some(quote! { type Inventory = #inventory_class_name; }),
|
||||||
|
@ -790,29 +786,17 @@ impl<'a> PyClassImplsBuilder<'a> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let pyproto_method_visitors = if cfg!(feature = "pyproto") {
|
let pyproto_items = if cfg!(feature = "pyproto") {
|
||||||
Some(quote! {
|
Some(quote! {
|
||||||
visitor(collector.object_protocol_methods());
|
visitor(collector.object_protocol_items());
|
||||||
visitor(collector.async_protocol_methods());
|
visitor(collector.number_protocol_items());
|
||||||
visitor(collector.descr_protocol_methods());
|
visitor(collector.iter_protocol_items());
|
||||||
visitor(collector.mapping_protocol_methods());
|
visitor(collector.gc_protocol_items());
|
||||||
visitor(collector.number_protocol_methods());
|
visitor(collector.descr_protocol_items());
|
||||||
})
|
visitor(collector.mapping_protocol_items());
|
||||||
} else {
|
visitor(collector.sequence_protocol_items());
|
||||||
None
|
visitor(collector.async_protocol_items());
|
||||||
};
|
visitor(collector.buffer_protocol_items());
|
||||||
|
|
||||||
let pyproto_proto_visitors = if cfg!(feature = "pyproto") {
|
|
||||||
Some(quote! {
|
|
||||||
visitor(collector.object_protocol_slots());
|
|
||||||
visitor(collector.number_protocol_slots());
|
|
||||||
visitor(collector.iter_protocol_slots());
|
|
||||||
visitor(collector.gc_protocol_slots());
|
|
||||||
visitor(collector.descr_protocol_slots());
|
|
||||||
visitor(collector.mapping_protocol_slots());
|
|
||||||
visitor(collector.sequence_protocol_slots());
|
|
||||||
visitor(collector.async_protocol_slots());
|
|
||||||
visitor(collector.buffer_protocol_slots());
|
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -830,12 +814,15 @@ impl<'a> PyClassImplsBuilder<'a> {
|
||||||
type ThreadChecker = #thread_checker;
|
type ThreadChecker = #thread_checker;
|
||||||
#inventory
|
#inventory
|
||||||
|
|
||||||
fn for_each_method_def(visitor: &mut dyn ::std::ops::FnMut(&[_pyo3::class::PyMethodDefType])) {
|
fn for_all_items(visitor: &mut dyn ::std::ops::FnMut(& _pyo3::impl_::pyclass::PyClassItems)) {
|
||||||
use _pyo3::impl_::pyclass::*;
|
use _pyo3::impl_::pyclass::*;
|
||||||
let collector = PyClassImplCollector::<Self>::new();
|
let collector = PyClassImplCollector::<Self>::new();
|
||||||
#for_each_py_method;
|
visitor(collector.pyclass_intrinsic_items());
|
||||||
visitor(collector.py_class_descriptors());
|
// This depends on Python implementation detail;
|
||||||
#pyproto_method_visitors
|
// an old slot entry will be overriden by newer ones.
|
||||||
|
visitor(collector.pyclass_default_items());
|
||||||
|
#pymethods_items
|
||||||
|
#pyproto_items
|
||||||
}
|
}
|
||||||
fn get_new() -> ::std::option::Option<_pyo3::ffi::newfunc> {
|
fn get_new() -> ::std::option::Option<_pyo3::ffi::newfunc> {
|
||||||
use _pyo3::impl_::pyclass::*;
|
use _pyo3::impl_::pyclass::*;
|
||||||
|
@ -853,17 +840,6 @@ impl<'a> PyClassImplsBuilder<'a> {
|
||||||
collector.free_impl()
|
collector.free_impl()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn for_each_proto_slot(visitor: &mut dyn ::std::ops::FnMut(&[_pyo3::ffi::PyType_Slot])) {
|
|
||||||
// Implementation which uses dtolnay specialization to load all slots.
|
|
||||||
use _pyo3::impl_::pyclass::*;
|
|
||||||
let collector = PyClassImplCollector::<Self>::new();
|
|
||||||
// This depends on Python implementation detail;
|
|
||||||
// an old slot entry will be overriden by newer ones.
|
|
||||||
visitor(collector.py_class_default_slots());
|
|
||||||
#pyproto_proto_visitors
|
|
||||||
#methods_protos
|
|
||||||
}
|
|
||||||
|
|
||||||
#dict_offset
|
#dict_offset
|
||||||
|
|
||||||
#weaklist_offset
|
#weaklist_offset
|
||||||
|
@ -933,31 +909,20 @@ fn define_inventory_class(inventory_class_name: &syn::Ident) -> TokenStream {
|
||||||
quote! {
|
quote! {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub struct #inventory_class_name {
|
pub struct #inventory_class_name {
|
||||||
methods: &'static [_pyo3::class::PyMethodDefType],
|
items: _pyo3::impl_::pyclass::PyClassItems,
|
||||||
slots: &'static [_pyo3::ffi::PyType_Slot],
|
|
||||||
}
|
}
|
||||||
impl #inventory_class_name {
|
impl #inventory_class_name {
|
||||||
const fn new(
|
const fn new(items: _pyo3::impl_::pyclass::PyClassItems) -> Self {
|
||||||
methods: &'static [_pyo3::class::PyMethodDefType],
|
Self { items }
|
||||||
slots: &'static [_pyo3::ffi::PyType_Slot],
|
|
||||||
) -> Self {
|
|
||||||
Self { methods, slots }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl _pyo3::impl_::pyclass::PyClassInventory for #inventory_class_name {
|
impl _pyo3::impl_::pyclass::PyClassInventory for #inventory_class_name {
|
||||||
fn methods(&'static self) -> &'static [_pyo3::class::PyMethodDefType] {
|
fn items(&self) -> &_pyo3::impl_::pyclass::PyClassItems {
|
||||||
self.methods
|
&self.items
|
||||||
}
|
|
||||||
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);
|
_pyo3::inventory::collect!(#inventory_class_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,35 +150,19 @@ pub fn impl_methods(
|
||||||
|
|
||||||
let krate = get_pyo3_crate(&options.krate);
|
let krate = get_pyo3_crate(&options.krate);
|
||||||
|
|
||||||
Ok(match methods_type {
|
let items = match methods_type {
|
||||||
PyClassMethodsType::Specialization => {
|
PyClassMethodsType::Specialization => impl_py_methods(ty, methods, proto_impls),
|
||||||
let methods_registration = impl_py_methods(ty, methods);
|
PyClassMethodsType::Inventory => submit_methods_inventory(ty, methods, proto_impls),
|
||||||
let protos_registration = impl_protos(ty, proto_impls);
|
};
|
||||||
|
|
||||||
quote! {
|
Ok(quote! {
|
||||||
const _: () = {
|
const _: () = {
|
||||||
use #krate as _pyo3;
|
use #krate as _pyo3;
|
||||||
|
|
||||||
#(#trait_impls)*
|
#(#trait_impls)*
|
||||||
|
|
||||||
#protos_registration
|
#items
|
||||||
|
};
|
||||||
#methods_registration
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PyClassMethodsType::Inventory => {
|
|
||||||
let inventory = submit_methods_inventory(ty, methods, proto_impls);
|
|
||||||
quote! {
|
|
||||||
const _: () = {
|
|
||||||
use #krate as _pyo3;
|
|
||||||
|
|
||||||
#(#trait_impls)*
|
|
||||||
|
|
||||||
#inventory
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,7 +186,7 @@ pub fn gen_py_const(cls: &syn::Type, spec: &ConstSpec) -> TokenStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_default_slot_impls(cls: &syn::Ident, method_defs: Vec<TokenStream>) -> TokenStream {
|
pub fn gen_default_items(cls: &syn::Ident, method_defs: Vec<TokenStream>) -> TokenStream {
|
||||||
// This function uses a lot of `unwrap()`; since method_defs are provided by us, they should
|
// This function uses a lot of `unwrap()`; since method_defs are provided by us, they should
|
||||||
// all succeed.
|
// all succeed.
|
||||||
let ty: syn::Type = syn::parse_quote!(#cls);
|
let ty: syn::Type = syn::parse_quote!(#cls);
|
||||||
|
@ -234,23 +218,34 @@ pub fn gen_default_slot_impls(cls: &syn::Ident, method_defs: Vec<TokenStream>) -
|
||||||
impl #cls {
|
impl #cls {
|
||||||
#(#method_defs)*
|
#(#method_defs)*
|
||||||
}
|
}
|
||||||
impl ::pyo3::impl_::pyclass::PyClassDefaultSlots<#cls>
|
impl ::pyo3::impl_::pyclass::PyClassDefaultItems<#cls>
|
||||||
for ::pyo3::impl_::pyclass::PyClassImplCollector<#cls> {
|
for ::pyo3::impl_::pyclass::PyClassImplCollector<#cls> {
|
||||||
fn py_class_default_slots(self) -> &'static [::pyo3::ffi::PyType_Slot] {
|
fn pyclass_default_items(self) -> &'static _pyo3::impl_::pyclass::PyClassItems {
|
||||||
&[#(#proto_impls),*]
|
static ITEMS: _pyo3::impl_::pyclass::PyClassItems = _pyo3::impl_::pyclass::PyClassItems {
|
||||||
|
methods: &[],
|
||||||
|
slots: &[#(#proto_impls),*]
|
||||||
|
};
|
||||||
|
&ITEMS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn impl_py_methods(ty: &syn::Type, methods: Vec<TokenStream>) -> TokenStream {
|
fn impl_py_methods(
|
||||||
|
ty: &syn::Type,
|
||||||
|
methods: Vec<TokenStream>,
|
||||||
|
proto_impls: Vec<TokenStream>,
|
||||||
|
) -> TokenStream {
|
||||||
quote! {
|
quote! {
|
||||||
impl _pyo3::impl_::pyclass::PyMethods<#ty>
|
impl _pyo3::impl_::pyclass::PyMethods<#ty>
|
||||||
for _pyo3::impl_::pyclass::PyClassImplCollector<#ty>
|
for _pyo3::impl_::pyclass::PyClassImplCollector<#ty>
|
||||||
{
|
{
|
||||||
fn py_methods(self) -> &'static [_pyo3::impl_::pymethods::PyMethodDefType] {
|
fn py_methods(self) -> &'static _pyo3::impl_::pyclass::PyClassItems {
|
||||||
static METHODS: &[_pyo3::impl_::pymethods::PyMethodDefType] = &[#(#methods),*];
|
static ITEMS: _pyo3::impl_::pyclass::PyClassItems = _pyo3::impl_::pyclass::PyClassItems {
|
||||||
METHODS
|
methods: &[#(#methods),*],
|
||||||
|
slots: &[#(#proto_impls),*]
|
||||||
|
};
|
||||||
|
&ITEMS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -298,18 +293,6 @@ fn add_shared_proto_slots(
|
||||||
assert!(implemented_proto_fragments.is_empty());
|
assert!(implemented_proto_fragments.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn impl_protos(ty: &syn::Type, proto_impls: Vec<TokenStream>) -> TokenStream {
|
|
||||||
quote! {
|
|
||||||
impl _pyo3::impl_::pyclass::PyMethodsProtocolSlots<#ty>
|
|
||||||
for _pyo3::impl_::pyclass::PyClassImplCollector<#ty>
|
|
||||||
{
|
|
||||||
fn methods_protocol_slots(self) -> &'static [_pyo3::ffi::PyType_Slot] {
|
|
||||||
&[#(#proto_impls),*]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn submit_methods_inventory(
|
fn submit_methods_inventory(
|
||||||
ty: &syn::Type,
|
ty: &syn::Type,
|
||||||
methods: Vec<TokenStream>,
|
methods: Vec<TokenStream>,
|
||||||
|
@ -318,7 +301,7 @@ fn submit_methods_inventory(
|
||||||
quote! {
|
quote! {
|
||||||
_pyo3::inventory::submit! {
|
_pyo3::inventory::submit! {
|
||||||
type Inventory = <#ty as _pyo3::impl_::pyclass::PyClassImpl>::Inventory;
|
type Inventory = <#ty as _pyo3::impl_::pyclass::PyClassImpl>::Inventory;
|
||||||
Inventory::new(&[#(#methods),*], &[#(#proto_impls),*])
|
Inventory::new(_pyo3::impl_::pyclass::PyClassItems { methods: &[#(#methods),*], slots: &[#(#proto_impls),*] })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,55 +84,30 @@ fn impl_proto_impl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let normal_methods = impl_normal_methods(py_methods, ty, proto);
|
let items = impl_proto_items(method_names, py_methods, ty, proto);
|
||||||
let protocol_methods = impl_proto_methods(method_names, ty, proto);
|
|
||||||
|
|
||||||
Ok(quote! {
|
Ok(quote! {
|
||||||
const _: () = {
|
const _: () = {
|
||||||
use ::pyo3 as _pyo3; // pyproto doesn't support specifying #[pyo3(crate)]
|
use ::pyo3 as _pyo3; // pyproto doesn't support specifying #[pyo3(crate)]
|
||||||
#trait_impls
|
#trait_impls
|
||||||
#normal_methods
|
#items
|
||||||
#protocol_methods
|
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn impl_normal_methods(
|
fn impl_proto_items(
|
||||||
|
method_names: HashSet<String>,
|
||||||
py_methods: Vec<TokenStream>,
|
py_methods: Vec<TokenStream>,
|
||||||
ty: &syn::Type,
|
ty: &syn::Type,
|
||||||
proto: &defs::Proto,
|
proto: &defs::Proto,
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
if py_methods.is_empty() {
|
if method_names.is_empty() && py_methods.is_empty() {
|
||||||
return TokenStream::default();
|
|
||||||
}
|
|
||||||
|
|
||||||
let methods_trait = proto.methods_trait();
|
|
||||||
let methods_trait_methods = proto.methods_trait_methods();
|
|
||||||
quote! {
|
|
||||||
impl _pyo3::impl_::pyclass::#methods_trait<#ty>
|
|
||||||
for _pyo3::impl_::pyclass::PyClassImplCollector<#ty>
|
|
||||||
{
|
|
||||||
fn #methods_trait_methods(self) -> &'static [_pyo3::impl_::pymethods::PyMethodDefType] {
|
|
||||||
static METHODS: &[_pyo3::impl_::pymethods::PyMethodDefType] =
|
|
||||||
&[#(#py_methods),*];
|
|
||||||
METHODS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn impl_proto_methods(
|
|
||||||
method_names: HashSet<String>,
|
|
||||||
ty: &syn::Type,
|
|
||||||
proto: &defs::Proto,
|
|
||||||
) -> TokenStream {
|
|
||||||
if method_names.is_empty() {
|
|
||||||
return TokenStream::default();
|
return TokenStream::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
let module = proto.module();
|
let module = proto.module();
|
||||||
let slots_trait = proto.slots_trait();
|
let items_trait = proto.items_trait();
|
||||||
let slots_trait_slots = proto.slots_trait_slots();
|
let items_trait_items = proto.items_trait_items();
|
||||||
|
|
||||||
let mut tokens = proto
|
let mut tokens = proto
|
||||||
.slot_defs(method_names)
|
.slot_defs(method_names)
|
||||||
|
@ -153,11 +128,15 @@ fn impl_proto_methods(
|
||||||
}
|
}
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
impl _pyo3::impl_::pyclass::#slots_trait<#ty>
|
impl _pyo3::impl_::pyclass::#items_trait<#ty>
|
||||||
for _pyo3::impl_::pyclass::PyClassImplCollector<#ty>
|
for _pyo3::impl_::pyclass::PyClassImplCollector<#ty>
|
||||||
{
|
{
|
||||||
fn #slots_trait_slots(self) -> &'static [_pyo3::ffi::PyType_Slot] {
|
fn #items_trait_items(self) -> &'static _pyo3::impl_::pyclass::PyClassItems {
|
||||||
&[#(#tokens),*]
|
static ITEMS: _pyo3::impl_::pyclass::PyClassItems = _pyo3::impl_::pyclass::PyClassItems {
|
||||||
|
methods: &[#(#py_methods),*],
|
||||||
|
slots: &[#(#tokens),*]
|
||||||
|
};
|
||||||
|
&ITEMS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,12 @@ use crate::{
|
||||||
type_object::{PyLayout, PyTypeObject},
|
type_object::{PyLayout, PyTypeObject},
|
||||||
PyCell, PyClass, PyMethodDefType, PyNativeType, PyResult, PyTypeInfo, Python,
|
PyCell, PyClass, PyMethodDefType, PyNativeType, PyResult, PyTypeInfo, Python,
|
||||||
};
|
};
|
||||||
use std::{marker::PhantomData, os::raw::{c_int, c_void}, ptr::NonNull, thread};
|
use std::{
|
||||||
|
marker::PhantomData,
|
||||||
|
os::raw::{c_int, c_void},
|
||||||
|
ptr::NonNull,
|
||||||
|
thread,
|
||||||
|
};
|
||||||
|
|
||||||
/// Gets the offset of the dictionary from the start of the object in bytes.
|
/// Gets the offset of the dictionary from the start of the object in bytes.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -128,6 +133,14 @@ impl<T> Clone for PyClassImplCollector<T> {
|
||||||
|
|
||||||
impl<T> Copy for PyClassImplCollector<T> {}
|
impl<T> Copy for PyClassImplCollector<T> {}
|
||||||
|
|
||||||
|
pub struct PyClassItems {
|
||||||
|
pub methods: &'static [PyMethodDefType],
|
||||||
|
pub slots: &'static [ffi::PyType_Slot],
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow PyClassItems in statics
|
||||||
|
unsafe impl Sync for PyClassItems {}
|
||||||
|
|
||||||
/// Implements the underlying functionality of `#[pyclass]`, assembled by various proc macros.
|
/// Implements the underlying functionality of `#[pyclass]`, assembled by various proc macros.
|
||||||
///
|
///
|
||||||
/// Users are discouraged from implementing this trait manually; it is a PyO3 implementation detail
|
/// Users are discouraged from implementing this trait manually; it is a PyO3 implementation detail
|
||||||
|
@ -163,8 +176,7 @@ pub trait PyClassImpl: Sized {
|
||||||
#[cfg(feature = "multiple-pymethods")]
|
#[cfg(feature = "multiple-pymethods")]
|
||||||
type Inventory: PyClassInventory;
|
type Inventory: PyClassInventory;
|
||||||
|
|
||||||
fn for_each_method_def(_visitor: &mut dyn FnMut(&[PyMethodDefType])) {}
|
fn for_all_items(visitor: &mut dyn FnMut(&PyClassItems));
|
||||||
fn for_each_proto_slot(_visitor: &mut dyn FnMut(&[ffi::PyType_Slot])) {}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_new() -> Option<ffi::newfunc> {
|
fn get_new() -> Option<ffi::newfunc> {
|
||||||
|
@ -697,15 +709,18 @@ unsafe fn bpo_35810_workaround(_py: Python, ty: *mut ffi::PyTypeObject) {
|
||||||
// General methods implementation: either dtolnay specialization trait or inventory if
|
// General methods implementation: either dtolnay specialization trait or inventory if
|
||||||
// multiple-pymethods feature is enabled.
|
// multiple-pymethods feature is enabled.
|
||||||
|
|
||||||
macro_rules! methods_trait {
|
macro_rules! items_trait {
|
||||||
($name:ident, $function_name: ident) => {
|
($name:ident, $function_name: ident) => {
|
||||||
pub trait $name<T> {
|
pub trait $name<T> {
|
||||||
fn $function_name(self) -> &'static [PyMethodDefType];
|
fn $function_name(self) -> &'static PyClassItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> $name<T> for &'_ PyClassImplCollector<T> {
|
impl<T> $name<T> for &'_ PyClassImplCollector<T> {
|
||||||
fn $function_name(self) -> &'static [PyMethodDefType] {
|
fn $function_name(self) -> &'static PyClassItems {
|
||||||
&[]
|
&PyClassItems {
|
||||||
|
methods: &[],
|
||||||
|
slots: &[],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -717,62 +732,40 @@ macro_rules! methods_trait {
|
||||||
/// which are eventually collected by `#[pyclass]`.
|
/// which are eventually collected by `#[pyclass]`.
|
||||||
#[cfg(feature = "multiple-pymethods")]
|
#[cfg(feature = "multiple-pymethods")]
|
||||||
pub trait PyClassInventory: inventory::Collect {
|
pub trait PyClassInventory: inventory::Collect {
|
||||||
/// Returns the methods for a single `#[pymethods] impl` block
|
/// Returns the items for a single `#[pymethods] impl` block
|
||||||
fn methods(&'static self) -> &'static [PyMethodDefType];
|
fn items(&'static self) -> &'static PyClassItems;
|
||||||
|
|
||||||
/// Returns the slots for a single `#[pymethods] impl` block
|
|
||||||
fn slots(&'static self) -> &'static [ffi::PyType_Slot];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Methods from #[pyo3(get, set)] on struct fields.
|
// Methods from #[pyo3(get, set)] on struct fields.
|
||||||
methods_trait!(PyClassDescriptors, py_class_descriptors);
|
items_trait!(PyClassIntrinsicItems, pyclass_intrinsic_items);
|
||||||
|
|
||||||
// Methods from #[pymethods] if not using inventory.
|
// Items from #[pymethods] if not using inventory.
|
||||||
#[cfg(not(feature = "multiple-pymethods"))]
|
#[cfg(not(feature = "multiple-pymethods"))]
|
||||||
methods_trait!(PyMethods, py_methods);
|
items_trait!(PyMethods, py_methods);
|
||||||
|
|
||||||
// All traits describing slots, as well as the fallback implementations for unimplemented protos
|
/// Items from `#[pyproto]` implementations
|
||||||
//
|
#[cfg(feature = "pyproto")]
|
||||||
// Protos which are implemented use dtolnay specialization to implement for PyClassImplCollector<T>.
|
mod pyproto_traits {
|
||||||
//
|
use super::*;
|
||||||
// See https://github.com/dtolnay/case-studies/blob/master/autoref-specialization/README.md
|
items_trait!(PyObjectProtocolItems, object_protocol_items);
|
||||||
|
items_trait!(PyDescrProtocolItems, descr_protocol_items);
|
||||||
macro_rules! slots_trait {
|
items_trait!(PyGCProtocolItems, gc_protocol_items);
|
||||||
($name:ident, $function_name: ident) => {
|
items_trait!(PyIterProtocolItems, iter_protocol_items);
|
||||||
pub trait $name<T> {
|
items_trait!(PyMappingProtocolItems, mapping_protocol_items);
|
||||||
fn $function_name(self) -> &'static [ffi::PyType_Slot];
|
items_trait!(PyNumberProtocolItems, number_protocol_items);
|
||||||
}
|
items_trait!(PyAsyncProtocolItems, async_protocol_items);
|
||||||
|
items_trait!(PySequenceProtocolItems, sequence_protocol_items);
|
||||||
impl<T> $name<T> for &'_ PyClassImplCollector<T> {
|
items_trait!(PyBufferProtocolItems, buffer_protocol_items);
|
||||||
fn $function_name(self) -> &'static [ffi::PyType_Slot] {
|
|
||||||
&[]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "pyproto")]
|
||||||
|
pub use pyproto_traits::*;
|
||||||
|
|
||||||
slots_trait!(PyObjectProtocolSlots, object_protocol_slots);
|
// items that PyO3 implements by default, but can be overidden by the users.
|
||||||
slots_trait!(PyDescrProtocolSlots, descr_protocol_slots);
|
items_trait!(PyClassDefaultItems, pyclass_default_items);
|
||||||
slots_trait!(PyGCProtocolSlots, gc_protocol_slots);
|
|
||||||
slots_trait!(PyIterProtocolSlots, iter_protocol_slots);
|
|
||||||
slots_trait!(PyMappingProtocolSlots, mapping_protocol_slots);
|
|
||||||
slots_trait!(PyNumberProtocolSlots, number_protocol_slots);
|
|
||||||
slots_trait!(PyAsyncProtocolSlots, async_protocol_slots);
|
|
||||||
slots_trait!(PySequenceProtocolSlots, sequence_protocol_slots);
|
|
||||||
slots_trait!(PyBufferProtocolSlots, buffer_protocol_slots);
|
|
||||||
|
|
||||||
// slots that PyO3 implements by default, but can be overidden by the users.
|
|
||||||
slots_trait!(PyClassDefaultSlots, py_class_default_slots);
|
|
||||||
|
|
||||||
// Protocol slots from #[pymethods] if not using inventory.
|
// Protocol slots from #[pymethods] if not using inventory.
|
||||||
#[cfg(not(feature = "multiple-pymethods"))]
|
#[cfg(not(feature = "multiple-pymethods"))]
|
||||||
slots_trait!(PyMethodsProtocolSlots, methods_protocol_slots);
|
items_trait!(PyMethodsProtocolItems, methods_protocol_items);
|
||||||
|
|
||||||
methods_trait!(PyObjectProtocolMethods, object_protocol_methods);
|
|
||||||
methods_trait!(PyAsyncProtocolMethods, async_protocol_methods);
|
|
||||||
methods_trait!(PyDescrProtocolMethods, descr_protocol_methods);
|
|
||||||
methods_trait!(PyMappingProtocolMethods, mapping_protocol_methods);
|
|
||||||
methods_trait!(PyNumberProtocolMethods, number_protocol_methods);
|
|
||||||
|
|
||||||
// Thread checkers
|
// Thread checkers
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,10 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
callback::IntoPyCallbackOutput,
|
callback::IntoPyCallbackOutput,
|
||||||
ffi,
|
ffi,
|
||||||
impl_::pyclass::{assign_sequence_item_from_mapping, get_sequence_item_from_mapping, fallback_new, tp_dealloc, PyClassDict, PyClassImpl, PyClassWeakRef},
|
impl_::pyclass::{
|
||||||
|
assign_sequence_item_from_mapping, fallback_new, get_sequence_item_from_mapping,
|
||||||
|
tp_dealloc, PyClassDict, PyClassImpl, PyClassItems, PyClassWeakRef,
|
||||||
|
},
|
||||||
IntoPy, IntoPyPointer, PyCell, PyErr, PyMethodDefType, PyNativeType, PyObject, PyResult,
|
IntoPy, IntoPyPointer, PyCell, PyErr, PyMethodDefType, PyNativeType, PyObject, PyResult,
|
||||||
PyTypeInfo, Python,
|
PyTypeInfo, Python,
|
||||||
};
|
};
|
||||||
|
@ -52,8 +55,7 @@ where
|
||||||
T::get_free(),
|
T::get_free(),
|
||||||
T::dict_offset(),
|
T::dict_offset(),
|
||||||
T::weaklist_offset(),
|
T::weaklist_offset(),
|
||||||
&T::for_each_method_def,
|
&T::for_all_items,
|
||||||
&T::for_each_proto_slot,
|
|
||||||
T::IS_GC,
|
T::IS_GC,
|
||||||
T::IS_BASETYPE,
|
T::IS_BASETYPE,
|
||||||
)
|
)
|
||||||
|
@ -77,8 +79,7 @@ unsafe fn create_type_object_impl(
|
||||||
tp_free: Option<ffi::freefunc>,
|
tp_free: Option<ffi::freefunc>,
|
||||||
dict_offset: Option<ffi::Py_ssize_t>,
|
dict_offset: Option<ffi::Py_ssize_t>,
|
||||||
weaklist_offset: Option<ffi::Py_ssize_t>,
|
weaklist_offset: Option<ffi::Py_ssize_t>,
|
||||||
for_each_method_def: &dyn Fn(&mut dyn FnMut(&[PyMethodDefType])),
|
for_all_items: &dyn Fn(&mut dyn FnMut(&PyClassItems)),
|
||||||
for_each_proto_slot: &dyn Fn(&mut dyn FnMut(&[ffi::PyType_Slot])),
|
|
||||||
is_gc: bool,
|
is_gc: bool,
|
||||||
is_basetype: bool,
|
is_basetype: bool,
|
||||||
) -> PyResult<*mut ffi::PyTypeObject> {
|
) -> PyResult<*mut ffi::PyTypeObject> {
|
||||||
|
@ -118,7 +119,7 @@ unsafe fn create_type_object_impl(
|
||||||
let PyClassInfo {
|
let PyClassInfo {
|
||||||
method_defs,
|
method_defs,
|
||||||
property_defs,
|
property_defs,
|
||||||
} = method_defs_to_pyclass_info(for_each_method_def, dict_offset.is_none());
|
} = method_defs_to_pyclass_info(for_all_items, dict_offset.is_none());
|
||||||
|
|
||||||
// normal methods
|
// normal methods
|
||||||
if !method_defs.is_empty() {
|
if !method_defs.is_empty() {
|
||||||
|
@ -139,8 +140,8 @@ unsafe fn create_type_object_impl(
|
||||||
#[cfg(all(not(Py_3_9), not(Py_LIMITED_API)))]
|
#[cfg(all(not(Py_3_9), not(Py_LIMITED_API)))]
|
||||||
let mut buffer_procs: ffi::PyBufferProcs = Default::default();
|
let mut buffer_procs: ffi::PyBufferProcs = Default::default();
|
||||||
|
|
||||||
for_each_proto_slot(&mut |proto_slots| {
|
for_all_items(&mut |items| {
|
||||||
for slot in proto_slots {
|
for slot in items.slots {
|
||||||
has_getitem |= slot.slot == ffi::Py_mp_subscript;
|
has_getitem |= slot.slot == ffi::Py_mp_subscript;
|
||||||
has_setitem |= slot.slot == ffi::Py_mp_ass_subscript;
|
has_setitem |= slot.slot == ffi::Py_mp_ass_subscript;
|
||||||
has_gc_methods |= slot.slot == ffi::Py_tp_clear || slot.slot == ffi::Py_tp_traverse;
|
has_gc_methods |= slot.slot == ffi::Py_tp_clear || slot.slot == ffi::Py_tp_traverse;
|
||||||
|
@ -156,7 +157,7 @@ unsafe fn create_type_object_impl(
|
||||||
buffer_procs.bf_releasebuffer = Some(std::mem::transmute(slot.pfunc));
|
buffer_procs.bf_releasebuffer = Some(std::mem::transmute(slot.pfunc));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
slots.extend_from_slice(proto_slots);
|
slots.extend_from_slice(items.slots);
|
||||||
});
|
});
|
||||||
|
|
||||||
// If mapping methods implemented, define sequence methods get implemented too.
|
// If mapping methods implemented, define sequence methods get implemented too.
|
||||||
|
@ -320,14 +321,14 @@ struct PyClassInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn method_defs_to_pyclass_info(
|
fn method_defs_to_pyclass_info(
|
||||||
for_each_method_def: &dyn Fn(&mut dyn FnMut(&[PyMethodDefType])),
|
for_all_items: &dyn Fn(&mut dyn FnMut(&PyClassItems)),
|
||||||
has_dict: bool,
|
has_dict: bool,
|
||||||
) -> PyClassInfo {
|
) -> PyClassInfo {
|
||||||
let mut method_defs = Vec::new();
|
let mut method_defs = Vec::new();
|
||||||
let mut property_defs_map = std::collections::HashMap::new();
|
let mut property_defs_map = std::collections::HashMap::new();
|
||||||
|
|
||||||
for_each_method_def(&mut |class_method_defs| {
|
for_all_items(&mut |items| {
|
||||||
for def in class_method_defs {
|
for def in items.methods {
|
||||||
match def {
|
match def {
|
||||||
PyMethodDefType::Getter(getter) => {
|
PyMethodDefType::Getter(getter) => {
|
||||||
getter.copy_to(
|
getter.copy_to(
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||||
//! Python type object information
|
//! Python type object information
|
||||||
|
|
||||||
|
use crate::impl_::pyclass::PyClassItems;
|
||||||
use crate::internal_tricks::extract_cstr_or_leak_cstring;
|
use crate::internal_tricks::extract_cstr_or_leak_cstring;
|
||||||
use crate::once_cell::GILOnceCell;
|
use crate::once_cell::GILOnceCell;
|
||||||
use crate::pyclass::create_type_object;
|
use crate::pyclass::create_type_object;
|
||||||
|
@ -108,7 +109,7 @@ impl LazyStaticType {
|
||||||
|
|
||||||
pub fn get_or_init<T: PyClass>(&self, py: Python) -> *mut ffi::PyTypeObject {
|
pub fn get_or_init<T: PyClass>(&self, py: Python) -> *mut ffi::PyTypeObject {
|
||||||
let type_object = *self.value.get_or_init(py, || create_type_object::<T>(py));
|
let type_object = *self.value.get_or_init(py, || create_type_object::<T>(py));
|
||||||
self.ensure_init(py, type_object, T::NAME, &T::for_each_method_def);
|
self.ensure_init(py, type_object, T::NAME, &T::for_all_items);
|
||||||
type_object
|
type_object
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +118,7 @@ impl LazyStaticType {
|
||||||
py: Python,
|
py: Python,
|
||||||
type_object: *mut ffi::PyTypeObject,
|
type_object: *mut ffi::PyTypeObject,
|
||||||
name: &str,
|
name: &str,
|
||||||
for_each_method_def: &dyn Fn(&mut dyn FnMut(&[PyMethodDefType])),
|
for_all_items: &dyn Fn(&mut dyn FnMut(&PyClassItems)),
|
||||||
) {
|
) {
|
||||||
// We might want to fill the `tp_dict` with python instances of `T`
|
// We might want to fill the `tp_dict` with python instances of `T`
|
||||||
// itself. In order to do so, we must first initialize the type object
|
// itself. In order to do so, we must first initialize the type object
|
||||||
|
@ -151,8 +152,8 @@ impl LazyStaticType {
|
||||||
// means that another thread can continue the initialization in the
|
// means that another thread can continue the initialization in the
|
||||||
// meantime: at worst, we'll just make a useless computation.
|
// meantime: at worst, we'll just make a useless computation.
|
||||||
let mut items = vec![];
|
let mut items = vec![];
|
||||||
for_each_method_def(&mut |method_defs| {
|
for_all_items(&mut |class_items| {
|
||||||
items.extend(method_defs.iter().filter_map(|def| {
|
items.extend(class_items.methods.iter().filter_map(|def| {
|
||||||
if let PyMethodDefType::ClassAttribute(attr) = def {
|
if let PyMethodDefType::ClassAttribute(attr) = def {
|
||||||
let key = extract_cstr_or_leak_cstring(
|
let key = extract_cstr_or_leak_cstring(
|
||||||
attr.name,
|
attr.name,
|
||||||
|
|
|
@ -56,6 +56,7 @@ struct Iter {
|
||||||
|
|
||||||
#[pymethods]
|
#[pymethods]
|
||||||
impl Iter {
|
impl Iter {
|
||||||
|
#[allow(clippy::self_named_constructors)]
|
||||||
fn __iter__(slf: PyRef<Self>) -> PyRef<Self> {
|
fn __iter__(slf: PyRef<Self>) -> PyRef<Self> {
|
||||||
slf
|
slf
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue