Skip to content

Commit ecfd2c2

Browse files
committed
pyclass: simplify generated code for PyClassImpl
1 parent 558549e commit ecfd2c2

File tree

9 files changed

+160
-271
lines changed

9 files changed

+160
-271
lines changed

guide/src/class.md

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -858,16 +858,11 @@ impl pyo3::impl_::pyclass::PyClassImpl for MyClass {
858858
type BaseType = PyAny;
859859
type ThreadChecker = pyo3::impl_::pyclass::ThreadCheckerStub<MyClass>;
860860

861-
fn for_each_method_def(visitor: &mut dyn FnMut(&[pyo3::class::PyMethodDefType])) {
861+
fn for_all_items(visitor: &mut dyn FnMut(&pyo3::impl_::pyclass::PyClassItems)) {
862862
use pyo3::impl_::pyclass::*;
863863
let collector = PyClassImplCollector::<MyClass>::new();
864864
visitor(collector.py_methods());
865-
visitor(collector.py_class_descriptors());
866-
visitor(collector.object_protocol_methods());
867-
visitor(collector.async_protocol_methods());
868-
visitor(collector.descr_protocol_methods());
869-
visitor(collector.mapping_protocol_methods());
870-
visitor(collector.number_protocol_methods());
865+
visitor(collector.pyclass_intrinsic_items());
871866
}
872867
fn get_new() -> Option<pyo3::ffi::newfunc> {
873868
use pyo3::impl_::pyclass::*;
@@ -884,21 +879,6 @@ impl pyo3::impl_::pyclass::PyClassImpl for MyClass {
884879
let collector = PyClassImplCollector::<Self>::new();
885880
collector.free_impl()
886881
}
887-
fn for_each_proto_slot(visitor: &mut dyn FnMut(&[pyo3::ffi::PyType_Slot])) {
888-
// Implementation which uses dtolnay specialization to load all slots.
889-
use pyo3::impl_::pyclass::*;
890-
let collector = PyClassImplCollector::<Self>::new();
891-
visitor(collector.object_protocol_slots());
892-
visitor(collector.number_protocol_slots());
893-
visitor(collector.iter_protocol_slots());
894-
visitor(collector.gc_protocol_slots());
895-
visitor(collector.descr_protocol_slots());
896-
visitor(collector.mapping_protocol_slots());
897-
visitor(collector.sequence_protocol_slots());
898-
visitor(collector.async_protocol_slots());
899-
visitor(collector.buffer_protocol_slots());
900-
visitor(collector.methods_protocol_slots());
901-
}
902882
}
903883
# Python::with_gil(|py| {
904884
# let cls = py.get_type::<MyClass>();

pyo3-macros-backend/src/defs.rs

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -64,27 +64,13 @@ impl Proto {
6464
})
6565
}
6666

67-
pub(crate) fn slots_trait(&self) -> syn::Ident {
68-
syn::Ident::new(&format!("Py{}ProtocolSlots", self.name), Span::call_site())
67+
pub(crate) fn items_trait(&self) -> syn::Ident {
68+
syn::Ident::new(&format!("Py{}ProtocolItems", self.name), Span::call_site())
6969
}
7070

71-
pub(crate) fn slots_trait_slots(&self) -> syn::Ident {
71+
pub(crate) fn items_trait_items(&self) -> syn::Ident {
7272
syn::Ident::new(
73-
&format!("{}_protocol_slots", self.name.to_ascii_lowercase()),
74-
Span::call_site(),
75-
)
76-
}
77-
78-
pub(crate) fn methods_trait(&self) -> syn::Ident {
79-
syn::Ident::new(
80-
&format!("Py{}ProtocolMethods", self.name),
81-
Span::call_site(),
82-
)
83-
}
84-
85-
pub(crate) fn methods_trait_methods(&self) -> syn::Ident {
86-
syn::Ident::new(
87-
&format!("{}_protocol_methods", self.name.to_ascii_lowercase()),
73+
&format!("{}_protocol_items", self.name.to_ascii_lowercase()),
8874
Span::call_site(),
8975
)
9076
}

pyo3-macros-backend/src/pyclass.rs

Lines changed: 43 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::attributes::{
55
};
66
use crate::deprecations::Deprecations;
77
use crate::konst::{ConstAttributes, ConstSpec};
8-
use crate::pyimpl::{gen_default_slot_impls, gen_py_const, PyClassMethodsType};
8+
use crate::pyimpl::{gen_default_items, gen_py_const, PyClassMethodsType};
99
use crate::pymethod::{impl_py_getter_def, impl_py_setter_def, PropertyType};
1010
use crate::utils::{self, get_pyo3_crate, unwrap_group, PythonDoc};
1111
use proc_macro2::{Span, TokenStream};
@@ -477,7 +477,7 @@ fn impl_enum_class(
477477
}
478478
};
479479

480-
let default_impls = gen_default_slot_impls(cls, vec![default_repr_impl]);
480+
let default_impls = gen_default_items(cls, vec![default_repr_impl]);
481481
Ok(quote! {
482482
const _: () = {
483483
use #krate as _pyo3;
@@ -511,12 +511,15 @@ fn unit_variants_as_descriptors<'a>(
511511
.map(|var| gen_py_const(&cls_type, &variant_to_attribute(var)));
512512

513513
quote! {
514-
impl _pyo3::impl_::pyclass::PyClassDescriptors<#cls>
514+
impl _pyo3::impl_::pyclass::PyClassIntrinsicItems<#cls>
515515
for _pyo3::impl_::pyclass::PyClassImplCollector<#cls>
516516
{
517-
fn py_class_descriptors(self) -> &'static [_pyo3::impl_::pymethods::PyMethodDefType] {
518-
static METHODS: &[_pyo3::impl_::pymethods::PyMethodDefType] = &[#(#py_methods),*];
519-
METHODS
517+
fn pyclass_intrinsic_items(self) -> &'static _pyo3::impl_::pyclass::PyClassItems {
518+
static ITEMS: _pyo3::impl_::pyclass::PyClassItems = _pyo3::impl_::pyclass::PyClassItems {
519+
methods: &[#(#py_methods),*],
520+
slots: &[]
521+
};
522+
&ITEMS
520523
}
521524
}
522525
}
@@ -574,12 +577,15 @@ fn impl_descriptors(
574577
.collect::<syn::Result<_>>()?;
575578

576579
Ok(quote! {
577-
impl _pyo3::impl_::pyclass::PyClassDescriptors<#cls>
580+
impl _pyo3::impl_::pyclass::PyClassIntrinsicItems<#cls>
578581
for _pyo3::impl_::pyclass::PyClassImplCollector<#cls>
579582
{
580-
fn py_class_descriptors(self) -> &'static [_pyo3::impl_::pymethods::PyMethodDefType] {
581-
static METHODS: &[_pyo3::impl_::pymethods::PyMethodDefType] = &[#(#py_methods),*];
582-
METHODS
583+
fn pyclass_intrinsic_items(self) -> &'static _pyo3::impl_::pyclass::PyClassItems {
584+
static ITEMS: _pyo3::impl_::pyclass::PyClassItems = _pyo3::impl_::pyclass::PyClassItems {
585+
methods: &[#(#py_methods),*],
586+
slots: &[]
587+
};
588+
&ITEMS
583589
}
584590
}
585591
})
@@ -758,15 +764,10 @@ impl<'a> PyClassImplsBuilder<'a> {
758764
quote! { _pyo3::impl_::pyclass::ThreadCheckerStub<#cls> }
759765
};
760766

761-
let (for_each_py_method, methods_protos, inventory, inventory_class) = match self
762-
.methods_type
763-
{
764-
PyClassMethodsType::Specialization => (
765-
quote! { visitor(collector.py_methods()); },
766-
quote! { visitor(collector.methods_protocol_slots()); },
767-
None,
768-
None,
769-
),
767+
let (pymethods_items, inventory, inventory_class) = match self.methods_type {
768+
PyClassMethodsType::Specialization => {
769+
(quote! { visitor(collector.py_methods()); }, None, None)
770+
}
770771
PyClassMethodsType::Inventory => {
771772
// To allow multiple #[pymethods] block, we define inventory types.
772773
let inventory_class_name = syn::Ident::new(
@@ -776,12 +777,7 @@ impl<'a> PyClassImplsBuilder<'a> {
776777
(
777778
quote! {
778779
for inventory in _pyo3::inventory::iter::<<Self as _pyo3::impl_::pyclass::PyClassImpl>::Inventory>() {
779-
visitor(_pyo3::impl_::pyclass::PyClassInventory::methods(inventory));
780-
}
781-
},
782-
quote! {
783-
for inventory in _pyo3::inventory::iter::<<Self as _pyo3::impl_::pyclass::PyClassImpl>::Inventory>() {
784-
visitor(_pyo3::impl_::pyclass::PyClassInventory::slots(inventory));
780+
visitor(_pyo3::impl_::pyclass::PyClassInventory::items(inventory));
785781
}
786782
},
787783
Some(quote! { type Inventory = #inventory_class_name; }),
@@ -790,29 +786,17 @@ impl<'a> PyClassImplsBuilder<'a> {
790786
}
791787
};
792788

793-
let pyproto_method_visitors = if cfg!(feature = "pyproto") {
789+
let pyproto_items = if cfg!(feature = "pyproto") {
794790
Some(quote! {
795-
visitor(collector.object_protocol_methods());
796-
visitor(collector.async_protocol_methods());
797-
visitor(collector.descr_protocol_methods());
798-
visitor(collector.mapping_protocol_methods());
799-
visitor(collector.number_protocol_methods());
800-
})
801-
} else {
802-
None
803-
};
804-
805-
let pyproto_proto_visitors = if cfg!(feature = "pyproto") {
806-
Some(quote! {
807-
visitor(collector.object_protocol_slots());
808-
visitor(collector.number_protocol_slots());
809-
visitor(collector.iter_protocol_slots());
810-
visitor(collector.gc_protocol_slots());
811-
visitor(collector.descr_protocol_slots());
812-
visitor(collector.mapping_protocol_slots());
813-
visitor(collector.sequence_protocol_slots());
814-
visitor(collector.async_protocol_slots());
815-
visitor(collector.buffer_protocol_slots());
791+
visitor(collector.object_protocol_items());
792+
visitor(collector.number_protocol_items());
793+
visitor(collector.iter_protocol_items());
794+
visitor(collector.gc_protocol_items());
795+
visitor(collector.descr_protocol_items());
796+
visitor(collector.mapping_protocol_items());
797+
visitor(collector.sequence_protocol_items());
798+
visitor(collector.async_protocol_items());
799+
visitor(collector.buffer_protocol_items());
816800
})
817801
} else {
818802
None
@@ -830,12 +814,15 @@ impl<'a> PyClassImplsBuilder<'a> {
830814
type ThreadChecker = #thread_checker;
831815
#inventory
832816

833-
fn for_each_method_def(visitor: &mut dyn ::std::ops::FnMut(&[_pyo3::class::PyMethodDefType])) {
817+
fn for_all_items(visitor: &mut dyn ::std::ops::FnMut(& _pyo3::impl_::pyclass::PyClassItems)) {
834818
use _pyo3::impl_::pyclass::*;
835819
let collector = PyClassImplCollector::<Self>::new();
836-
#for_each_py_method;
837-
visitor(collector.py_class_descriptors());
838-
#pyproto_method_visitors
820+
visitor(collector.pyclass_intrinsic_items());
821+
// This depends on Python implementation detail;
822+
// an old slot entry will be overriden by newer ones.
823+
visitor(collector.pyclass_default_items());
824+
#pymethods_items
825+
#pyproto_items
839826
}
840827
fn get_new() -> ::std::option::Option<_pyo3::ffi::newfunc> {
841828
use _pyo3::impl_::pyclass::*;
@@ -853,17 +840,6 @@ impl<'a> PyClassImplsBuilder<'a> {
853840
collector.free_impl()
854841
}
855842

856-
fn for_each_proto_slot(visitor: &mut dyn ::std::ops::FnMut(&[_pyo3::ffi::PyType_Slot])) {
857-
// Implementation which uses dtolnay specialization to load all slots.
858-
use _pyo3::impl_::pyclass::*;
859-
let collector = PyClassImplCollector::<Self>::new();
860-
// This depends on Python implementation detail;
861-
// an old slot entry will be overriden by newer ones.
862-
visitor(collector.py_class_default_slots());
863-
#pyproto_proto_visitors
864-
#methods_protos
865-
}
866-
867843
#dict_offset
868844

869845
#weaklist_offset
@@ -933,31 +909,20 @@ fn define_inventory_class(inventory_class_name: &syn::Ident) -> TokenStream {
933909
quote! {
934910
#[doc(hidden)]
935911
pub struct #inventory_class_name {
936-
methods: &'static [_pyo3::class::PyMethodDefType],
937-
slots: &'static [_pyo3::ffi::PyType_Slot],
912+
items: _pyo3::impl_::pyclass::PyClassItems,
938913
}
939914
impl #inventory_class_name {
940-
const fn new(
941-
methods: &'static [_pyo3::class::PyMethodDefType],
942-
slots: &'static [_pyo3::ffi::PyType_Slot],
943-
) -> Self {
944-
Self { methods, slots }
915+
const fn new(items: _pyo3::impl_::pyclass::PyClassItems) -> Self {
916+
Self { items }
945917
}
946918
}
947919

948920
impl _pyo3::impl_::pyclass::PyClassInventory for #inventory_class_name {
949-
fn methods(&'static self) -> &'static [_pyo3::class::PyMethodDefType] {
950-
self.methods
951-
}
952-
fn slots(&'static self) -> &'static [_pyo3::ffi::PyType_Slot] {
953-
self.slots
921+
fn items(&self) -> &_pyo3::impl_::pyclass::PyClassItems {
922+
&self.items
954923
}
955924
}
956925

957-
// inventory requires these bounds
958-
unsafe impl ::std::marker::Send for #inventory_class_name {}
959-
unsafe impl ::std::marker::Sync for #inventory_class_name {}
960-
961926
_pyo3::inventory::collect!(#inventory_class_name);
962927
}
963928
}

0 commit comments

Comments
 (0)