Refactor PyMethodDef creation too.

This commit is contained in:
Georg Brandl 2021-06-05 17:53:35 +02:00
parent a8d2649032
commit c670c57ddb
3 changed files with 37 additions and 50 deletions

View File

@ -544,7 +544,7 @@ impl<'a> FnSpec<'a> {
let rust_call = quote! { #rust_name(#(#arg_names),*) };
let arg_convert_and_rust_call = impl_arg_params(self, cls, rust_call, &py, false)?;
quote! {
unsafe extern "C" fn __wrap(
unsafe extern "C" fn #ident (
subtype: *mut pyo3::ffi::PyTypeObject,
_args: *mut pyo3::ffi::PyObject,
_kwargs: *mut pyo3::ffi::PyObject) -> *mut pyo3::ffi::PyObject
@ -565,6 +565,37 @@ impl<'a> FnSpec<'a> {
}
})
}
/// Return a `PyMethodDef` constructor for this function, matching the selected
/// calling convention.
pub fn get_methoddef(&self, wrapper: impl ToTokens) -> TokenStream {
let python_name = self.null_terminated_python_name();
let doc = &self.doc;
match self.convention {
CallingConvention::Noargs => quote! {
pyo3::class::methods::PyMethodDef::noargs(
#python_name,
pyo3::class::methods::PyCFunction(#wrapper),
#doc,
)
},
CallingConvention::Fastcall => quote! {
pyo3::class::methods::PyMethodDef::fastcall_cfunction_with_keywords(
#python_name,
pyo3::class::methods::PyCFunctionFastWithKeywords(#wrapper),
#doc,
)
},
CallingConvention::Varargs => quote! {
pyo3::class::methods::PyMethodDef::cfunction_with_keywords(
#python_name,
pyo3::class::methods::PyCFunctionWithKeywords(#wrapper),
#doc,
)
},
CallingConvention::TpNew => unreachable!("tp_new cannot get a methoddef"),
}
}
}
#[derive(Clone, PartialEq, Debug)]

View File

@ -426,37 +426,16 @@ pub fn impl_wrap_pyfunction(
deprecations: options.deprecations,
};
let doc = &spec.doc;
let python_name = spec.null_terminated_python_name();
let name = &func.sig.ident;
let wrapper_ident = format_ident!("__pyo3_raw_{}", name);
let wrapper_ident = format_ident!("__pyo3_raw_{}", spec.name);
let wrapper = spec.get_wrapper_function(&wrapper_ident, None)?;
let (methoddef_meth, cfunc_variant) = match spec.convention {
CallingConvention::Noargs => (quote!(noargs), quote!(PyCFunction)),
CallingConvention::Fastcall => (
quote!(fastcall_cfunction_with_keywords),
quote!(PyCFunctionFastWithKeywords),
),
_ => (
quote!(cfunction_with_keywords),
quote!(PyCFunctionWithKeywords),
),
};
let methoddef = spec.get_methoddef(wrapper_ident);
let wrapped_pyfunction = quote! {
#wrapper
pub(crate) fn #function_wrapper_ident<'a>(
args: impl Into<pyo3::derive_utils::PyFunctionArguments<'a>>
) -> pyo3::PyResult<&'a pyo3::types::PyCFunction> {
pyo3::types::PyCFunction::internal_new(
pyo3::class::methods::PyMethodDef:: #methoddef_meth (
#python_name,
pyo3::class::methods:: #cfunc_variant (#wrapper_ident),
#doc,
),
args.into(),
)
pyo3::types::PyCFunction::internal_new(#methoddef, args.into())
}
};
Ok((function_wrapper_ident, wrapped_pyfunction))

View File

@ -4,7 +4,6 @@ use std::borrow::Cow;
use crate::attributes::NameAttribute;
use crate::konst::ConstSpec;
use crate::method::CallingConvention;
use crate::utils::ensure_not_async_fn;
use crate::{deprecations::Deprecations, utils};
use crate::{
@ -250,36 +249,14 @@ pub fn impl_py_method_def(
let wrapper_ident = syn::Ident::new("__wrap", Span::call_site());
let wrapper_def = spec.get_wrapper_function(&wrapper_ident, Some(cls))?;
let add_flags = flags.map(|flags| quote!(.flags(#flags)));
let doc = &spec.doc;
let python_name = spec.null_terminated_python_name();
let methoddef_type = match spec.tp {
FnType::FnStatic => quote!(Static),
FnType::FnClass => quote!(Class),
_ => quote!(Method),
};
let (methoddef_meth, cfunc_variant) = match spec.convention {
CallingConvention::Noargs => (quote!(noargs), quote!(PyCFunction)),
CallingConvention::Fastcall => (
quote!(fastcall_cfunction_with_keywords),
quote!(PyCFunctionFastWithKeywords),
),
_ => (
quote!(cfunction_with_keywords),
quote!(PyCFunctionWithKeywords),
),
};
let methoddef = spec.get_methoddef(quote! {{ #wrapper_def #wrapper_ident }});
Ok(quote! {
pyo3::class::PyMethodDefType:: #methoddef_type ({
pyo3::class::PyMethodDef:: #methoddef_meth (
#python_name,
pyo3::class::methods:: #cfunc_variant ({
#wrapper_def
#wrapper_ident
}),
#doc
)
#add_flags
})
pyo3::class::PyMethodDefType::#methoddef_type(#methoddef #add_flags)
})
}