refactor: pass tp_alloc and tp_free via slots

This commit is contained in:
David Hewitt 2022-02-08 21:55:21 +00:00
parent 4d471077b4
commit 75e44585de
5 changed files with 55 additions and 103 deletions

View file

@ -986,16 +986,6 @@ impl pyo3::impl_::pyclass::PyClassImpl for MyClass {
let collector = PyClassImplCollector::<Self>::new();
collector.new_impl()
}
fn get_alloc() -> Option<pyo3::ffi::allocfunc> {
use pyo3::impl_::pyclass::*;
let collector = PyClassImplCollector::<Self>::new();
collector.alloc_impl()
}
fn get_free() -> Option<pyo3::ffi::freefunc> {
use pyo3::impl_::pyclass::*;
let collector = PyClassImplCollector::<Self>::new();
collector.free_impl()
}
}
# Python::with_gil(|py| {
# let cls = py.get_type::<MyClass>();

View file

@ -387,6 +387,7 @@ fn impl_class(
attr,
methods_type,
descriptors_to_items(cls, field_options)?,
vec![],
)
.doc(doc)
.impl_all();
@ -582,7 +583,8 @@ fn impl_enum_class(
cls,
args,
methods_type,
enum_default_items(cls, variants.iter().map(|v| v.ident), &mut default_methods),
enum_default_methods(cls, variants.iter().map(|v| v.ident)),
enum_default_slots(cls, &mut default_methods),
)
.doc(doc)
.impl_all();
@ -602,11 +604,10 @@ fn impl_enum_class(
})
}
fn enum_default_items<'a>(
fn enum_default_methods<'a>(
cls: &'a syn::Ident,
unit_variant_names: impl IntoIterator<Item = &'a syn::Ident>,
default_items: &mut [syn::ImplItemMethod],
) -> TokenStream {
) -> Vec<TokenStream> {
let cls_type = syn::parse_quote!(#cls);
let variant_to_attribute = |ident: &syn::Ident| ConstSpec {
rust_ident: ident.clone(),
@ -616,18 +617,17 @@ fn enum_default_items<'a>(
deprecations: Default::default(),
},
};
let py_methods = unit_variant_names
unit_variant_names
.into_iter()
.map(|var| gen_py_const(&cls_type, &variant_to_attribute(var)));
.map(|var| gen_py_const(&cls_type, &variant_to_attribute(var)))
.collect()
}
let slots = gen_default_items(cls, default_items);
quote! {
_pyo3::impl_::pyclass::PyClassItems {
methods: &[#(#py_methods),*],
slots: &[#(#slots),*]
}
}
fn enum_default_slots(
cls: &syn::Ident,
default_items: &mut [syn::ImplItemMethod],
) -> Vec<TokenStream> {
gen_default_items(cls, default_items).collect()
}
fn extract_variant_data(variant: &syn::Variant) -> syn::Result<PyClassEnumVariant> {
@ -642,9 +642,9 @@ fn extract_variant_data(variant: &syn::Variant) -> syn::Result<PyClassEnumVarian
fn descriptors_to_items(
cls: &syn::Ident,
field_options: Vec<(&syn::Field, FieldPyO3Options)>,
) -> syn::Result<TokenStream> {
) -> syn::Result<Vec<TokenStream>> {
let ty = syn::parse_quote!(#cls);
let py_methods: Vec<TokenStream> = field_options
field_options
.into_iter()
.enumerate()
.flat_map(|(field_index, (field, options))| {
@ -676,14 +676,7 @@ fn descriptors_to_items(
name_err.into_iter().chain(getter).chain(setter)
})
.collect::<syn::Result<_>>()?;
Ok(quote! {
_pyo3::impl_::pyclass::PyClassItems {
methods: &[#(#py_methods),*],
slots: &[]
}
})
.collect::<syn::Result<_>>()
}
fn impl_pytypeinfo(
@ -727,7 +720,8 @@ struct PyClassImplsBuilder<'a> {
cls: &'a syn::Ident,
attr: &'a PyClassArgs,
methods_type: PyClassMethodsType,
default_items: TokenStream,
default_methods: Vec<TokenStream>,
default_slots: Vec<TokenStream>,
doc: Option<PythonDoc>,
}
@ -736,13 +730,15 @@ impl<'a> PyClassImplsBuilder<'a> {
cls: &'a syn::Ident,
attr: &'a PyClassArgs,
methods_type: PyClassMethodsType,
default_items: TokenStream,
default_methods: Vec<TokenStream>,
default_slots: Vec<TokenStream>,
) -> Self {
Self {
cls,
attr,
methods_type,
default_items,
default_methods,
default_slots,
doc: None,
}
}
@ -904,7 +900,9 @@ impl<'a> PyClassImplsBuilder<'a> {
None
};
let default_items = &self.default_items;
let default_methods = &self.default_methods;
let default_slots = &self.default_slots;
let freelist_slots = self.freelist_slots();
quote! {
impl _pyo3::impl_::pyclass::PyClassImpl for #cls {
@ -921,7 +919,10 @@ impl<'a> PyClassImplsBuilder<'a> {
fn for_all_items(visitor: &mut dyn ::std::ops::FnMut(& _pyo3::impl_::pyclass::PyClassItems)) {
use _pyo3::impl_::pyclass::*;
let collector = PyClassImplCollector::<Self>::new();
static INTRINSIC_ITEMS: PyClassItems = #default_items;
static INTRINSIC_ITEMS: PyClassItems = PyClassItems {
methods: &[#(#default_methods),*],
slots: &[#(#default_slots),* #(#freelist_slots),*],
};
visitor(&INTRINSIC_ITEMS);
#pymethods_items
#pyproto_items
@ -931,16 +932,6 @@ impl<'a> PyClassImplsBuilder<'a> {
let collector = PyClassImplCollector::<Self>::new();
collector.new_impl()
}
fn get_alloc() -> ::std::option::Option<_pyo3::ffi::allocfunc> {
use _pyo3::impl_::pyclass::*;
let collector = PyClassImplCollector::<Self>::new();
collector.alloc_impl()
}
fn get_free() -> ::std::option::Option<_pyo3::ffi::freefunc> {
use _pyo3::impl_::pyclass::*;
let collector = PyClassImplCollector::<Self>::new();
collector.free_impl()
}
#dict_offset
@ -969,23 +960,33 @@ impl<'a> PyClassImplsBuilder<'a> {
}
}
}
impl _pyo3::impl_::pyclass::PyClassAllocImpl<#cls> for _pyo3::impl_::pyclass::PyClassImplCollector<#cls> {
#[inline]
fn alloc_impl(self) -> ::std::option::Option<_pyo3::ffi::allocfunc> {
::std::option::Option::Some(_pyo3::impl_::pyclass::alloc_with_freelist::<#cls>)
}
}
impl _pyo3::impl_::pyclass::PyClassFreeImpl<#cls> for _pyo3::impl_::pyclass::PyClassImplCollector<#cls> {
#[inline]
fn free_impl(self) -> ::std::option::Option<_pyo3::ffi::freefunc> {
::std::option::Option::Some(_pyo3::impl_::pyclass::free_with_freelist::<#cls>)
}
}
}
})
}
fn freelist_slots(&self) -> Vec<TokenStream> {
let cls = self.cls;
if self.attr.freelist.is_some() {
vec![
quote! {
_pyo3::ffi::PyType_Slot {
slot: _pyo3::ffi::Py_tp_alloc,
pfunc: _pyo3::impl_::pyclass::alloc_with_freelist::<#cls> as *mut _,
}
},
quote! {
_pyo3::ffi::PyType_Slot {
slot: _pyo3::ffi::Py_tp_free,
pfunc: _pyo3::impl_::pyclass::free_with_freelist::<#cls> as *mut _,
}
},
]
} else {
Vec::new()
}
}
/// Enforce at compile time that PyGCProtocol is implemented
fn impl_gc(&self) -> TokenStream {
let cls = self.cls;

View file

@ -194,7 +194,7 @@ pub fn gen_default_items<'a>(
// all succeed.
let ty: syn::Type = syn::parse_quote!(#cls);
method_defs.into_iter().map(move |meth| {
method_defs.iter_mut().map(move |meth| {
let options = PyFunctionOptions::from_attrs(&mut meth.attrs).unwrap();
match pymethod::gen_py_method(&ty, &mut meth.sig, &mut meth.attrs, options).unwrap() {
GeneratedPyMethod::Proto(token_stream) => {

View file

@ -183,14 +183,6 @@ pub trait PyClassImpl: Sized {
None
}
#[inline]
fn get_alloc() -> Option<ffi::allocfunc> {
None
}
#[inline]
fn get_free() -> Option<ffi::freefunc> {
None
}
#[inline]
fn dict_offset() -> Option<ffi::Py_ssize_t> {
None
}
@ -602,26 +594,6 @@ macro_rules! generate_pyclass_pow_slot {
}
pub use generate_pyclass_pow_slot;
pub trait PyClassAllocImpl<T> {
fn alloc_impl(self) -> Option<ffi::allocfunc>;
}
impl<T> PyClassAllocImpl<T> for &'_ PyClassImplCollector<T> {
fn alloc_impl(self) -> Option<ffi::allocfunc> {
None
}
}
pub trait PyClassFreeImpl<T> {
fn free_impl(self) -> Option<ffi::freefunc>;
}
impl<T> PyClassFreeImpl<T> for &'_ PyClassImplCollector<T> {
fn free_impl(self) -> Option<ffi::freefunc> {
None
}
}
/// Implements a freelist.
///
/// Do not implement this trait manually. Instead, use `#[pyclass(freelist = N)]`

View file

@ -51,8 +51,6 @@ where
std::mem::size_of::<T::Layout>(),
T::get_new(),
tp_dealloc::<T>,
T::get_alloc(),
T::get_free(),
T::dict_offset(),
T::weaklist_offset(),
&T::for_all_items,
@ -75,8 +73,6 @@ unsafe fn create_type_object_impl(
basicsize: usize,
tp_new: Option<ffi::newfunc>,
tp_dealloc: ffi::destructor,
tp_alloc: Option<ffi::allocfunc>,
tp_free: Option<ffi::freefunc>,
dict_offset: Option<ffi::Py_ssize_t>,
weaklist_offset: Option<ffi::Py_ssize_t>,
for_all_items: &dyn Fn(&mut dyn FnMut(&PyClassItems)),
@ -101,13 +97,6 @@ unsafe fn create_type_object_impl(
);
push_slot(&mut slots, ffi::Py_tp_dealloc, tp_dealloc as _);
if let Some(alloc) = tp_alloc {
push_slot(&mut slots, ffi::Py_tp_alloc, alloc as _);
}
if let Some(free) = tp_free {
push_slot(&mut slots, ffi::Py_tp_free, free as _);
}
#[cfg(Py_3_9)]
{
let members = py_class_members(dict_offset, weaklist_offset);