pymethods: faster compilation for protos, tidy ups

This commit is contained in:
David Hewitt 2021-09-18 09:49:05 +01:00
parent 43eb762346
commit c2d78ca76e
7 changed files with 212 additions and 176 deletions

View file

@ -93,11 +93,17 @@ pub enum FnType {
}
impl FnType {
pub fn self_conversion(&self, cls: Option<&syn::Type>, error_mode: ExtractErrorMode) -> TokenStream {
pub fn self_conversion(
&self,
cls: Option<&syn::Type>,
error_mode: ExtractErrorMode,
) -> TokenStream {
match self {
FnType::Getter(st) | FnType::Setter(st) | FnType::Fn(st) | FnType::FnCall(st) => {
st.receiver(cls.expect("no class given for Fn with a \"self\" receiver"), error_mode)
}
FnType::Getter(st) | FnType::Setter(st) | FnType::Fn(st) | FnType::FnCall(st) => st
.receiver(
cls.expect("no class given for Fn with a \"self\" receiver"),
error_mode,
),
FnType::FnNew | FnType::FnStatic | FnType::ClassAttribute => {
quote!()
}
@ -128,6 +134,7 @@ pub enum SelfType {
TryFromPyCell(Span),
}
#[derive(Clone, Copy)]
pub enum ExtractErrorMode {
NotImplemented,
Raise,
@ -138,7 +145,7 @@ impl SelfType {
let cell = match error_mode {
ExtractErrorMode::Raise => {
quote! { _py.from_borrowed_ptr::<::pyo3::PyAny>(_slf).downcast::<::pyo3::PyCell<#cls>>()? }
},
}
ExtractErrorMode::NotImplemented => {
quote! {
match _py.from_borrowed_ptr::<::pyo3::PyAny>(_slf).downcast::<::pyo3::PyCell<#cls>>() {
@ -146,7 +153,7 @@ impl SelfType {
::std::result::Result::Err(_) => return ::pyo3::callback::convert(_py, _py.NotImplemented()),
}
}
},
}
};
match self {
SelfType::Receiver { mutable: false } => {

View file

@ -592,50 +592,6 @@ fn impl_class(
visitor(collector.async_protocol_slots());
visitor(collector.buffer_protocol_slots());
visitor(collector.methods_protocol_slots());
let mut generated_slots = ::std::vec::Vec::new();
if let ::std::option::Option::Some(setattr) = ::pyo3::generate_pyclass_setattr_slot!(#cls) {
generated_slots.push(setattr);
}
if let ::std::option::Option::Some(setdescr) = ::pyo3::generate_pyclass_setdescr_slot!(#cls) {
generated_slots.push(setdescr);
}
if let ::std::option::Option::Some(setdescr) = ::pyo3::generate_pyclass_setitem_slot!(#cls) {
generated_slots.push(setdescr);
}
if let ::std::option::Option::Some(setdescr) = ::pyo3::generate_pyclass_add_slot!(#cls) {
generated_slots.push(setdescr);
}
if let ::std::option::Option::Some(setdescr) = ::pyo3::generate_pyclass_sub_slot!(#cls) {
generated_slots.push(setdescr);
}
if let ::std::option::Option::Some(setdescr) = ::pyo3::generate_pyclass_mul_slot!(#cls) {
generated_slots.push(setdescr);
}
if let ::std::option::Option::Some(setdescr) = ::pyo3::generate_pyclass_mod_slot!(#cls) {
generated_slots.push(setdescr);
}
if let ::std::option::Option::Some(setdescr) = ::pyo3::generate_pyclass_divmod_slot!(#cls) {
generated_slots.push(setdescr);
}
if let ::std::option::Option::Some(setdescr) = ::pyo3::generate_pyclass_lshift_slot!(#cls) {
generated_slots.push(setdescr);
}
if let ::std::option::Option::Some(setdescr) = ::pyo3::generate_pyclass_rshift_slot!(#cls) {
generated_slots.push(setdescr);
}
if let ::std::option::Option::Some(setdescr) = ::pyo3::generate_pyclass_and_slot!(#cls) {
generated_slots.push(setdescr);
}
if let ::std::option::Option::Some(setdescr) = ::pyo3::generate_pyclass_or_slot!(#cls) {
generated_slots.push(setdescr);
}
if let ::std::option::Option::Some(setdescr) = ::pyo3::generate_pyclass_xor_slot!(#cls) {
generated_slots.push(setdescr);
}
if let ::std::option::Option::Some(setdescr) = ::pyo3::generate_pyclass_matmul_slot!(#cls) {
generated_slots.push(setdescr);
}
visitor(&generated_slots);
}
fn get_buffer() -> ::std::option::Option<&'static ::pyo3::class::impl_::PyBufferProcs> {

View file

@ -1,5 +1,7 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
use std::collections::HashSet;
use crate::{
konst::{ConstAttributes, ConstSpec},
pyfunction::PyFunctionOptions,
@ -40,6 +42,9 @@ pub fn impl_methods(
let mut trait_impls = Vec::new();
let mut proto_impls = Vec::new();
let mut methods = Vec::new();
let mut implemented_proto_fragments = HashSet::new();
for iimpl in impls.iter_mut() {
match iimpl {
syn::ImplItem::Method(meth) => {
@ -53,6 +58,11 @@ pub fn impl_methods(
let attrs = get_cfg_attributes(&meth.attrs);
trait_impls.push(quote!(#(#attrs)* #token_stream));
}
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) => {
let attrs = get_cfg_attributes(&meth.attrs);
proto_impls.push(quote!(#(#attrs)* #token_stream))
@ -81,7 +91,9 @@ pub fn impl_methods(
};
let protos_registration = match methods_type {
PyClassMethodsType::Specialization => Some(impl_protos(ty, proto_impls)),
PyClassMethodsType::Specialization => {
Some(impl_protos(ty, proto_impls, implemented_proto_fragments))
}
PyClassMethodsType::Inventory => {
if proto_impls.is_empty() {
None
@ -135,7 +147,36 @@ fn impl_py_methods(ty: &syn::Type, methods: Vec<TokenStream>) -> TokenStream {
}
}
fn impl_protos(ty: &syn::Type, proto_impls: Vec<TokenStream>) -> TokenStream {
fn impl_protos(
ty: &syn::Type,
mut proto_impls: Vec<TokenStream>,
mut implemented_proto_fragments: HashSet<String>,
) -> TokenStream {
macro_rules! try_add_shared_slot {
($first:literal, $second:literal, $slot:ident) => {{
let first_implemented = implemented_proto_fragments.remove($first);
let second_implemented = implemented_proto_fragments.remove($second);
if first_implemented || second_implemented {
proto_impls.push(quote! { ::pyo3::$slot!(#ty) })
}
}};
}
try_add_shared_slot!("__setattr__", "__delattr__", generate_pyclass_setattr_slot);
try_add_shared_slot!("__set__", "__delete__", generate_pyclass_setdescr_slot);
try_add_shared_slot!("__setitem__", "__delitem__", generate_pyclass_setitem_slot);
try_add_shared_slot!("__add__", "__radd__", generate_pyclass_add_slot);
try_add_shared_slot!("__sub__", "__rsub__", generate_pyclass_sub_slot);
try_add_shared_slot!("__mul__", "__rmul__", generate_pyclass_mul_slot);
try_add_shared_slot!("__mod__", "__rmod__", generate_pyclass_mod_slot);
try_add_shared_slot!("__divmod__", "__rdivmod__", generate_pyclass_divmod_slot);
try_add_shared_slot!("__lshift__", "__rlshift__", generate_pyclass_lshift_slot);
try_add_shared_slot!("__rshift__", "__rrshift__", generate_pyclass_rshift_slot);
try_add_shared_slot!("__and__", "__rand__", generate_pyclass_and_slot);
try_add_shared_slot!("__or__", "__ror__", generate_pyclass_or_slot);
try_add_shared_slot!("__xor__", "__rxor__", generate_pyclass_xor_slot);
try_add_shared_slot!("__matmul__", "__rmatmul__", generate_pyclass_matmul_slot);
quote! {
impl ::pyo3::class::impl_::PyMethodsProtocolSlots<#ty>
for ::pyo3::class::impl_::PyClassImplCollector<#ty>

View file

@ -19,6 +19,7 @@ pub enum GeneratedPyMethod {
Method(TokenStream),
Proto(TokenStream),
TraitImpl(TokenStream),
SlotTraitImpl(String, TokenStream),
}
pub fn gen_py_method(
@ -41,7 +42,7 @@ pub fn gen_py_method(
if let Some(slot_fragment_def) = pyproto_fragment(&method_name) {
let proto = slot_fragment_def.generate_pyproto_fragment(cls, &spec)?;
return Ok(GeneratedPyMethod::TraitImpl(proto));
return Ok(GeneratedPyMethod::SlotTraitImpl(method_name, proto));
}
Ok(match &spec.tp {
@ -216,8 +217,12 @@ pub fn impl_py_setter_def(cls: &syn::Type, property_type: PropertyType) -> Resul
};
let slf = match property_type {
PropertyType::Descriptor { .. } => SelfType::Receiver { mutable: true }.receiver(cls, ExtractErrorMode::Raise),
PropertyType::Function { self_type, .. } => self_type.receiver(cls, ExtractErrorMode::Raise),
PropertyType::Descriptor { .. } => {
SelfType::Receiver { mutable: true }.receiver(cls, ExtractErrorMode::Raise)
}
PropertyType::Function { self_type, .. } => {
self_type.receiver(cls, ExtractErrorMode::Raise)
}
};
Ok(quote! {
::pyo3::class::PyMethodDefType::Setter({
@ -292,8 +297,12 @@ pub fn impl_py_getter_def(cls: &syn::Type, property_type: PropertyType) -> Resul
};
let slf = match property_type {
PropertyType::Descriptor { .. } => SelfType::Receiver { mutable: false }.receiver(cls, ExtractErrorMode::Raise),
PropertyType::Function { self_type, .. } => self_type.receiver(cls, ExtractErrorMode::Raise),
PropertyType::Descriptor { .. } => {
SelfType::Receiver { mutable: false }.receiver(cls, ExtractErrorMode::Raise)
}
PropertyType::Function { self_type, .. } => {
self_type.receiver(cls, ExtractErrorMode::Raise)
}
};
Ok(quote! {
::pyo3::class::PyMethodDefType::Getter({
@ -401,8 +410,9 @@ const __HASH__: SlotDef = SlotDef::new("Py_tp_hash", "hashfunc")
.return_conversion(TokenGenerator(
|| quote! { ::pyo3::callback::HashCallbackOutput },
));
const __RICHCMP__: SlotDef =
SlotDef::new("Py_tp_richcompare", "richcmpfunc").arguments(&[Ty::Object, Ty::CompareOp]);
const __RICHCMP__: SlotDef = SlotDef::new("Py_tp_richcompare", "richcmpfunc")
.extract_error_mode(ExtractErrorMode::NotImplemented)
.arguments(&[Ty::ObjectOrNotImplemented, Ty::CompareOp]);
const __GET__: SlotDef =
SlotDef::new("Py_tp_descr_get", "descrgetfunc").arguments(&[Ty::Object, Ty::Object]);
const __ITER__: SlotDef = SlotDef::new("Py_tp_iter", "getiterfunc");
@ -431,42 +441,55 @@ const __BOOL__: SlotDef = SlotDef::new("Py_nb_bool", "inquiry").ret_ty(Ty::Int);
const __IADD__: SlotDef = SlotDef::new("Py_nb_inplace_add", "binaryfunc")
.arguments(&[Ty::ObjectOrNotImplemented])
.extract_error_mode(ExtractErrorMode::NotImplemented)
.return_self();
const __ISUB__: SlotDef = SlotDef::new("Py_nb_inplace_subtract", "binaryfunc")
.arguments(&[Ty::ObjectOrNotImplemented])
.extract_error_mode(ExtractErrorMode::NotImplemented)
.return_self();
const __IMUL__: SlotDef = SlotDef::new("Py_nb_inplace_multiply", "binaryfunc")
.arguments(&[Ty::ObjectOrNotImplemented])
.extract_error_mode(ExtractErrorMode::NotImplemented)
.return_self();
const __IMATMUL__: SlotDef = SlotDef::new("Py_nb_inplace_matrix_multiply", "binaryfunc")
.arguments(&[Ty::ObjectOrNotImplemented])
.extract_error_mode(ExtractErrorMode::NotImplemented)
.return_self();
const __ITRUEDIV__: SlotDef = SlotDef::new("Py_nb_inplace_true_divide", "binaryfunc")
.arguments(&[Ty::ObjectOrNotImplemented])
.extract_error_mode(ExtractErrorMode::NotImplemented)
.return_self();
const __IFLOORDIV__: SlotDef = SlotDef::new("Py_nb_inplace_floor_divide", "binaryfunc")
.arguments(&[Ty::ObjectOrNotImplemented])
.extract_error_mode(ExtractErrorMode::NotImplemented)
.return_self();
const __IMOD__: SlotDef = SlotDef::new("Py_nb_inplace_remainder", "binaryfunc")
.arguments(&[Ty::ObjectOrNotImplemented])
.extract_error_mode(ExtractErrorMode::NotImplemented)
.return_self();
const __IPOW__: SlotDef = SlotDef::new("Py_nb_inplace_power", "ternaryfunc")
.arguments(&[Ty::ObjectOrNotImplemented, Ty::ObjectOrNotImplemented])
.extract_error_mode(ExtractErrorMode::NotImplemented)
.return_self();
const __ILSHIFT__: SlotDef = SlotDef::new("Py_nb_inplace_lshift", "binaryfunc")
.arguments(&[Ty::ObjectOrNotImplemented])
.extract_error_mode(ExtractErrorMode::NotImplemented)
.return_self();
const __IRSHIFT__: SlotDef = SlotDef::new("Py_nb_inplace_rshift", "binaryfunc")
.arguments(&[Ty::ObjectOrNotImplemented])
.extract_error_mode(ExtractErrorMode::NotImplemented)
.return_self();
const __IAND__: SlotDef = SlotDef::new("Py_nb_inplace_and", "binaryfunc")
.arguments(&[Ty::ObjectOrNotImplemented])
.extract_error_mode(ExtractErrorMode::NotImplemented)
.return_self();
const __IXOR__: SlotDef = SlotDef::new("Py_nb_inplace_xor", "binaryfunc")
.arguments(&[Ty::ObjectOrNotImplemented])
.extract_error_mode(ExtractErrorMode::NotImplemented)
.return_self();
const __IOR__: SlotDef = SlotDef::new("Py_nb_inplace_or", "binaryfunc")
.arguments(&[Ty::ObjectOrNotImplemented])
.extract_error_mode(ExtractErrorMode::NotImplemented)
.return_self();
fn pyproto(method_name: &str) -> Option<&'static SlotDef> {
@ -659,6 +682,7 @@ struct SlotDef {
arguments: &'static [Ty],
ret_ty: Ty,
before_call_method: Option<TokenGenerator>,
extract_error_mode: ExtractErrorMode,
return_mode: Option<ReturnMode>,
}
@ -670,6 +694,7 @@ impl SlotDef {
arguments: &[],
ret_ty: Ty::Object,
before_call_method: None,
extract_error_mode: ExtractErrorMode::Raise,
return_mode: None,
}
}
@ -694,6 +719,11 @@ impl SlotDef {
self
}
const fn extract_error_mode(mut self, extract_error_mode: ExtractErrorMode) -> Self {
self.extract_error_mode = extract_error_mode;
self
}
const fn return_self(mut self) -> Self {
self.return_mode = Some(ReturnMode::ReturnSelf);
self
@ -705,13 +735,21 @@ impl SlotDef {
func_ty,
before_call_method,
arguments,
extract_error_mode,
ret_ty,
return_mode,
} = self;
let py = syn::Ident::new("_py", Span::call_site());
let method_arguments = generate_method_arguments(arguments);
let ret_ty = ret_ty.ffi_type();
let body = generate_method_body(cls, spec, &py, arguments, ExtractErrorMode::Raise, return_mode.as_ref())?;
let body = generate_method_body(
cls,
spec,
&py,
arguments,
*extract_error_mode,
return_mode.as_ref(),
)?;
Ok(quote!({
unsafe extern "C" fn __wrap(_raw_slf: *mut ::pyo3::ffi::PyObject, #(#method_arguments),*) -> #ret_ty {
let _slf = _raw_slf;
@ -765,6 +803,7 @@ fn generate_method_body(
struct SlotFragmentDef {
fragment: &'static str,
arguments: &'static [Ty],
extract_error_mode: ExtractErrorMode,
ret_ty: Ty,
}
@ -773,10 +812,16 @@ impl SlotFragmentDef {
SlotFragmentDef {
fragment,
arguments,
extract_error_mode: ExtractErrorMode::Raise,
ret_ty: Ty::Void,
}
}
const fn extract_error_mode(mut self, extract_error_mode: ExtractErrorMode) -> Self {
self.extract_error_mode = extract_error_mode;
self
}
const fn ret_ty(mut self, ret_ty: Ty) -> Self {
self.ret_ty = ret_ty;
self
@ -786,19 +831,17 @@ impl SlotFragmentDef {
let SlotFragmentDef {
fragment,
arguments,
extract_error_mode,
ret_ty,
} = self;
let fragment_trait = format_ident!("PyClass{}SlotFragment", fragment);
let implemented = format_ident!("{}implemented", fragment);
let method = syn::Ident::new(fragment, Span::call_site());
let py = syn::Ident::new("_py", Span::call_site());
let method_arguments = generate_method_arguments(arguments);
let body = generate_method_body(cls, spec, &py, arguments, ExtractErrorMode::NotImplemented, None)?;
let body = generate_method_body(cls, spec, &py, arguments, *extract_error_mode, None)?;
let ret_ty = ret_ty.ffi_type();
Ok(quote! {
impl ::pyo3::class::impl_::#fragment_trait<#cls> for ::pyo3::class::impl_::PyClassImplCollector<#cls> {
#[inline]
fn #implemented(self) -> bool { true }
#[inline]
unsafe fn #method(
@ -817,21 +860,43 @@ impl SlotFragmentDef {
const __SETATTR__: SlotFragmentDef =
SlotFragmentDef::new("__setattr__", &[Ty::Object, Ty::NonNullObject]);
const __DELATTR__: SlotFragmentDef =
SlotFragmentDef::new("__delattr__", &[Ty::Object]);
const __SET__: SlotFragmentDef =
SlotFragmentDef::new("__set__", &[Ty::Object, Ty::NonNullObject]);
const __DELETE__: SlotFragmentDef =
SlotFragmentDef::new("__delete__", &[Ty::Object]);
const __DELATTR__: SlotFragmentDef = SlotFragmentDef::new("__delattr__", &[Ty::Object]);
const __SET__: SlotFragmentDef = SlotFragmentDef::new("__set__", &[Ty::Object, Ty::NonNullObject]);
const __DELETE__: SlotFragmentDef = SlotFragmentDef::new("__delete__", &[Ty::Object]);
const __SETITEM__: SlotFragmentDef =
SlotFragmentDef::new("__setitem__", &[Ty::Object, Ty::NonNullObject]);
const __DELITEM__: SlotFragmentDef =
SlotFragmentDef::new("__delitem__", &[Ty::Object]);
const __DELITEM__: SlotFragmentDef = SlotFragmentDef::new("__delitem__", &[Ty::Object]);
const __ADD__: SlotFragmentDef =
SlotFragmentDef::new("__add__", &[Ty::ObjectOrNotImplemented]).ret_ty(Ty::Object);
const __RADD__: SlotFragmentDef =
SlotFragmentDef::new("__radd__", &[Ty::ObjectOrNotImplemented]).ret_ty(Ty::Object);
macro_rules! binary_num_slot_fragment_def {
($ident:ident, $name:literal) => {
const $ident: SlotFragmentDef = SlotFragmentDef::new($name, &[Ty::ObjectOrNotImplemented])
.extract_error_mode(ExtractErrorMode::NotImplemented)
.ret_ty(Ty::Object);
};
}
binary_num_slot_fragment_def!(__ADD__, "__add__");
binary_num_slot_fragment_def!(__RADD__, "__radd__");
binary_num_slot_fragment_def!(__SUB__, "__sub__");
binary_num_slot_fragment_def!(__RSUB__, "__rsub__");
binary_num_slot_fragment_def!(__MUL__, "__mul__");
binary_num_slot_fragment_def!(__RMUL__, "__rmul__");
binary_num_slot_fragment_def!(__MATMUL__, "__matmul__");
binary_num_slot_fragment_def!(__RMATMUL__, "__rmatmul__");
binary_num_slot_fragment_def!(__DIVMOD__, "__divmod__");
binary_num_slot_fragment_def!(__RDIVMOD__, "__rdivmod__");
binary_num_slot_fragment_def!(__MOD__, "__mod__");
binary_num_slot_fragment_def!(__RMOD__, "__rmod__");
binary_num_slot_fragment_def!(__LSHIFT__, "__lshift__");
binary_num_slot_fragment_def!(__RLSHIFT__, "__rlshift__");
binary_num_slot_fragment_def!(__RSHIFT__, "__rshift__");
binary_num_slot_fragment_def!(__RRSHIFT__, "__rrshift__");
binary_num_slot_fragment_def!(__AND__, "__and__");
binary_num_slot_fragment_def!(__RAND__, "__rand__");
binary_num_slot_fragment_def!(__XOR__, "__xor__");
binary_num_slot_fragment_def!(__RXOR__, "__rxor__");
binary_num_slot_fragment_def!(__OR__, "__or__");
binary_num_slot_fragment_def!(__ROR__, "__ror__");
fn pyproto_fragment(method_name: &str) -> Option<&'static SlotFragmentDef> {
match method_name {
@ -843,6 +908,26 @@ fn pyproto_fragment(method_name: &str) -> Option<&'static SlotFragmentDef> {
"__delitem__" => Some(&__DELITEM__),
"__add__" => Some(&__ADD__),
"__radd__" => Some(&__RADD__),
"__sub__" => Some(&__SUB__),
"__rsub__" => Some(&__RSUB__),
"__mul__" => Some(&__MUL__),
"__rmul__" => Some(&__RMUL__),
"__matmul__" => Some(&__MATMUL__),
"__rmatmul__" => Some(&__RMATMUL__),
"__divmod__" => Some(&__DIVMOD__),
"__rdivmod__" => Some(&__RDIVMOD__),
"__mod__" => Some(&__MOD__),
"__rmod__" => Some(&__RMOD__),
"__lshift__" => Some(&__LSHIFT__),
"__rlshift__" => Some(&__RLSHIFT__),
"__rshift__" => Some(&__RSHIFT__),
"__rrshift__" => Some(&__RRSHIFT__),
"__and__" => Some(&__AND__),
"__rand__" => Some(&__RAND__),
"__xor__" => Some(&__XOR__),
"__rxor__" => Some(&__RXOR__),
"__or__" => Some(&__OR__),
"__ror__" => Some(&__ROR__),
_ => None,
}
}

View file

@ -109,15 +109,9 @@ impl<T> PyClassCallImpl<T> for &'_ PyClassImplCollector<T> {
}
macro_rules! slot_fragment_trait {
($trait_name:ident, $implemented_name:ident, $($default_method:tt)*) => {
($trait_name:ident, $($default_method:tt)*) => {
#[allow(non_camel_case_types)]
pub trait $trait_name<T>: Sized {
#[inline]
#[allow(non_snake_case)]
fn $implemented_name(self) -> bool {
false
}
$($default_method)*
}
@ -133,8 +127,6 @@ macro_rules! define_pyclass_setattr_slot {
(
$set_trait:ident,
$del_trait:ident,
$set_implemented:ident,
$del_implemented:ident,
$set:ident,
$del:ident,
$set_error:expr,
@ -145,7 +137,6 @@ macro_rules! define_pyclass_setattr_slot {
) => {
slot_fragment_trait! {
$set_trait,
$set_implemented,
/// # Safety: _slf and _attr must be valid non-null Python objects
#[inline]
@ -162,7 +153,6 @@ macro_rules! define_pyclass_setattr_slot {
slot_fragment_trait! {
$del_trait,
$del_implemented,
/// # Safety: _slf and _attr must be valid non-null Python objects
#[inline]
@ -180,31 +170,26 @@ macro_rules! define_pyclass_setattr_slot {
#[macro_export]
macro_rules! $generate_macro {
($cls:ty) => {{
use ::std::option::Option::*;
use $crate::class::impl_::*;
let collector = PyClassImplCollector::<$cls>::new();
if collector.$set_implemented() || collector.$del_implemented() {
unsafe extern "C" fn __wrap(
_slf: *mut $crate::ffi::PyObject,
attr: *mut $crate::ffi::PyObject,
value: *mut $crate::ffi::PyObject,
) -> ::std::os::raw::c_int {
use $crate::callback::IntoPyCallbackOutput;
$crate::callback::handle_panic(|py| {
let collector = PyClassImplCollector::<$cls>::new();
if let Some(value) = ::std::ptr::NonNull::new(value) {
collector.$set(py, _slf, attr, value).convert(py)
} else {
collector.$del(py, _slf, attr).convert(py)
}
})
}
Some($crate::ffi::PyType_Slot {
slot: $crate::ffi::$slot,
pfunc: __wrap as $crate::ffi::$func_ty as _,
unsafe extern "C" fn __wrap(
_slf: *mut $crate::ffi::PyObject,
attr: *mut $crate::ffi::PyObject,
value: *mut $crate::ffi::PyObject,
) -> ::std::os::raw::c_int {
use ::std::option::Option::*;
use $crate::callback::IntoPyCallbackOutput;
use $crate::class::impl_::*;
$crate::callback::handle_panic(|py| {
let collector = PyClassImplCollector::<$cls>::new();
if let Some(value) = ::std::ptr::NonNull::new(value) {
collector.$set(py, _slf, attr, value).convert(py)
} else {
collector.$del(py, _slf, attr).convert(py)
}
})
} else {
None
}
$crate::ffi::PyType_Slot {
slot: $crate::ffi::$slot,
pfunc: __wrap as $crate::ffi::$func_ty as _,
}
}};
}
@ -214,8 +199,6 @@ macro_rules! define_pyclass_setattr_slot {
define_pyclass_setattr_slot! {
PyClass__setattr__SlotFragment,
PyClass__delattr__SlotFragment,
__setattr__implemented,
__delattr__implemented,
__setattr__,
__delattr__,
Err(PyAttributeError::new_err("can't set attribute")),
@ -228,8 +211,6 @@ define_pyclass_setattr_slot! {
define_pyclass_setattr_slot! {
PyClass__set__SlotFragment,
PyClass__delete__SlotFragment,
__set__implemented,
__delete__implemented,
__set__,
__delete__,
Err(PyNotImplementedError::new_err("can't set descriptor")),
@ -242,8 +223,6 @@ define_pyclass_setattr_slot! {
define_pyclass_setattr_slot! {
PyClass__setitem__SlotFragment,
PyClass__delitem__SlotFragment,
__setitem__implemented,
__delitem__implemented,
__setitem__,
__delitem__,
Err(PyNotImplementedError::new_err("can't set item")),
@ -261,8 +240,6 @@ macro_rules! define_pyclass_binary_operator_slot {
(
$lhs_trait:ident,
$rhs_trait:ident,
$lhs_implemented:ident,
$rhs_implemented:ident,
$lhs:ident,
$rhs:ident,
$generate_macro:ident,
@ -271,7 +248,6 @@ macro_rules! define_pyclass_binary_operator_slot {
) => {
slot_fragment_trait! {
$lhs_trait,
$lhs_implemented,
/// # Safety: _slf and _attr must be valid non-null Python objects
#[inline]
@ -288,7 +264,6 @@ macro_rules! define_pyclass_binary_operator_slot {
slot_fragment_trait! {
$rhs_trait,
$rhs_implemented,
/// # Safety: _slf and _attr must be valid non-null Python objects
#[inline]
@ -307,31 +282,25 @@ macro_rules! define_pyclass_binary_operator_slot {
#[macro_export]
macro_rules! $generate_macro {
($cls:ty) => {{
use ::std::option::Option::*;
use $crate::class::impl_::*;
let collector = PyClassImplCollector::<$cls>::new();
if collector.$lhs_implemented() || collector.$rhs_implemented() {
unsafe extern "C" fn __wrap(
_slf: *mut $crate::ffi::PyObject,
_other: *mut $crate::ffi::PyObject,
) -> *mut $crate::ffi::PyObject {
$crate::callback::handle_panic(|py| {
let collector = PyClassImplCollector::<$cls>::new();
let lhs_result = collector.$lhs(py, _slf, _other)?;
if lhs_result == $crate::ffi::Py_NotImplemented() {
$crate::ffi::Py_DECREF(lhs_result);
collector.$rhs(py, _other, _slf)
} else {
::std::result::Result::Ok(lhs_result)
}
})
}
Some($crate::ffi::PyType_Slot {
slot: $crate::ffi::$slot,
pfunc: __wrap as $crate::ffi::$func_ty as _,
unsafe extern "C" fn __wrap(
_slf: *mut $crate::ffi::PyObject,
_other: *mut $crate::ffi::PyObject,
) -> *mut $crate::ffi::PyObject {
$crate::callback::handle_panic(|py| {
use ::pyo3::class::impl_::*;
let collector = PyClassImplCollector::<$cls>::new();
let lhs_result = collector.$lhs(py, _slf, _other)?;
if lhs_result == $crate::ffi::Py_NotImplemented() {
$crate::ffi::Py_DECREF(lhs_result);
collector.$rhs(py, _other, _slf)
} else {
::std::result::Result::Ok(lhs_result)
}
})
} else {
None
}
$crate::ffi::PyType_Slot {
slot: $crate::ffi::$slot,
pfunc: __wrap as $crate::ffi::$func_ty as _,
}
}};
}
@ -341,8 +310,6 @@ macro_rules! define_pyclass_binary_operator_slot {
define_pyclass_binary_operator_slot! {
PyClass__add__SlotFragment,
PyClass__radd__SlotFragment,
__add__implemented,
__radd__implemented,
__add__,
__radd__,
generate_pyclass_add_slot,
@ -353,8 +320,6 @@ define_pyclass_binary_operator_slot! {
define_pyclass_binary_operator_slot! {
PyClass__sub__SlotFragment,
PyClass__rsub__SlotFragment,
__sub__implemented,
__rsub__implemented,
__sub__,
__rsub__,
generate_pyclass_sub_slot,
@ -365,8 +330,6 @@ define_pyclass_binary_operator_slot! {
define_pyclass_binary_operator_slot! {
PyClass__mul__SlotFragment,
PyClass__rmul__SlotFragment,
__mul__implemented,
__rmul__implemented,
__mul__,
__rmul__,
generate_pyclass_mul_slot,
@ -377,8 +340,6 @@ define_pyclass_binary_operator_slot! {
define_pyclass_binary_operator_slot! {
PyClass__mod__SlotFragment,
PyClass__rmod__SlotFragment,
__mod__implemented,
__rmod__implemented,
__mod__,
__rmod__,
generate_pyclass_mod_slot,
@ -389,8 +350,6 @@ define_pyclass_binary_operator_slot! {
define_pyclass_binary_operator_slot! {
PyClass__divmod__SlotFragment,
PyClass__rdivmod__SlotFragment,
__divmod__implemented,
__rdivmod__implemented,
__divmod__,
__rdivmod__,
generate_pyclass_divmod_slot,
@ -401,8 +360,6 @@ define_pyclass_binary_operator_slot! {
define_pyclass_binary_operator_slot! {
PyClass__lshift__SlotFragment,
PyClass__rlshift__SlotFragment,
__lshift__implemented,
__rlshift__implemented,
__lshift__,
__rlshift__,
generate_pyclass_lshift_slot,
@ -413,8 +370,6 @@ define_pyclass_binary_operator_slot! {
define_pyclass_binary_operator_slot! {
PyClass__rshift__SlotFragment,
PyClass__rrshift__SlotFragment,
__rshift__implemented,
__rrshift__implemented,
__rshift__,
__rrshift__,
generate_pyclass_rshift_slot,
@ -425,8 +380,6 @@ define_pyclass_binary_operator_slot! {
define_pyclass_binary_operator_slot! {
PyClass__and__SlotFragment,
PyClass__rand__SlotFragment,
__and__implemented,
__rand__implemented,
__and__,
__rand__,
generate_pyclass_and_slot,
@ -437,8 +390,6 @@ define_pyclass_binary_operator_slot! {
define_pyclass_binary_operator_slot! {
PyClass__or__SlotFragment,
PyClass__ror__SlotFragment,
__or__implemented,
__ror__implemented,
__or__,
__ror__,
generate_pyclass_or_slot,
@ -449,8 +400,6 @@ define_pyclass_binary_operator_slot! {
define_pyclass_binary_operator_slot! {
PyClass__xor__SlotFragment,
PyClass__rxor__SlotFragment,
__xor__implemented,
__rxor__implemented,
__xor__,
__rxor__,
generate_pyclass_xor_slot,
@ -461,8 +410,6 @@ define_pyclass_binary_operator_slot! {
define_pyclass_binary_operator_slot! {
PyClass__matmul__SlotFragment,
PyClass__rmatmul__SlotFragment,
__matmul__implemented,
__rmatmul__implemented,
__matmul__,
__rmatmul__,
generate_pyclass_matmul_slot,

View file

@ -9,7 +9,9 @@ struct UnaryArithmetic {
inner: f64,
}
#[pymethods]
impl UnaryArithmetic {
#[new]
fn new(value: f64) -> Self {
UnaryArithmetic { inner: value }
}
@ -521,7 +523,7 @@ mod return_not_implemented {
fn __mod__<'p>(slf: PyRef<'p, Self>, _other: PyRef<'p, Self>) -> PyRef<'p, Self> {
slf
}
fn __pow__<'p>(slf: PyRef<'p, Self>, _other: u8, _modulo: Option<u8>) -> PyRef<'p, Self> {
fn __pow__(slf: PyRef<Self>, _other: u8, _modulo: Option<u8>) -> PyRef<Self> {
slf
}
fn __lshift__<'p>(slf: PyRef<'p, Self>, _other: PyRef<'p, Self>) -> PyRef<'p, Self> {

View file

@ -158,14 +158,11 @@ fn test_hash() {
fn test_richcmp() {
Python::with_gil(|py| {
let example_py = make_example(py);
assert_eq!(
example_py
.rich_compare(example_py, CompareOp::Eq)
.unwrap()
.is_true()
.unwrap(),
true
);
assert!(example_py
.rich_compare(example_py, CompareOp::Eq)
.unwrap()
.is_true()
.unwrap());
})
}
@ -552,4 +549,5 @@ assert c.counter.count == 3
// TODO: test __anext__, __aiter__
// TODO: test __index__, __int__, __float__, __invert__
// TODO: __floordiv__, __truediv__
// TODO: __pow__, __rpow__
// TODO: better argument casting errors