diff --git a/pyo3-macros-backend/src/method.rs b/pyo3-macros-backend/src/method.rs index 3646e360..27b9c612 100644 --- a/pyo3-macros-backend/src/method.rs +++ b/pyo3-macros-backend/src/method.rs @@ -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 } => { diff --git a/pyo3-macros-backend/src/pyclass.rs b/pyo3-macros-backend/src/pyclass.rs index adb87ab1..baf0041a 100644 --- a/pyo3-macros-backend/src/pyclass.rs +++ b/pyo3-macros-backend/src/pyclass.rs @@ -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> { diff --git a/pyo3-macros-backend/src/pyimpl.rs b/pyo3-macros-backend/src/pyimpl.rs index 5d2dd881..4fc1c7da 100644 --- a/pyo3-macros-backend/src/pyimpl.rs +++ b/pyo3-macros-backend/src/pyimpl.rs @@ -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 { } } -fn impl_protos(ty: &syn::Type, proto_impls: Vec) -> TokenStream { +fn impl_protos( + ty: &syn::Type, + mut proto_impls: Vec, + mut implemented_proto_fragments: HashSet, +) -> 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> diff --git a/pyo3-macros-backend/src/pymethod.rs b/pyo3-macros-backend/src/pymethod.rs index b6508e58..e0698262 100644 --- a/pyo3-macros-backend/src/pymethod.rs +++ b/pyo3-macros-backend/src/pymethod.rs @@ -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, + extract_error_mode: ExtractErrorMode, return_mode: Option, } @@ -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, } } diff --git a/src/class/impl_.rs b/src/class/impl_.rs index d2fe3814..5a914868 100644 --- a/src/class/impl_.rs +++ b/src/class/impl_.rs @@ -109,15 +109,9 @@ impl PyClassCallImpl for &'_ PyClassImplCollector { } 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: 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, diff --git a/tests/test_arithmetics.rs b/tests/test_arithmetics.rs index 6f39920d..711cbfb9 100644 --- a/tests/test_arithmetics.rs +++ b/tests/test_arithmetics.rs @@ -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) -> PyRef<'p, Self> { + fn __pow__(slf: PyRef, _other: u8, _modulo: Option) -> PyRef { slf } fn __lshift__<'p>(slf: PyRef<'p, Self>, _other: PyRef<'p, Self>) -> PyRef<'p, Self> { diff --git a/tests/test_proto_methods.rs b/tests/test_proto_methods.rs index 50f1e4a4..8a12d2df 100644 --- a/tests/test_proto_methods.rs +++ b/tests/test_proto_methods.rs @@ -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