pymethods: faster compilation for protos, tidy ups
This commit is contained in:
parent
43eb762346
commit
c2d78ca76e
|
@ -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 } => {
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue