macros: emit pymethod associated methods as a single block
This commit is contained in:
parent
197871245c
commit
f81a01b604
|
@ -7,7 +7,7 @@ use crate::deprecations::Deprecation;
|
|||
use crate::params::{accept_args_kwargs, impl_arg_params};
|
||||
use crate::pyfunction::PyFunctionOptions;
|
||||
use crate::pyfunction::{PyFunctionArgPyO3Attributes, PyFunctionSignature};
|
||||
use crate::utils::{self, get_pyo3_crate, PythonDoc};
|
||||
use crate::utils::{self, PythonDoc};
|
||||
use crate::{deprecations::Deprecations, pyfunction::Argument};
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::ToTokens;
|
||||
|
@ -224,7 +224,6 @@ pub struct FnSpec<'a> {
|
|||
pub deprecations: Deprecations,
|
||||
pub convention: CallingConvention,
|
||||
pub text_signature: Option<TextSignatureAttribute>,
|
||||
pub krate: syn::Path,
|
||||
pub unsafety: Option<syn::Token![unsafe]>,
|
||||
}
|
||||
|
||||
|
@ -266,7 +265,6 @@ impl<'a> FnSpec<'a> {
|
|||
) -> Result<FnSpec<'a>> {
|
||||
let PyFunctionOptions {
|
||||
text_signature,
|
||||
krate,
|
||||
name,
|
||||
mut deprecations,
|
||||
..
|
||||
|
@ -285,7 +283,6 @@ impl<'a> FnSpec<'a> {
|
|||
let name = &sig.ident;
|
||||
let ty = get_return_info(&sig.output);
|
||||
let python_name = python_name.as_ref().unwrap_or(name).unraw();
|
||||
let krate = get_pyo3_crate(&krate);
|
||||
|
||||
let doc = utils::get_doc(
|
||||
meth_attrs,
|
||||
|
@ -321,7 +318,6 @@ impl<'a> FnSpec<'a> {
|
|||
doc,
|
||||
deprecations,
|
||||
text_signature,
|
||||
krate,
|
||||
unsafety: sig.unsafety,
|
||||
})
|
||||
}
|
||||
|
@ -489,16 +485,14 @@ impl<'a> FnSpec<'a> {
|
|||
_pyo3::callback::convert(#py, ret)
|
||||
};
|
||||
|
||||
let krate = &self.krate;
|
||||
Ok(match self.convention {
|
||||
CallingConvention::Noargs => {
|
||||
quote! {
|
||||
unsafe extern "C" fn #ident (
|
||||
_slf: *mut #krate::ffi::PyObject,
|
||||
_args: *mut #krate::ffi::PyObject,
|
||||
) -> *mut #krate::ffi::PyObject
|
||||
_slf: *mut _pyo3::ffi::PyObject,
|
||||
_args: *mut _pyo3::ffi::PyObject,
|
||||
) -> *mut _pyo3::ffi::PyObject
|
||||
{
|
||||
use #krate as _pyo3;
|
||||
#deprecations
|
||||
let gil = _pyo3::GILPool::new();
|
||||
let #py = gil.python();
|
||||
|
@ -513,12 +507,11 @@ impl<'a> FnSpec<'a> {
|
|||
let arg_convert = impl_arg_params(self, cls, &py, true)?;
|
||||
quote! {
|
||||
unsafe extern "C" fn #ident (
|
||||
_slf: *mut #krate::ffi::PyObject,
|
||||
_args: *const *mut #krate::ffi::PyObject,
|
||||
_nargs: #krate::ffi::Py_ssize_t,
|
||||
_kwnames: *mut #krate::ffi::PyObject) -> *mut #krate::ffi::PyObject
|
||||
_slf: *mut _pyo3::ffi::PyObject,
|
||||
_args: *const *mut _pyo3::ffi::PyObject,
|
||||
_nargs: _pyo3::ffi::Py_ssize_t,
|
||||
_kwnames: *mut _pyo3::ffi::PyObject) -> *mut _pyo3::ffi::PyObject
|
||||
{
|
||||
use #krate as _pyo3;
|
||||
#deprecations
|
||||
let gil = _pyo3::GILPool::new();
|
||||
let #py = gil.python();
|
||||
|
@ -534,11 +527,10 @@ impl<'a> FnSpec<'a> {
|
|||
let arg_convert = impl_arg_params(self, cls, &py, false)?;
|
||||
quote! {
|
||||
unsafe extern "C" fn #ident (
|
||||
_slf: *mut #krate::ffi::PyObject,
|
||||
_args: *mut #krate::ffi::PyObject,
|
||||
_kwargs: *mut #krate::ffi::PyObject) -> *mut #krate::ffi::PyObject
|
||||
_slf: *mut _pyo3::ffi::PyObject,
|
||||
_args: *mut _pyo3::ffi::PyObject,
|
||||
_kwargs: *mut _pyo3::ffi::PyObject) -> *mut _pyo3::ffi::PyObject
|
||||
{
|
||||
use #krate as _pyo3;
|
||||
#deprecations
|
||||
let gil = _pyo3::GILPool::new();
|
||||
let #py = gil.python();
|
||||
|
@ -555,11 +547,10 @@ impl<'a> FnSpec<'a> {
|
|||
let arg_convert = impl_arg_params(self, cls, &py, false)?;
|
||||
quote! {
|
||||
unsafe extern "C" fn #ident (
|
||||
subtype: *mut #krate::ffi::PyTypeObject,
|
||||
_args: *mut #krate::ffi::PyObject,
|
||||
_kwargs: *mut #krate::ffi::PyObject) -> *mut #krate::ffi::PyObject
|
||||
subtype: *mut _pyo3::ffi::PyTypeObject,
|
||||
_args: *mut _pyo3::ffi::PyObject,
|
||||
_kwargs: *mut _pyo3::ffi::PyObject) -> *mut _pyo3::ffi::PyObject
|
||||
{
|
||||
use #krate as _pyo3;
|
||||
#deprecations
|
||||
use _pyo3::callback::IntoPyCallbackOutput;
|
||||
let gil = _pyo3::GILPool::new();
|
||||
|
|
|
@ -11,7 +11,8 @@ use crate::konst::{ConstAttributes, ConstSpec};
|
|||
use crate::method::FnSpec;
|
||||
use crate::pyimpl::{gen_py_const, PyClassMethodsType};
|
||||
use crate::pymethod::{
|
||||
impl_py_getter_def, impl_py_setter_def, PropertyType, SlotDef, __INT__, __REPR__, __RICHCMP__,
|
||||
impl_py_getter_def, impl_py_setter_def, MethodAndMethodDef, MethodAndSlotDef, PropertyType,
|
||||
SlotDef, __INT__, __REPR__, __RICHCMP__,
|
||||
};
|
||||
use crate::utils::{self, get_pyo3_crate, PythonDoc};
|
||||
use crate::PyFunctionOptions;
|
||||
|
@ -539,7 +540,7 @@ fn generate_default_protocol_slot(
|
|||
cls: &syn::Type,
|
||||
method: &mut syn::ImplItemMethod,
|
||||
slot: &SlotDef,
|
||||
) -> syn::Result<TokenStream> {
|
||||
) -> syn::Result<MethodAndSlotDef> {
|
||||
let spec = FnSpec::parse(
|
||||
&mut method.sig,
|
||||
&mut Vec::new(),
|
||||
|
@ -557,7 +558,7 @@ fn generate_default_protocol_slot(
|
|||
fn enum_default_methods<'a>(
|
||||
cls: &'a syn::Ident,
|
||||
unit_variant_names: impl IntoIterator<Item = &'a syn::Ident>,
|
||||
) -> Vec<TokenStream> {
|
||||
) -> Vec<MethodAndMethodDef> {
|
||||
let cls_type = syn::parse_quote!(#cls);
|
||||
let variant_to_attribute = |ident: &syn::Ident| ConstSpec {
|
||||
rust_ident: ident.clone(),
|
||||
|
@ -588,7 +589,7 @@ 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<Vec<TokenStream>> {
|
||||
) -> syn::Result<Vec<MethodAndMethodDef>> {
|
||||
let ty = syn::parse_quote!(#cls);
|
||||
field_options
|
||||
.into_iter()
|
||||
|
@ -666,8 +667,8 @@ struct PyClassImplsBuilder<'a> {
|
|||
cls: &'a syn::Ident,
|
||||
attr: &'a PyClassArgs,
|
||||
methods_type: PyClassMethodsType,
|
||||
default_methods: Vec<TokenStream>,
|
||||
default_slots: Vec<TokenStream>,
|
||||
default_methods: Vec<MethodAndMethodDef>,
|
||||
default_slots: Vec<MethodAndSlotDef>,
|
||||
doc: Option<PythonDoc>,
|
||||
}
|
||||
|
||||
|
@ -676,8 +677,8 @@ impl<'a> PyClassImplsBuilder<'a> {
|
|||
cls: &'a syn::Ident,
|
||||
attr: &'a PyClassArgs,
|
||||
methods_type: PyClassMethodsType,
|
||||
default_methods: Vec<TokenStream>,
|
||||
default_slots: Vec<TokenStream>,
|
||||
default_methods: Vec<MethodAndMethodDef>,
|
||||
default_slots: Vec<MethodAndSlotDef>,
|
||||
) -> Self {
|
||||
Self {
|
||||
cls,
|
||||
|
@ -838,8 +839,18 @@ impl<'a> PyClassImplsBuilder<'a> {
|
|||
None
|
||||
};
|
||||
|
||||
let default_methods = &self.default_methods;
|
||||
let default_slots = &self.default_slots;
|
||||
let default_methods = self
|
||||
.default_methods
|
||||
.iter()
|
||||
.map(|meth| &meth.associated_method)
|
||||
.chain(
|
||||
self.default_slots
|
||||
.iter()
|
||||
.map(|meth| &meth.associated_method),
|
||||
);
|
||||
|
||||
let default_method_defs = self.default_methods.iter().map(|meth| &meth.method_def);
|
||||
let default_slot_defs = self.default_slots.iter().map(|slot| &slot.slot_def);
|
||||
let freelist_slots = self.freelist_slots();
|
||||
|
||||
let deprecations = &self.attr.deprecations;
|
||||
|
@ -907,8 +918,8 @@ impl<'a> PyClassImplsBuilder<'a> {
|
|||
let collector = PyClassImplCollector::<Self>::new();
|
||||
#deprecations;
|
||||
static INTRINSIC_ITEMS: PyClassItems = PyClassItems {
|
||||
methods: &[#(#default_methods),*],
|
||||
slots: &[#(#default_slots),* #(#freelist_slots),*],
|
||||
methods: &[#(#default_method_defs),*],
|
||||
slots: &[#(#default_slot_defs),* #(#freelist_slots),*],
|
||||
};
|
||||
visitor(&INTRINSIC_ITEMS);
|
||||
#pymethods_items
|
||||
|
@ -920,6 +931,12 @@ impl<'a> PyClassImplsBuilder<'a> {
|
|||
#weaklist_offset
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
impl #cls {
|
||||
#(#default_methods)*
|
||||
}
|
||||
|
||||
#inventory_class
|
||||
}
|
||||
}
|
||||
|
|
|
@ -430,7 +430,6 @@ pub fn impl_wrap_pyfunction(
|
|||
doc,
|
||||
deprecations: options.deprecations,
|
||||
text_signature: options.text_signature,
|
||||
krate: krate.clone(),
|
||||
unsafety: func.sig.unsafety,
|
||||
};
|
||||
|
||||
|
@ -442,7 +441,6 @@ pub fn impl_wrap_pyfunction(
|
|||
let methoddef = spec.get_methoddef(wrapper_ident);
|
||||
|
||||
let wrapped_pyfunction = quote! {
|
||||
#wrapper
|
||||
|
||||
// Create a module with the same name as the `#[pyfunction]` - this way `use <the function>`
|
||||
// will actually bring both the module and the function into scope.
|
||||
|
@ -461,6 +459,8 @@ pub fn impl_wrap_pyfunction(
|
|||
impl #name::MakeDef {
|
||||
const DEF: #krate::impl_::pyfunction::PyMethodDef = #methoddef;
|
||||
}
|
||||
|
||||
#wrapper
|
||||
};
|
||||
};
|
||||
Ok(wrapped_pyfunction)
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::{
|
|||
attributes::{take_pyo3_options, CrateAttribute},
|
||||
konst::{ConstAttributes, ConstSpec},
|
||||
pyfunction::PyFunctionOptions,
|
||||
pymethod::{self, is_proto_method},
|
||||
pymethod::{self, is_proto_method, MethodAndMethodDef, MethodAndSlotDef},
|
||||
utils::get_pyo3_crate,
|
||||
};
|
||||
use proc_macro2::TokenStream;
|
||||
|
@ -95,6 +95,7 @@ pub fn impl_methods(
|
|||
let mut trait_impls = Vec::new();
|
||||
let mut proto_impls = Vec::new();
|
||||
let mut methods = Vec::new();
|
||||
let mut associated_methods = Vec::new();
|
||||
|
||||
let mut implemented_proto_fragments = HashSet::new();
|
||||
|
||||
|
@ -104,18 +105,26 @@ pub fn impl_methods(
|
|||
let mut fun_options = PyFunctionOptions::from_attrs(&mut meth.attrs)?;
|
||||
fun_options.krate = fun_options.krate.or_else(|| options.krate.clone());
|
||||
match pymethod::gen_py_method(ty, &mut meth.sig, &mut meth.attrs, fun_options)? {
|
||||
GeneratedPyMethod::Method(token_stream) => {
|
||||
GeneratedPyMethod::Method(MethodAndMethodDef {
|
||||
associated_method,
|
||||
method_def,
|
||||
}) => {
|
||||
let attrs = get_cfg_attributes(&meth.attrs);
|
||||
methods.push(quote!(#(#attrs)* #token_stream));
|
||||
associated_methods.push(quote!(#(#attrs)* #associated_method));
|
||||
methods.push(quote!(#(#attrs)* #method_def));
|
||||
}
|
||||
GeneratedPyMethod::SlotTraitImpl(method_name, token_stream) => {
|
||||
implemented_proto_fragments.insert(method_name);
|
||||
let attrs = get_cfg_attributes(&meth.attrs);
|
||||
trait_impls.push(quote!(#(#attrs)* #token_stream));
|
||||
}
|
||||
GeneratedPyMethod::Proto(token_stream) => {
|
||||
GeneratedPyMethod::Proto(MethodAndSlotDef {
|
||||
associated_method,
|
||||
slot_def,
|
||||
}) => {
|
||||
let attrs = get_cfg_attributes(&meth.attrs);
|
||||
proto_impls.push(quote!(#(#attrs)* #token_stream))
|
||||
proto_impls.push(quote!(#(#attrs)* #slot_def));
|
||||
associated_methods.push(quote!(#(#attrs)* #associated_method));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -127,8 +136,12 @@ pub fn impl_methods(
|
|||
attributes,
|
||||
};
|
||||
let attrs = get_cfg_attributes(&konst.attrs);
|
||||
let meth = gen_py_const(ty, &spec);
|
||||
methods.push(quote!(#(#attrs)* #meth));
|
||||
let MethodAndMethodDef {
|
||||
associated_method,
|
||||
method_def,
|
||||
} = gen_py_const(ty, &spec);
|
||||
methods.push(quote!(#(#attrs)* #method_def));
|
||||
associated_methods.push(quote!(#(#attrs)* #associated_method));
|
||||
if is_proto_method(&spec.python_name().to_string()) {
|
||||
// If this is a known protocol method e.g. __contains__, then allow this
|
||||
// symbol even though it's not an uppercase constant.
|
||||
|
@ -158,32 +171,41 @@ pub fn impl_methods(
|
|||
#(#trait_impls)*
|
||||
|
||||
#items
|
||||
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
impl #ty {
|
||||
#(#associated_methods)*
|
||||
}
|
||||
};
|
||||
})
|
||||
}
|
||||
|
||||
pub fn gen_py_const(cls: &syn::Type, spec: &ConstSpec) -> TokenStream {
|
||||
pub fn gen_py_const(cls: &syn::Type, spec: &ConstSpec) -> MethodAndMethodDef {
|
||||
let member = &spec.rust_ident;
|
||||
let wrapper_ident = format_ident!("__pymethod_{}__", member);
|
||||
let deprecations = &spec.attributes.deprecations;
|
||||
let python_name = &spec.null_terminated_python_name();
|
||||
quote! {
|
||||
|
||||
let associated_method = quote! {
|
||||
fn #wrapper_ident(py: _pyo3::Python<'_>) -> _pyo3::PyResult<_pyo3::PyObject> {
|
||||
#deprecations
|
||||
::std::result::Result::Ok(_pyo3::IntoPy::into_py(#cls::#member, py))
|
||||
}
|
||||
};
|
||||
|
||||
let method_def = quote! {
|
||||
_pyo3::class::PyMethodDefType::ClassAttribute({
|
||||
_pyo3::class::PyClassAttributeDef::new(
|
||||
#python_name,
|
||||
_pyo3::impl_::pymethods::PyClassAttributeFactory({
|
||||
impl #cls {
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
fn #wrapper_ident(py: _pyo3::Python<'_>) -> _pyo3::PyResult<_pyo3::PyObject> {
|
||||
#deprecations
|
||||
::std::result::Result::Ok(_pyo3::IntoPy::into_py(#cls::#member, py))
|
||||
}
|
||||
}
|
||||
#cls::#wrapper_ident
|
||||
})
|
||||
_pyo3::impl_::pymethods::PyClassAttributeFactory(#cls::#wrapper_ident)
|
||||
)
|
||||
})
|
||||
};
|
||||
|
||||
MethodAndMethodDef {
|
||||
associated_method,
|
||||
method_def,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,9 +15,25 @@ use quote::{format_ident, quote, ToTokens};
|
|||
use syn::Ident;
|
||||
use syn::{ext::IdentExt, spanned::Spanned, Result};
|
||||
|
||||
/// Generated code for a single pymethod item.
|
||||
pub struct MethodAndMethodDef {
|
||||
/// The implementation of the Python wrapper for the pymethod
|
||||
pub associated_method: TokenStream,
|
||||
/// The method def which will be used to register this pymethod
|
||||
pub method_def: TokenStream,
|
||||
}
|
||||
|
||||
/// Generated code for a single pymethod item which is registered by a slot.
|
||||
pub struct MethodAndSlotDef {
|
||||
/// The implementation of the Python wrapper for the pymethod
|
||||
pub associated_method: TokenStream,
|
||||
/// The slot def which will be used to register this pymethod
|
||||
pub slot_def: TokenStream,
|
||||
}
|
||||
|
||||
pub enum GeneratedPyMethod {
|
||||
Method(TokenStream),
|
||||
Proto(TokenStream),
|
||||
Method(MethodAndMethodDef),
|
||||
Proto(MethodAndSlotDef),
|
||||
SlotTraitImpl(String, TokenStream),
|
||||
}
|
||||
|
||||
|
@ -262,93 +278,96 @@ pub fn impl_py_method_def(
|
|||
cls: &syn::Type,
|
||||
spec: &FnSpec<'_>,
|
||||
flags: Option<TokenStream>,
|
||||
) -> Result<TokenStream> {
|
||||
) -> Result<MethodAndMethodDef> {
|
||||
let wrapper_ident = format_ident!("__pymethod_{}__", spec.python_name);
|
||||
let wrapper_def = spec.get_wrapper_function(&wrapper_ident, Some(cls))?;
|
||||
let associated_method = spec.get_wrapper_function(&wrapper_ident, Some(cls))?;
|
||||
let add_flags = flags.map(|flags| quote!(.flags(#flags)));
|
||||
let methoddef_type = match spec.tp {
|
||||
FnType::FnStatic => quote!(Static),
|
||||
FnType::FnClass => quote!(Class),
|
||||
_ => quote!(Method),
|
||||
};
|
||||
let methoddef = spec.get_methoddef(quote! {{
|
||||
impl #cls { #[doc(hidden)]#[allow(non_snake_case)] #wrapper_def }
|
||||
#cls::#wrapper_ident
|
||||
}});
|
||||
Ok(quote! {
|
||||
let methoddef = spec.get_methoddef(quote! { #cls::#wrapper_ident });
|
||||
let method_def = quote! {
|
||||
_pyo3::class::PyMethodDefType::#methoddef_type(#methoddef #add_flags)
|
||||
};
|
||||
Ok(MethodAndMethodDef {
|
||||
associated_method,
|
||||
method_def,
|
||||
})
|
||||
}
|
||||
|
||||
fn impl_py_method_def_new(cls: &syn::Type, spec: &FnSpec<'_>) -> Result<TokenStream> {
|
||||
fn impl_py_method_def_new(cls: &syn::Type, spec: &FnSpec<'_>) -> Result<MethodAndSlotDef> {
|
||||
let wrapper_ident = syn::Ident::new("__pymethod___new____", Span::call_site());
|
||||
let wrapper = spec.get_wrapper_function(&wrapper_ident, Some(cls))?;
|
||||
Ok(quote! {{
|
||||
impl #cls {
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
#wrapper
|
||||
}
|
||||
let associated_method = spec.get_wrapper_function(&wrapper_ident, Some(cls))?;
|
||||
let slot_def = quote! {
|
||||
_pyo3::ffi::PyType_Slot {
|
||||
slot: _pyo3::ffi::Py_tp_new,
|
||||
pfunc: #cls::#wrapper_ident as _pyo3::ffi::newfunc as _
|
||||
}
|
||||
}})
|
||||
};
|
||||
Ok(MethodAndSlotDef {
|
||||
associated_method,
|
||||
slot_def,
|
||||
})
|
||||
}
|
||||
|
||||
fn impl_call_slot(cls: &syn::Type, mut spec: FnSpec<'_>) -> Result<TokenStream> {
|
||||
fn impl_call_slot(cls: &syn::Type, mut spec: FnSpec<'_>) -> Result<MethodAndSlotDef> {
|
||||
// HACK: __call__ proto slot must always use varargs calling convention, so change the spec.
|
||||
// Probably indicates there's a refactoring opportunity somewhere.
|
||||
spec.convention = CallingConvention::Varargs;
|
||||
|
||||
let wrapper_ident = syn::Ident::new("__pymethod___call____", Span::call_site());
|
||||
let wrapper = spec.get_wrapper_function(&wrapper_ident, Some(cls))?;
|
||||
Ok(quote! {{
|
||||
impl #cls {
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
#wrapper
|
||||
}
|
||||
let associated_method = spec.get_wrapper_function(&wrapper_ident, Some(cls))?;
|
||||
let slot_def = quote! {
|
||||
_pyo3::ffi::PyType_Slot {
|
||||
slot: _pyo3::ffi::Py_tp_call,
|
||||
pfunc: #cls::#wrapper_ident as _pyo3::ffi::ternaryfunc as _
|
||||
}
|
||||
}})
|
||||
};
|
||||
Ok(MethodAndSlotDef {
|
||||
associated_method,
|
||||
slot_def,
|
||||
})
|
||||
}
|
||||
|
||||
fn impl_traverse_slot(cls: &syn::Type, spec: FnSpec<'_>) -> TokenStream {
|
||||
fn impl_traverse_slot(cls: &syn::Type, spec: FnSpec<'_>) -> MethodAndSlotDef {
|
||||
let ident = spec.name;
|
||||
quote! {{
|
||||
impl #cls {
|
||||
pub unsafe extern "C" fn __pymethod_traverse__(
|
||||
slf: *mut _pyo3::ffi::PyObject,
|
||||
visit: _pyo3::ffi::visitproc,
|
||||
arg: *mut ::std::os::raw::c_void,
|
||||
) -> ::std::os::raw::c_int
|
||||
{
|
||||
let pool = _pyo3::GILPool::new();
|
||||
let py = pool.python();
|
||||
_pyo3::callback::abort_on_traverse_panic(::std::panic::catch_unwind(move || {
|
||||
let slf = py.from_borrowed_ptr::<_pyo3::PyCell<#cls>>(slf);
|
||||
let associated_method = quote! {
|
||||
pub unsafe extern "C" fn __pymethod_traverse__(
|
||||
slf: *mut _pyo3::ffi::PyObject,
|
||||
visit: _pyo3::ffi::visitproc,
|
||||
arg: *mut ::std::os::raw::c_void,
|
||||
) -> ::std::os::raw::c_int
|
||||
{
|
||||
let pool = _pyo3::GILPool::new();
|
||||
let py = pool.python();
|
||||
_pyo3::callback::abort_on_traverse_panic(::std::panic::catch_unwind(move || {
|
||||
let slf = py.from_borrowed_ptr::<_pyo3::PyCell<#cls>>(slf);
|
||||
|
||||
let visit = _pyo3::class::gc::PyVisit::from_raw(visit, arg, py);
|
||||
let borrow = slf.try_borrow();
|
||||
if let ::std::result::Result::Ok(borrow) = borrow {
|
||||
_pyo3::impl_::pymethods::unwrap_traverse_result(borrow.#ident(visit))
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}))
|
||||
}
|
||||
let visit = _pyo3::class::gc::PyVisit::from_raw(visit, arg, py);
|
||||
let borrow = slf.try_borrow();
|
||||
if let ::std::result::Result::Ok(borrow) = borrow {
|
||||
_pyo3::impl_::pymethods::unwrap_traverse_result(borrow.#ident(visit))
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}))
|
||||
}
|
||||
};
|
||||
let slot_def = quote! {
|
||||
_pyo3::ffi::PyType_Slot {
|
||||
slot: _pyo3::ffi::Py_tp_traverse,
|
||||
pfunc: #cls::__pymethod_traverse__ as _pyo3::ffi::traverseproc as _
|
||||
}
|
||||
}}
|
||||
};
|
||||
MethodAndSlotDef {
|
||||
associated_method,
|
||||
slot_def,
|
||||
}
|
||||
}
|
||||
|
||||
fn impl_py_class_attribute(cls: &syn::Type, spec: &FnSpec<'_>) -> syn::Result<TokenStream> {
|
||||
fn impl_py_class_attribute(cls: &syn::Type, spec: &FnSpec<'_>) -> syn::Result<MethodAndMethodDef> {
|
||||
let (py_arg, args) = split_off_python_arg(&spec.args);
|
||||
ensure_spanned!(
|
||||
args.is_empty(),
|
||||
|
@ -366,30 +385,31 @@ fn impl_py_class_attribute(cls: &syn::Type, spec: &FnSpec<'_>) -> syn::Result<To
|
|||
let deprecations = &spec.deprecations;
|
||||
let python_name = spec.null_terminated_python_name();
|
||||
|
||||
let classattr = quote! {
|
||||
let associated_method = quote! {
|
||||
fn #wrapper_ident(py: _pyo3::Python<'_>) -> _pyo3::PyResult<_pyo3::PyObject> {
|
||||
#deprecations
|
||||
let mut ret = #fncall;
|
||||
if false {
|
||||
use _pyo3::impl_::ghost::IntoPyResult;
|
||||
ret.assert_into_py_result();
|
||||
}
|
||||
_pyo3::callback::convert(py, ret)
|
||||
}
|
||||
};
|
||||
|
||||
let method_def = quote! {
|
||||
_pyo3::class::PyMethodDefType::ClassAttribute({
|
||||
_pyo3::class::PyClassAttributeDef::new(
|
||||
#python_name,
|
||||
_pyo3::impl_::pymethods::PyClassAttributeFactory({
|
||||
impl #cls {
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
fn #wrapper_ident(py: _pyo3::Python<'_>) -> _pyo3::PyResult<_pyo3::PyObject> {
|
||||
#deprecations
|
||||
let mut ret = #fncall;
|
||||
if false {
|
||||
use _pyo3::impl_::ghost::IntoPyResult;
|
||||
ret.assert_into_py_result();
|
||||
}
|
||||
_pyo3::callback::convert(py, ret)
|
||||
}
|
||||
}
|
||||
#cls::#wrapper_ident
|
||||
})
|
||||
_pyo3::impl_::pymethods::PyClassAttributeFactory(#cls::#wrapper_ident)
|
||||
)
|
||||
})
|
||||
};
|
||||
Ok(classattr)
|
||||
|
||||
Ok(MethodAndMethodDef {
|
||||
associated_method,
|
||||
method_def,
|
||||
})
|
||||
}
|
||||
|
||||
fn impl_call_setter(cls: &syn::Type, spec: &FnSpec<'_>) -> syn::Result<TokenStream> {
|
||||
|
@ -415,7 +435,10 @@ fn impl_call_setter(cls: &syn::Type, spec: &FnSpec<'_>) -> syn::Result<TokenStre
|
|||
}
|
||||
|
||||
// Used here for PropertyType::Function, used in pyclass for descriptors.
|
||||
pub fn impl_py_setter_def(cls: &syn::Type, property_type: PropertyType<'_>) -> Result<TokenStream> {
|
||||
pub fn impl_py_setter_def(
|
||||
cls: &syn::Type,
|
||||
property_type: PropertyType<'_>,
|
||||
) -> Result<MethodAndMethodDef> {
|
||||
let python_name = property_type.null_terminated_python_name()?;
|
||||
let deprecations = property_type.deprecations();
|
||||
let doc = property_type.doc();
|
||||
|
@ -462,40 +485,43 @@ pub fn impl_py_setter_def(cls: &syn::Type, property_type: PropertyType<'_>) -> R
|
|||
format_ident!("__pymethod_set_{}__", spec.name)
|
||||
}
|
||||
};
|
||||
Ok(quote! {
|
||||
|
||||
let associated_method = quote! {
|
||||
unsafe extern "C" fn #wrapper_ident(
|
||||
_slf: *mut _pyo3::ffi::PyObject,
|
||||
_value: *mut _pyo3::ffi::PyObject,
|
||||
_: *mut ::std::os::raw::c_void
|
||||
) -> ::std::os::raw::c_int {
|
||||
let gil = _pyo3::GILPool::new();
|
||||
let _py = gil.python();
|
||||
_pyo3::callback::panic_result_into_callback_output(_py, ::std::panic::catch_unwind(move || -> _pyo3::PyResult<_> {
|
||||
#slf
|
||||
let _value = _py
|
||||
.from_borrowed_ptr_or_opt(_value)
|
||||
.ok_or_else(|| {
|
||||
_pyo3::exceptions::PyAttributeError::new_err("can't delete attribute")
|
||||
})?;
|
||||
let _val = _pyo3::FromPyObject::extract(_value)?;
|
||||
|
||||
_pyo3::callback::convert(_py, #setter_impl)
|
||||
}))
|
||||
}
|
||||
};
|
||||
|
||||
let method_def = quote! {
|
||||
_pyo3::class::PyMethodDefType::Setter({
|
||||
#deprecations
|
||||
_pyo3::class::PySetterDef::new(
|
||||
#python_name,
|
||||
_pyo3::impl_::pymethods::PySetter({
|
||||
impl #cls {
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
unsafe extern "C" fn #wrapper_ident(
|
||||
_slf: *mut _pyo3::ffi::PyObject,
|
||||
_value: *mut _pyo3::ffi::PyObject,
|
||||
_: *mut ::std::os::raw::c_void
|
||||
) -> ::std::os::raw::c_int {
|
||||
let gil = _pyo3::GILPool::new();
|
||||
let _py = gil.python();
|
||||
_pyo3::callback::panic_result_into_callback_output(_py, ::std::panic::catch_unwind(move || -> _pyo3::PyResult<_> {
|
||||
#slf
|
||||
let _value = _py
|
||||
.from_borrowed_ptr_or_opt(_value)
|
||||
.ok_or_else(|| {
|
||||
_pyo3::exceptions::PyAttributeError::new_err("can't delete attribute")
|
||||
})?;
|
||||
let _val = _pyo3::FromPyObject::extract(_value)?;
|
||||
|
||||
_pyo3::callback::convert(_py, #setter_impl)
|
||||
}))
|
||||
}
|
||||
}
|
||||
#cls::#wrapper_ident
|
||||
}),
|
||||
_pyo3::impl_::pymethods::PySetter(#cls::#wrapper_ident),
|
||||
#doc
|
||||
)
|
||||
})
|
||||
};
|
||||
|
||||
Ok(MethodAndMethodDef {
|
||||
associated_method,
|
||||
method_def,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -517,7 +543,10 @@ fn impl_call_getter(cls: &syn::Type, spec: &FnSpec<'_>) -> syn::Result<TokenStre
|
|||
}
|
||||
|
||||
// Used here for PropertyType::Function, used in pyclass for descriptors.
|
||||
pub fn impl_py_getter_def(cls: &syn::Type, property_type: PropertyType<'_>) -> Result<TokenStream> {
|
||||
pub fn impl_py_getter_def(
|
||||
cls: &syn::Type,
|
||||
property_type: PropertyType<'_>,
|
||||
) -> Result<MethodAndMethodDef> {
|
||||
let python_name = property_type.null_terminated_python_name()?;
|
||||
let deprecations = property_type.deprecations();
|
||||
let doc = property_type.doc();
|
||||
|
@ -581,33 +610,35 @@ pub fn impl_py_getter_def(cls: &syn::Type, property_type: PropertyType<'_>) -> R
|
|||
}
|
||||
};
|
||||
|
||||
Ok(quote! {
|
||||
let associated_method = quote! {
|
||||
unsafe extern "C" fn #wrapper_ident(
|
||||
_slf: *mut _pyo3::ffi::PyObject,
|
||||
_: *mut ::std::os::raw::c_void
|
||||
) -> *mut _pyo3::ffi::PyObject {
|
||||
let gil = _pyo3::GILPool::new();
|
||||
let _py = gil.python();
|
||||
_pyo3::callback::panic_result_into_callback_output(_py, ::std::panic::catch_unwind(move || -> _pyo3::PyResult<_> {
|
||||
#slf
|
||||
let item = #getter_impl;
|
||||
#conversion
|
||||
}))
|
||||
}
|
||||
};
|
||||
|
||||
let method_def = quote! {
|
||||
_pyo3::class::PyMethodDefType::Getter({
|
||||
#deprecations
|
||||
_pyo3::class::PyGetterDef::new(
|
||||
#python_name,
|
||||
_pyo3::impl_::pymethods::PyGetter({
|
||||
impl #cls {
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
unsafe extern "C" fn #wrapper_ident(
|
||||
_slf: *mut _pyo3::ffi::PyObject,
|
||||
_: *mut ::std::os::raw::c_void
|
||||
) -> *mut _pyo3::ffi::PyObject {
|
||||
let gil = _pyo3::GILPool::new();
|
||||
let _py = gil.python();
|
||||
_pyo3::callback::panic_result_into_callback_output(_py, ::std::panic::catch_unwind(move || -> _pyo3::PyResult<_> {
|
||||
#slf
|
||||
let item = #getter_impl;
|
||||
#conversion
|
||||
}))
|
||||
}
|
||||
}
|
||||
#cls::#wrapper_ident
|
||||
}),
|
||||
_pyo3::impl_::pymethods::PyGetter(#cls::#wrapper_ident),
|
||||
#doc
|
||||
)
|
||||
})
|
||||
};
|
||||
|
||||
Ok(MethodAndMethodDef {
|
||||
associated_method,
|
||||
method_def,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1000,7 +1031,7 @@ impl SlotDef {
|
|||
cls: &syn::Type,
|
||||
spec: &FnSpec<'_>,
|
||||
method_name: &str,
|
||||
) -> Result<TokenStream> {
|
||||
) -> Result<MethodAndSlotDef> {
|
||||
let SlotDef {
|
||||
slot,
|
||||
func_ty,
|
||||
|
@ -1032,24 +1063,26 @@ impl SlotDef {
|
|||
*extract_error_mode,
|
||||
return_mode.as_ref(),
|
||||
)?;
|
||||
Ok(quote!({
|
||||
impl #cls {
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
unsafe extern "C" fn #wrapper_ident(_raw_slf: *mut _pyo3::ffi::PyObject, #(#arg_idents: #arg_types),*) -> #ret_ty {
|
||||
let _slf = _raw_slf;
|
||||
let gil = _pyo3::GILPool::new();
|
||||
let #py = gil.python();
|
||||
_pyo3::callback::panic_result_into_callback_output(#py, ::std::panic::catch_unwind(move || -> _pyo3::PyResult<_> {
|
||||
#body
|
||||
}))
|
||||
}
|
||||
let associated_method = quote! {
|
||||
unsafe extern "C" fn #wrapper_ident(_raw_slf: *mut _pyo3::ffi::PyObject, #(#arg_idents: #arg_types),*) -> #ret_ty {
|
||||
let _slf = _raw_slf;
|
||||
let gil = _pyo3::GILPool::new();
|
||||
let #py = gil.python();
|
||||
_pyo3::callback::panic_result_into_callback_output(#py, ::std::panic::catch_unwind(move || -> _pyo3::PyResult<_> {
|
||||
#body
|
||||
}))
|
||||
}
|
||||
};
|
||||
let slot_def = quote! {
|
||||
_pyo3::ffi::PyType_Slot {
|
||||
slot: _pyo3::ffi::#slot,
|
||||
pfunc: #cls::#wrapper_ident as _pyo3::ffi::#func_ty as _
|
||||
}
|
||||
}))
|
||||
};
|
||||
Ok(MethodAndSlotDef {
|
||||
associated_method,
|
||||
slot_def,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ use crate::method::{FnSpec, FnType};
|
|||
use crate::proto_method::impl_method_proto;
|
||||
use crate::pyfunction::PyFunctionOptions;
|
||||
use crate::pymethod;
|
||||
use crate::pymethod::MethodAndMethodDef;
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::quote;
|
||||
use quote::ToTokens;
|
||||
|
@ -48,7 +49,8 @@ fn impl_proto_impl(
|
|||
proto: &defs::Proto,
|
||||
) -> syn::Result<TokenStream> {
|
||||
let mut trait_impls = TokenStream::new();
|
||||
let mut py_methods = Vec::new();
|
||||
let mut associated_methods = Vec::new();
|
||||
let mut method_defs = Vec::new();
|
||||
let mut method_names = HashSet::new();
|
||||
let module = proto.module();
|
||||
|
||||
|
@ -72,7 +74,10 @@ fn impl_proto_impl(
|
|||
None
|
||||
};
|
||||
|
||||
let method = if let FnType::Fn(_) = &fn_spec.tp {
|
||||
let MethodAndMethodDef {
|
||||
associated_method,
|
||||
method_def,
|
||||
} = if let FnType::Fn(_) = &fn_spec.tp {
|
||||
pymethod::impl_py_method_def(ty, &fn_spec, flags)?
|
||||
} else {
|
||||
bail_spanned!(
|
||||
|
@ -80,17 +85,24 @@ fn impl_proto_impl(
|
|||
);
|
||||
};
|
||||
|
||||
py_methods.push(method);
|
||||
associated_methods.push(associated_method);
|
||||
method_defs.push(method_def);
|
||||
}
|
||||
}
|
||||
}
|
||||
let items = impl_proto_items(method_names, py_methods, ty, proto);
|
||||
let items = impl_proto_items(method_names, method_defs, ty, proto);
|
||||
|
||||
Ok(quote! {
|
||||
const _: () = {
|
||||
use ::pyo3 as _pyo3; // pyproto doesn't support specifying #[pyo3(crate)]
|
||||
#trait_impls
|
||||
#items
|
||||
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
impl #ty {
|
||||
#(#associated_methods)*
|
||||
}
|
||||
};
|
||||
})
|
||||
}
|
||||
|
|
|
@ -109,24 +109,24 @@ error: Python objects are shared, so 'self' cannot be moved out of the Python in
|
|||
124 | fn method_self_by_value(self){}
|
||||
| ^^^^
|
||||
|
||||
error[E0592]: duplicate definitions with name `__pymethod___new____`
|
||||
error[E0201]: duplicate definitions with name `__pymethod___new____`:
|
||||
--> tests/ui/invalid_pymethods.rs:129:1
|
||||
|
|
||||
129 | #[pymethods]
|
||||
| ^^^^^^^^^^^^
|
||||
| |
|
||||
| duplicate definitions for `__pymethod___new____`
|
||||
| other definition for `__pymethod___new____`
|
||||
| previous definition of `__pymethod___new____` here
|
||||
| duplicate definition
|
||||
|
|
||||
= note: this error originates in the attribute macro `pymethods` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0592]: duplicate definitions with name `__pymethod_func__`
|
||||
error[E0201]: duplicate definitions with name `__pymethod_func__`:
|
||||
--> tests/ui/invalid_pymethods.rs:140:1
|
||||
|
|
||||
140 | #[pymethods]
|
||||
| ^^^^^^^^^^^^
|
||||
| |
|
||||
| duplicate definitions for `__pymethod_func__`
|
||||
| other definition for `__pymethod_func__`
|
||||
| previous definition of `__pymethod_func__` here
|
||||
| duplicate definition
|
||||
|
|
||||
= note: this error originates in the attribute macro `pymethods` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
|
Loading…
Reference in New Issue