Add support for in-place numeric operators in py_class!

This commit is contained in:
Samuel Cormier-Iijima 2016-06-14 15:53:43 -04:00
parent 72e1e05835
commit 2e8d343b0f
5 changed files with 763 additions and 45 deletions

View File

@ -351,6 +351,26 @@ py_class!(class MyIterator |py| {
If you can't handle the combination of types you've been given,
you should return `Ok(py.NotImplemented())`.
* `def __iadd__(&self, other: impl ExtractPyObject) -> PyResult<impl ToPyObject>`
* `def __isub__(&self, other: impl ExtractPyObject) -> PyResult<impl ToPyObject>`
* `def __imul__(&self, other: impl ExtractPyObject) -> PyResult<impl ToPyObject>`
* `def __imatmul__(&self, other: impl ExtractPyObject) -> PyResult<impl ToPyObject>`
* `def __itruediv__(&self, other: impl ExtractPyObject) -> PyResult<impl ToPyObject>`
* `def __ifloordiv__(&self, other: impl ExtractPyObject) -> PyResult<impl ToPyObject>`
* `def __imod__(&self, other: impl ExtractPyObject) -> PyResult<impl ToPyObject>`
* `def __ilshift__(&self, other: impl ExtractPyObject) -> PyResult<impl ToPyObject>`
* `def __irshift__(&self, other: impl ExtractPyObject) -> PyResult<impl ToPyObject>`
* `def __iand__(&self, other: impl ExtractPyObject) -> PyResult<impl ToPyObject>`
* `def __ixor__(&self, other: impl ExtractPyObject) -> PyResult<impl ToPyObject>`
* `def __ior__(&self, other: impl ExtractPyObject) -> PyResult<impl ToPyObject>`
Handles inplace operations if possible, falling back to the non-inplace versions.
These methods must return a new reference! In the common case of returning the
same (mutated) object, you will want to return `Ok(self.clone_ref(py))`.
If you can't handle the combination of types you've been given,
you should return `Ok(py.NotImplemented())`.
## Context Manager
* `def __enter__(&self) -> PyResult<impl ToPyObject>`

View File

@ -584,6 +584,11 @@ def reflected_numeric_operator(special_name):
error('Reflected numeric operator %s is not supported by py_class! Use __%s__ instead!'
% (special_name, special_name[3:-2]))(special_name)
@special_method
def inplace_numeric_operator(special_name, slot):
operator(slot=slot,
args=[Argument('other')])(special_name)
special_names = {
'__init__': error('__init__ is not supported by py_class!; use __new__ instead.'),
'__new__': special_class_method(
@ -694,21 +699,20 @@ special_names = {
'__ror__': reflected_numeric_operator(),
# Emulating numeric types - in-place
'__iadd__': unimplemented(),
'__isub__': unimplemented(),
'__imul__': unimplemented(),
'__imatmul__': unimplemented(),
'__iadd__': inplace_numeric_operator('nb_inplace_add'),
'__isub__': inplace_numeric_operator('nb_inplace_subtract'),
'__imul__': inplace_numeric_operator('nb_inplace_multiply'),
'__imatmul__': inplace_numeric_operator('nb_inplace_matrix_multiply'),
'__idiv__': unimplemented(),
'__itruediv__': unimplemented(),
'__ifloordiv__': unimplemented(),
'__imod__': unimplemented(),
'__idivmod__': unimplemented(),
'__itruediv__': inplace_numeric_operator('nb_inplace_true_divide'),
'__ifloordiv__': inplace_numeric_operator('nb_inplace_floor_divide'),
'__imod__': inplace_numeric_operator('nb_inplace_remainder'),
'__ipow__': unimplemented(),
'__ilshift__': unimplemented(),
'__irshift__': unimplemented(),
'__iand__': unimplemented(),
'__ixor__': unimplemented(),
'__ior__': unimplemented(),
'__ilshift__': inplace_numeric_operator('nb_inplace_lshift'),
'__irshift__': inplace_numeric_operator('nb_inplace_rshift'),
'__iand__': inplace_numeric_operator('nb_inplace_and'),
'__ixor__': inplace_numeric_operator('nb_inplace_xor'),
'__ior__': inplace_numeric_operator('nb_inplace_or'),
# Unary arithmetic
'__neg__': operator('nb_negative'),

View File

@ -673,41 +673,219 @@ macro_rules! py_class_impl {
{ { def __hash__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "Invalid signature for operator __hash__" }
};
{ { def __iadd__(&$slf:ident, $other:ident : $other_type:ty) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
$class:ident $py:ident $info:tt
/* slots: */ {
$type_slots:tt
/* as_number */ [ $( $nb_slot_name:ident : $nb_slot_value:expr, )* ]
$as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
} => { py_class_impl! {
{ $($tail)* }
$class $py $info
/* slots: */ {
$type_slots
/* as_number */ [
$( $nb_slot_name : $nb_slot_value, )*
nb_inplace_add: py_class_binary_slot!($class::__iadd__, $other_type, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
]
$as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
py_class_impl_item! { $class, $py, __iadd__(&$slf,) $res_type; { $($body)* } [{ $other : $other_type = {} }] }
}
$members
}};
{ { def __iadd__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__iadd__ is not supported by py_class! yet." }
py_error! { "Invalid signature for operator __iadd__" }
};
{ { def __iand__(&$slf:ident, $other:ident : $other_type:ty) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
$class:ident $py:ident $info:tt
/* slots: */ {
$type_slots:tt
/* as_number */ [ $( $nb_slot_name:ident : $nb_slot_value:expr, )* ]
$as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
} => { py_class_impl! {
{ $($tail)* }
$class $py $info
/* slots: */ {
$type_slots
/* as_number */ [
$( $nb_slot_name : $nb_slot_value, )*
nb_inplace_and: py_class_binary_slot!($class::__iand__, $other_type, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
]
$as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
py_class_impl_item! { $class, $py, __iand__(&$slf,) $res_type; { $($body)* } [{ $other : $other_type = {} }] }
}
$members
}};
{ { def __iand__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__iand__ is not supported by py_class! yet." }
py_error! { "Invalid signature for operator __iand__" }
};
{ { def __idiv__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__idiv__ is not supported by py_class! yet." }
};
{ { def __idivmod__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__idivmod__ is not supported by py_class! yet." }
};
{ { def __ifloordiv__(&$slf:ident, $other:ident : $other_type:ty) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
$class:ident $py:ident $info:tt
/* slots: */ {
$type_slots:tt
/* as_number */ [ $( $nb_slot_name:ident : $nb_slot_value:expr, )* ]
$as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
} => { py_class_impl! {
{ $($tail)* }
$class $py $info
/* slots: */ {
$type_slots
/* as_number */ [
$( $nb_slot_name : $nb_slot_value, )*
nb_inplace_floor_divide: py_class_binary_slot!($class::__ifloordiv__, $other_type, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
]
$as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
py_class_impl_item! { $class, $py, __ifloordiv__(&$slf,) $res_type; { $($body)* } [{ $other : $other_type = {} }] }
}
$members
}};
{ { def __ifloordiv__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__ifloordiv__ is not supported by py_class! yet." }
py_error! { "Invalid signature for operator __ifloordiv__" }
};
{ { def __ilshift__(&$slf:ident, $other:ident : $other_type:ty) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
$class:ident $py:ident $info:tt
/* slots: */ {
$type_slots:tt
/* as_number */ [ $( $nb_slot_name:ident : $nb_slot_value:expr, )* ]
$as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
} => { py_class_impl! {
{ $($tail)* }
$class $py $info
/* slots: */ {
$type_slots
/* as_number */ [
$( $nb_slot_name : $nb_slot_value, )*
nb_inplace_lshift: py_class_binary_slot!($class::__ilshift__, $other_type, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
]
$as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
py_class_impl_item! { $class, $py, __ilshift__(&$slf,) $res_type; { $($body)* } [{ $other : $other_type = {} }] }
}
$members
}};
{ { def __ilshift__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__ilshift__ is not supported by py_class! yet." }
py_error! { "Invalid signature for operator __ilshift__" }
};
{ { def __imatmul__(&$slf:ident, $other:ident : $other_type:ty) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
$class:ident $py:ident $info:tt
/* slots: */ {
$type_slots:tt
/* as_number */ [ $( $nb_slot_name:ident : $nb_slot_value:expr, )* ]
$as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
} => { py_class_impl! {
{ $($tail)* }
$class $py $info
/* slots: */ {
$type_slots
/* as_number */ [
$( $nb_slot_name : $nb_slot_value, )*
nb_inplace_matrix_multiply: py_class_binary_slot!($class::__imatmul__, $other_type, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
]
$as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
py_class_impl_item! { $class, $py, __imatmul__(&$slf,) $res_type; { $($body)* } [{ $other : $other_type = {} }] }
}
$members
}};
{ { def __imatmul__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__imatmul__ is not supported by py_class! yet." }
py_error! { "Invalid signature for operator __imatmul__" }
};
{ { def __imod__(&$slf:ident, $other:ident : $other_type:ty) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
$class:ident $py:ident $info:tt
/* slots: */ {
$type_slots:tt
/* as_number */ [ $( $nb_slot_name:ident : $nb_slot_value:expr, )* ]
$as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
} => { py_class_impl! {
{ $($tail)* }
$class $py $info
/* slots: */ {
$type_slots
/* as_number */ [
$( $nb_slot_name : $nb_slot_value, )*
nb_inplace_remainder: py_class_binary_slot!($class::__imod__, $other_type, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
]
$as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
py_class_impl_item! { $class, $py, __imod__(&$slf,) $res_type; { $($body)* } [{ $other : $other_type = {} }] }
}
$members
}};
{ { def __imod__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__imod__ is not supported by py_class! yet." }
py_error! { "Invalid signature for operator __imod__" }
};
{ { def __imul__(&$slf:ident, $other:ident : $other_type:ty) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
$class:ident $py:ident $info:tt
/* slots: */ {
$type_slots:tt
/* as_number */ [ $( $nb_slot_name:ident : $nb_slot_value:expr, )* ]
$as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
} => { py_class_impl! {
{ $($tail)* }
$class $py $info
/* slots: */ {
$type_slots
/* as_number */ [
$( $nb_slot_name : $nb_slot_value, )*
nb_inplace_multiply: py_class_binary_slot!($class::__imul__, $other_type, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
]
$as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
py_class_impl_item! { $class, $py, __imul__(&$slf,) $res_type; { $($body)* } [{ $other : $other_type = {} }] }
}
$members
}};
{ { def __imul__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__imul__ is not supported by py_class! yet." }
py_error! { "Invalid signature for operator __imul__" }
};
{ { def __index__ $($tail:tt)* } $( $stuff:tt )* } => {
@ -755,21 +933,99 @@ macro_rules! py_class_impl {
{ { def __invert__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "Invalid signature for operator __invert__" }
};
{ { def __ior__(&$slf:ident, $other:ident : $other_type:ty) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
$class:ident $py:ident $info:tt
/* slots: */ {
$type_slots:tt
/* as_number */ [ $( $nb_slot_name:ident : $nb_slot_value:expr, )* ]
$as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
} => { py_class_impl! {
{ $($tail)* }
$class $py $info
/* slots: */ {
$type_slots
/* as_number */ [
$( $nb_slot_name : $nb_slot_value, )*
nb_inplace_or: py_class_binary_slot!($class::__ior__, $other_type, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
]
$as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
py_class_impl_item! { $class, $py, __ior__(&$slf,) $res_type; { $($body)* } [{ $other : $other_type = {} }] }
}
$members
}};
{ { def __ior__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__ior__ is not supported by py_class! yet." }
py_error! { "Invalid signature for operator __ior__" }
};
{ { def __ipow__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__ipow__ is not supported by py_class! yet." }
};
{ { def __irshift__(&$slf:ident, $other:ident : $other_type:ty) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
$class:ident $py:ident $info:tt
/* slots: */ {
$type_slots:tt
/* as_number */ [ $( $nb_slot_name:ident : $nb_slot_value:expr, )* ]
$as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
} => { py_class_impl! {
{ $($tail)* }
$class $py $info
/* slots: */ {
$type_slots
/* as_number */ [
$( $nb_slot_name : $nb_slot_value, )*
nb_inplace_rshift: py_class_binary_slot!($class::__irshift__, $other_type, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
]
$as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
py_class_impl_item! { $class, $py, __irshift__(&$slf,) $res_type; { $($body)* } [{ $other : $other_type = {} }] }
}
$members
}};
{ { def __irshift__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__irshift__ is not supported by py_class! yet." }
py_error! { "Invalid signature for operator __irshift__" }
};
{ { def __isub__(&$slf:ident, $other:ident : $other_type:ty) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
$class:ident $py:ident $info:tt
/* slots: */ {
$type_slots:tt
/* as_number */ [ $( $nb_slot_name:ident : $nb_slot_value:expr, )* ]
$as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
} => { py_class_impl! {
{ $($tail)* }
$class $py $info
/* slots: */ {
$type_slots
/* as_number */ [
$( $nb_slot_name : $nb_slot_value, )*
nb_inplace_subtract: py_class_binary_slot!($class::__isub__, $other_type, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
]
$as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
py_class_impl_item! { $class, $py, __isub__(&$slf,) $res_type; { $($body)* } [{ $other : $other_type = {} }] }
}
$members
}};
{ { def __isub__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__isub__ is not supported by py_class! yet." }
py_error! { "Invalid signature for operator __isub__" }
};
{ { def __iter__(&$slf:ident) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
$class:ident $py:ident $info:tt
@ -799,13 +1055,65 @@ macro_rules! py_class_impl {
{ { def __iter__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "Invalid signature for operator __iter__" }
};
{ { def __itruediv__(&$slf:ident, $other:ident : $other_type:ty) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
$class:ident $py:ident $info:tt
/* slots: */ {
$type_slots:tt
/* as_number */ [ $( $nb_slot_name:ident : $nb_slot_value:expr, )* ]
$as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
} => { py_class_impl! {
{ $($tail)* }
$class $py $info
/* slots: */ {
$type_slots
/* as_number */ [
$( $nb_slot_name : $nb_slot_value, )*
nb_inplace_true_divide: py_class_binary_slot!($class::__itruediv__, $other_type, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
]
$as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
py_class_impl_item! { $class, $py, __itruediv__(&$slf,) $res_type; { $($body)* } [{ $other : $other_type = {} }] }
}
$members
}};
{ { def __itruediv__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__itruediv__ is not supported by py_class! yet." }
py_error! { "Invalid signature for operator __itruediv__" }
};
{ { def __ixor__(&$slf:ident, $other:ident : $other_type:ty) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
$class:ident $py:ident $info:tt
/* slots: */ {
$type_slots:tt
/* as_number */ [ $( $nb_slot_name:ident : $nb_slot_value:expr, )* ]
$as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
} => { py_class_impl! {
{ $($tail)* }
$class $py $info
/* slots: */ {
$type_slots
/* as_number */ [
$( $nb_slot_name : $nb_slot_value, )*
nb_inplace_xor: py_class_binary_slot!($class::__ixor__, $other_type, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
]
$as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
py_class_impl_item! { $class, $py, __ixor__(&$slf,) $res_type; { $($body)* } [{ $other : $other_type = {} }] }
}
$members
}};
{ { def __ixor__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__ixor__ is not supported by py_class! yet." }
py_error! { "Invalid signature for operator __ixor__" }
};
{ { def __le__ $($tail:tt)* } $( $stuff:tt )* } => {

View File

@ -673,41 +673,219 @@ macro_rules! py_class_impl {
{ { def __hash__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "Invalid signature for operator __hash__" }
};
{ { def __iadd__(&$slf:ident, $other:ident : $other_type:ty) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
$class:ident $py:ident $info:tt
/* slots: */ {
$type_slots:tt
/* as_number */ [ $( $nb_slot_name:ident : $nb_slot_value:expr, )* ]
$as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
} => { py_class_impl! {
{ $($tail)* }
$class $py $info
/* slots: */ {
$type_slots
/* as_number */ [
$( $nb_slot_name : $nb_slot_value, )*
nb_inplace_add: py_class_binary_slot!($class::__iadd__, $other_type, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
]
$as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
py_class_impl_item! { $class, $py, __iadd__(&$slf,) $res_type; { $($body)* } [{ $other : $other_type = {} }] }
}
$members
}};
{ { def __iadd__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__iadd__ is not supported by py_class! yet." }
py_error! { "Invalid signature for operator __iadd__" }
};
{ { def __iand__(&$slf:ident, $other:ident : $other_type:ty) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
$class:ident $py:ident $info:tt
/* slots: */ {
$type_slots:tt
/* as_number */ [ $( $nb_slot_name:ident : $nb_slot_value:expr, )* ]
$as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
} => { py_class_impl! {
{ $($tail)* }
$class $py $info
/* slots: */ {
$type_slots
/* as_number */ [
$( $nb_slot_name : $nb_slot_value, )*
nb_inplace_and: py_class_binary_slot!($class::__iand__, $other_type, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
]
$as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
py_class_impl_item! { $class, $py, __iand__(&$slf,) $res_type; { $($body)* } [{ $other : $other_type = {} }] }
}
$members
}};
{ { def __iand__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__iand__ is not supported by py_class! yet." }
py_error! { "Invalid signature for operator __iand__" }
};
{ { def __idiv__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__idiv__ is not supported by py_class! yet." }
};
{ { def __idivmod__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__idivmod__ is not supported by py_class! yet." }
};
{ { def __ifloordiv__(&$slf:ident, $other:ident : $other_type:ty) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
$class:ident $py:ident $info:tt
/* slots: */ {
$type_slots:tt
/* as_number */ [ $( $nb_slot_name:ident : $nb_slot_value:expr, )* ]
$as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
} => { py_class_impl! {
{ $($tail)* }
$class $py $info
/* slots: */ {
$type_slots
/* as_number */ [
$( $nb_slot_name : $nb_slot_value, )*
nb_inplace_floor_divide: py_class_binary_slot!($class::__ifloordiv__, $other_type, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
]
$as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
py_class_impl_item! { $class, $py, __ifloordiv__(&$slf,) $res_type; { $($body)* } [{ $other : $other_type = {} }] }
}
$members
}};
{ { def __ifloordiv__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__ifloordiv__ is not supported by py_class! yet." }
py_error! { "Invalid signature for operator __ifloordiv__" }
};
{ { def __ilshift__(&$slf:ident, $other:ident : $other_type:ty) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
$class:ident $py:ident $info:tt
/* slots: */ {
$type_slots:tt
/* as_number */ [ $( $nb_slot_name:ident : $nb_slot_value:expr, )* ]
$as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
} => { py_class_impl! {
{ $($tail)* }
$class $py $info
/* slots: */ {
$type_slots
/* as_number */ [
$( $nb_slot_name : $nb_slot_value, )*
nb_inplace_lshift: py_class_binary_slot!($class::__ilshift__, $other_type, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
]
$as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
py_class_impl_item! { $class, $py, __ilshift__(&$slf,) $res_type; { $($body)* } [{ $other : $other_type = {} }] }
}
$members
}};
{ { def __ilshift__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__ilshift__ is not supported by py_class! yet." }
py_error! { "Invalid signature for operator __ilshift__" }
};
{ { def __imatmul__(&$slf:ident, $other:ident : $other_type:ty) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
$class:ident $py:ident $info:tt
/* slots: */ {
$type_slots:tt
/* as_number */ [ $( $nb_slot_name:ident : $nb_slot_value:expr, )* ]
$as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
} => { py_class_impl! {
{ $($tail)* }
$class $py $info
/* slots: */ {
$type_slots
/* as_number */ [
$( $nb_slot_name : $nb_slot_value, )*
nb_inplace_matrix_multiply: py_class_binary_slot!($class::__imatmul__, $other_type, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
]
$as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
py_class_impl_item! { $class, $py, __imatmul__(&$slf,) $res_type; { $($body)* } [{ $other : $other_type = {} }] }
}
$members
}};
{ { def __imatmul__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__imatmul__ is not supported by py_class! yet." }
py_error! { "Invalid signature for operator __imatmul__" }
};
{ { def __imod__(&$slf:ident, $other:ident : $other_type:ty) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
$class:ident $py:ident $info:tt
/* slots: */ {
$type_slots:tt
/* as_number */ [ $( $nb_slot_name:ident : $nb_slot_value:expr, )* ]
$as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
} => { py_class_impl! {
{ $($tail)* }
$class $py $info
/* slots: */ {
$type_slots
/* as_number */ [
$( $nb_slot_name : $nb_slot_value, )*
nb_inplace_remainder: py_class_binary_slot!($class::__imod__, $other_type, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
]
$as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
py_class_impl_item! { $class, $py, __imod__(&$slf,) $res_type; { $($body)* } [{ $other : $other_type = {} }] }
}
$members
}};
{ { def __imod__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__imod__ is not supported by py_class! yet." }
py_error! { "Invalid signature for operator __imod__" }
};
{ { def __imul__(&$slf:ident, $other:ident : $other_type:ty) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
$class:ident $py:ident $info:tt
/* slots: */ {
$type_slots:tt
/* as_number */ [ $( $nb_slot_name:ident : $nb_slot_value:expr, )* ]
$as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
} => { py_class_impl! {
{ $($tail)* }
$class $py $info
/* slots: */ {
$type_slots
/* as_number */ [
$( $nb_slot_name : $nb_slot_value, )*
nb_inplace_multiply: py_class_binary_slot!($class::__imul__, $other_type, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
]
$as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
py_class_impl_item! { $class, $py, __imul__(&$slf,) $res_type; { $($body)* } [{ $other : $other_type = {} }] }
}
$members
}};
{ { def __imul__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__imul__ is not supported by py_class! yet." }
py_error! { "Invalid signature for operator __imul__" }
};
{ { def __index__ $($tail:tt)* } $( $stuff:tt )* } => {
@ -755,21 +933,99 @@ macro_rules! py_class_impl {
{ { def __invert__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "Invalid signature for operator __invert__" }
};
{ { def __ior__(&$slf:ident, $other:ident : $other_type:ty) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
$class:ident $py:ident $info:tt
/* slots: */ {
$type_slots:tt
/* as_number */ [ $( $nb_slot_name:ident : $nb_slot_value:expr, )* ]
$as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
} => { py_class_impl! {
{ $($tail)* }
$class $py $info
/* slots: */ {
$type_slots
/* as_number */ [
$( $nb_slot_name : $nb_slot_value, )*
nb_inplace_or: py_class_binary_slot!($class::__ior__, $other_type, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
]
$as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
py_class_impl_item! { $class, $py, __ior__(&$slf,) $res_type; { $($body)* } [{ $other : $other_type = {} }] }
}
$members
}};
{ { def __ior__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__ior__ is not supported by py_class! yet." }
py_error! { "Invalid signature for operator __ior__" }
};
{ { def __ipow__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__ipow__ is not supported by py_class! yet." }
};
{ { def __irshift__(&$slf:ident, $other:ident : $other_type:ty) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
$class:ident $py:ident $info:tt
/* slots: */ {
$type_slots:tt
/* as_number */ [ $( $nb_slot_name:ident : $nb_slot_value:expr, )* ]
$as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
} => { py_class_impl! {
{ $($tail)* }
$class $py $info
/* slots: */ {
$type_slots
/* as_number */ [
$( $nb_slot_name : $nb_slot_value, )*
nb_inplace_rshift: py_class_binary_slot!($class::__irshift__, $other_type, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
]
$as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
py_class_impl_item! { $class, $py, __irshift__(&$slf,) $res_type; { $($body)* } [{ $other : $other_type = {} }] }
}
$members
}};
{ { def __irshift__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__irshift__ is not supported by py_class! yet." }
py_error! { "Invalid signature for operator __irshift__" }
};
{ { def __isub__(&$slf:ident, $other:ident : $other_type:ty) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
$class:ident $py:ident $info:tt
/* slots: */ {
$type_slots:tt
/* as_number */ [ $( $nb_slot_name:ident : $nb_slot_value:expr, )* ]
$as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
} => { py_class_impl! {
{ $($tail)* }
$class $py $info
/* slots: */ {
$type_slots
/* as_number */ [
$( $nb_slot_name : $nb_slot_value, )*
nb_inplace_subtract: py_class_binary_slot!($class::__isub__, $other_type, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
]
$as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
py_class_impl_item! { $class, $py, __isub__(&$slf,) $res_type; { $($body)* } [{ $other : $other_type = {} }] }
}
$members
}};
{ { def __isub__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__isub__ is not supported by py_class! yet." }
py_error! { "Invalid signature for operator __isub__" }
};
{ { def __iter__(&$slf:ident) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
$class:ident $py:ident $info:tt
@ -799,13 +1055,65 @@ macro_rules! py_class_impl {
{ { def __iter__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "Invalid signature for operator __iter__" }
};
{ { def __itruediv__(&$slf:ident, $other:ident : $other_type:ty) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
$class:ident $py:ident $info:tt
/* slots: */ {
$type_slots:tt
/* as_number */ [ $( $nb_slot_name:ident : $nb_slot_value:expr, )* ]
$as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
} => { py_class_impl! {
{ $($tail)* }
$class $py $info
/* slots: */ {
$type_slots
/* as_number */ [
$( $nb_slot_name : $nb_slot_value, )*
nb_inplace_true_divide: py_class_binary_slot!($class::__itruediv__, $other_type, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
]
$as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
py_class_impl_item! { $class, $py, __itruediv__(&$slf,) $res_type; { $($body)* } [{ $other : $other_type = {} }] }
}
$members
}};
{ { def __itruediv__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__itruediv__ is not supported by py_class! yet." }
py_error! { "Invalid signature for operator __itruediv__" }
};
{ { def __ixor__(&$slf:ident, $other:ident : $other_type:ty) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
$class:ident $py:ident $info:tt
/* slots: */ {
$type_slots:tt
/* as_number */ [ $( $nb_slot_name:ident : $nb_slot_value:expr, )* ]
$as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
} => { py_class_impl! {
{ $($tail)* }
$class $py $info
/* slots: */ {
$type_slots
/* as_number */ [
$( $nb_slot_name : $nb_slot_value, )*
nb_inplace_xor: py_class_binary_slot!($class::__ixor__, $other_type, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
]
$as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
py_class_impl_item! { $class, $py, __ixor__(&$slf,) $res_type; { $($body)* } [{ $other : $other_type = {} }] }
}
$members
}};
{ { def __ixor__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__ixor__ is not supported by py_class! yet." }
py_error! { "Invalid signature for operator __ixor__" }
};
{ { def __le__ $($tail:tt)* } $( $stuff:tt )* } => {

View File

@ -749,6 +749,84 @@ fn rich_comparisons_python_3_type_error() {
py_expect_exception!(py, c2, "1 >= c2", TypeError);
}
py_class!(class InPlaceOperations |py| {
data value: Cell<u32>;
def __repr__(&self) -> PyResult<String> {
Ok(format!("IPO({:?})", self.value(py).get()))
}
def __iadd__(&self, other: u32) -> PyResult<Self> {
self.value(py).set(self.value(py).get() + other);
Ok(self.clone_ref(py))
}
def __isub__(&self, other: u32) -> PyResult<Self> {
self.value(py).set(self.value(py).get() - other);
Ok(self.clone_ref(py))
}
def __imul__(&self, other: u32) -> PyResult<Self> {
self.value(py).set(self.value(py).get() * other);
Ok(self.clone_ref(py))
}
def __ilshift__(&self, other: u32) -> PyResult<Self> {
self.value(py).set(self.value(py).get() << other);
Ok(self.clone_ref(py))
}
def __irshift__(&self, other: u32) -> PyResult<Self> {
self.value(py).set(self.value(py).get() >> other);
Ok(self.clone_ref(py))
}
def __iand__(&self, other: u32) -> PyResult<Self> {
self.value(py).set(self.value(py).get() & other);
Ok(self.clone_ref(py))
}
def __ixor__(&self, other: u32) -> PyResult<Self> {
self.value(py).set(self.value(py).get() ^ other);
Ok(self.clone_ref(py))
}
def __ior__(&self, other: u32) -> PyResult<Self> {
self.value(py).set(self.value(py).get() | other);
Ok(self.clone_ref(py))
}
});
#[test]
fn inplace_operations() {
let gil = Python::acquire_gil();
let py = gil.python();
let c = InPlaceOperations::create_instance(py, Cell::new(0)).unwrap();
py_run!(py, c, "d = c; c += 1; assert repr(c) == repr(d) == 'IPO(1)'");
let c = InPlaceOperations::create_instance(py, Cell::new(10)).unwrap();
py_run!(py, c, "d = c; c -= 1; assert repr(c) == repr(d) == 'IPO(9)'");
let c = InPlaceOperations::create_instance(py, Cell::new(3)).unwrap();
py_run!(py, c, "d = c; c *= 3; assert repr(c) == repr(d) == 'IPO(9)'");
let c = InPlaceOperations::create_instance(py, Cell::new(3)).unwrap();
py_run!(py, c, "d = c; c <<= 2; assert repr(c) == repr(d) == 'IPO(12)'");
let c = InPlaceOperations::create_instance(py, Cell::new(12)).unwrap();
py_run!(py, c, "d = c; c >>= 2; assert repr(c) == repr(d) == 'IPO(3)'");
let c = InPlaceOperations::create_instance(py, Cell::new(12)).unwrap();
py_run!(py, c, "d = c; c &= 10; assert repr(c) == repr(d) == 'IPO(8)'");
let c = InPlaceOperations::create_instance(py, Cell::new(12)).unwrap();
py_run!(py, c, "d = c; c |= 3; assert repr(c) == repr(d) == 'IPO(15)'");
let c = InPlaceOperations::create_instance(py, Cell::new(12)).unwrap();
py_run!(py, c, "d = c; c ^= 5; assert repr(c) == repr(d) == 'IPO(9)'");
}
py_class!(class ContextManager |py| {
data exit_called : Cell<bool>;