py_class!: add __contains__ and __reversed__
This commit is contained in:
parent
5886720c90
commit
9eafaebfa2
|
@ -310,6 +310,17 @@ TODO: implement support for `__cmp__`, `__lt__`, `__le__`, `__gt__`, `__ge__`, `
|
|||
|
||||
Called by Python `del self[key]`.
|
||||
|
||||
* `def __reversed__(&self) -> PyResult<impl ToPyObject>`
|
||||
|
||||
Called by the `reversed()` built-in.
|
||||
It should return a new iterator object that iterates over all the objects in the container in reverse order.
|
||||
|
||||
* `def __contains__(&self, item: impl ExtractPyObject) -> PyResult<bool>`
|
||||
|
||||
Called by Python `item in self`.
|
||||
For mapping types, this should consider the keys of the mapping rather than the values
|
||||
or the key-item pairs.
|
||||
|
||||
## Other Special Methods
|
||||
|
||||
* `def __bool__(&self) -> PyResult<bool>`
|
||||
|
|
|
@ -519,6 +519,9 @@ def operator(special_name, slot,
|
|||
if res_type == '()':
|
||||
res_conv = '$crate::py_class::slots::UnitCallbackConverter'
|
||||
res_ffi_type = '$crate::_detail::libc::c_int'
|
||||
elif res_type == 'bool':
|
||||
res_conv = '$crate::py_class::slots::BoolConverter'
|
||||
res_ffi_type = '$crate::_detail::libc::c_int'
|
||||
elif res_type == 'PyObject':
|
||||
res_conv = '$crate::_detail::PyObjectCallbackConverter'
|
||||
else:
|
||||
|
@ -582,8 +585,7 @@ special_names = {
|
|||
res_ffi_type='$crate::Py_hash_t'),
|
||||
'__nonzero__': error('__nonzero__ is not supported by py_class!; use the Python 3 spelling __bool__ instead.'),
|
||||
'__bool__': operator('nb_nonzero' if PY2 else 'nb_bool',
|
||||
res_conv='$crate::py_class::slots::BoolConverter',
|
||||
res_ffi_type='$crate::_detail::libc::c_int'),
|
||||
res_type='bool'),
|
||||
# Customizing attribute access
|
||||
'__getattr__': unimplemented(),
|
||||
'__getattribute__': unimplemented(),
|
||||
|
@ -627,8 +629,10 @@ special_names = {
|
|||
'__iter__': operator('tp_iter'),
|
||||
'__next__': operator('tp_iternext',
|
||||
res_conv='$crate::py_class::slots::IterNextResultConverter'),
|
||||
'__reversed__': unimplemented(),
|
||||
'__contains__': unimplemented(),
|
||||
'__reversed__': normal_method(),
|
||||
'__contains__': operator('sq_contains',
|
||||
args=[Argument('item', '&PyObject')],
|
||||
res_type='bool'),
|
||||
|
||||
# Emulating numeric types
|
||||
'__add__': unimplemented(),
|
||||
|
|
|
@ -414,9 +414,35 @@ macro_rules! py_class_impl {
|
|||
{ { def __complex__ $($tail:tt)* } $( $stuff:tt )* } => {
|
||||
py_error! { "__complex__ is not supported by py_class! yet." }
|
||||
};
|
||||
{ { def __contains__(&$slf:ident, $item:ident : $item_type:ty) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
|
||||
$class:ident $py:ident $info:tt
|
||||
/* slots: */ {
|
||||
$type_slots:tt $as_number:tt
|
||||
/* as_sequence */ [ $( $sq_slot_name:ident : $sq_slot_value:expr, )* ]
|
||||
$as_mapping:tt $setdelitem:tt
|
||||
}
|
||||
{ $( $imp:item )* }
|
||||
$members:tt
|
||||
} => { py_class_impl! {
|
||||
{ $($tail)* }
|
||||
$class $py $info
|
||||
/* slots: */ {
|
||||
$type_slots $as_number
|
||||
/* as_sequence */ [
|
||||
$( $sq_slot_name : $sq_slot_value, )*
|
||||
sq_contains: py_class_binary_slot!($class::__contains__, $item_type, $crate::_detail::libc::c_int, $crate::py_class::slots::BoolConverter),
|
||||
]
|
||||
$as_mapping $setdelitem
|
||||
}
|
||||
/* impl: */ {
|
||||
$($imp)*
|
||||
py_class_impl_item! { $class, $py, __contains__(&$slf,) $res_type; { $($body)* } [{ $item : $item_type = {} }] }
|
||||
}
|
||||
$members
|
||||
}};
|
||||
|
||||
{ { def __contains__ $($tail:tt)* } $( $stuff:tt )* } => {
|
||||
py_error! { "__contains__ is not supported by py_class! yet." }
|
||||
py_error! { "Invalid signature for operator __contains__" }
|
||||
};
|
||||
|
||||
{ { def __del__ $($tail:tt)* } $( $stuff:tt )* } => {
|
||||
|
@ -895,10 +921,6 @@ macro_rules! py_class_impl {
|
|||
py_error! { "Invalid signature for operator __repr__" }
|
||||
};
|
||||
|
||||
{ { def __reversed__ $($tail:tt)* } $( $stuff:tt )* } => {
|
||||
py_error! { "__reversed__ is not supported by py_class! yet." }
|
||||
};
|
||||
|
||||
{ { def __rfloordiv__ $($tail:tt)* } $( $stuff:tt )* } => {
|
||||
py_error! { "__rfloordiv__ is not supported by py_class! yet." }
|
||||
};
|
||||
|
|
|
@ -414,9 +414,35 @@ macro_rules! py_class_impl {
|
|||
{ { def __complex__ $($tail:tt)* } $( $stuff:tt )* } => {
|
||||
py_error! { "__complex__ is not supported by py_class! yet." }
|
||||
};
|
||||
{ { def __contains__(&$slf:ident, $item:ident : $item_type:ty) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
|
||||
$class:ident $py:ident $info:tt
|
||||
/* slots: */ {
|
||||
$type_slots:tt $as_number:tt
|
||||
/* as_sequence */ [ $( $sq_slot_name:ident : $sq_slot_value:expr, )* ]
|
||||
$as_mapping:tt $setdelitem:tt
|
||||
}
|
||||
{ $( $imp:item )* }
|
||||
$members:tt
|
||||
} => { py_class_impl! {
|
||||
{ $($tail)* }
|
||||
$class $py $info
|
||||
/* slots: */ {
|
||||
$type_slots $as_number
|
||||
/* as_sequence */ [
|
||||
$( $sq_slot_name : $sq_slot_value, )*
|
||||
sq_contains: py_class_binary_slot!($class::__contains__, $item_type, $crate::_detail::libc::c_int, $crate::py_class::slots::BoolConverter),
|
||||
]
|
||||
$as_mapping $setdelitem
|
||||
}
|
||||
/* impl: */ {
|
||||
$($imp)*
|
||||
py_class_impl_item! { $class, $py, __contains__(&$slf,) $res_type; { $($body)* } [{ $item : $item_type = {} }] }
|
||||
}
|
||||
$members
|
||||
}};
|
||||
|
||||
{ { def __contains__ $($tail:tt)* } $( $stuff:tt )* } => {
|
||||
py_error! { "__contains__ is not supported by py_class! yet." }
|
||||
py_error! { "Invalid signature for operator __contains__" }
|
||||
};
|
||||
|
||||
{ { def __del__ $($tail:tt)* } $( $stuff:tt )* } => {
|
||||
|
@ -895,10 +921,6 @@ macro_rules! py_class_impl {
|
|||
py_error! { "Invalid signature for operator __repr__" }
|
||||
};
|
||||
|
||||
{ { def __reversed__ $($tail:tt)* } $( $stuff:tt )* } => {
|
||||
py_error! { "__reversed__ is not supported by py_class! yet." }
|
||||
};
|
||||
|
||||
{ { def __rfloordiv__ $($tail:tt)* } $( $stuff:tt )* } => {
|
||||
py_error! { "__rfloordiv__ is not supported by py_class! yet." }
|
||||
};
|
||||
|
|
|
@ -540,3 +540,34 @@ fn setdelitem() {
|
|||
assert_eq!(c.val(py).get(), None);
|
||||
}
|
||||
|
||||
py_class!(class Reversed |py| {
|
||||
def __reversed__(&self) -> PyResult<&'static str> {
|
||||
Ok("I am reversed")
|
||||
}
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn reversed() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
||||
let c = Reversed::create_instance(py).unwrap();
|
||||
py_run!(py, c, "assert reversed(c) == 'I am reversed'");
|
||||
}
|
||||
|
||||
py_class!(class Contains |py| {
|
||||
def __contains__(&self, item: i32) -> PyResult<bool> {
|
||||
Ok(item >= 0)
|
||||
}
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn contains() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
||||
let c = Contains::create_instance(py).unwrap();
|
||||
py_run!(py, c, "assert 1 in c");
|
||||
py_run!(py, c, "assert -1 not in c");
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue