py_class!: add __setitem__ and __delitem__

This commit is contained in:
Daniel Grunwald 2016-05-07 23:01:45 +02:00
parent 806f212dc4
commit 5886720c90
6 changed files with 457 additions and 102 deletions

View File

@ -302,6 +302,14 @@ TODO: implement support for `__cmp__`, `__lt__`, `__le__`, `__gt__`, `__ge__`, `
Called by the Python subscript operator `self[key]`.
* `def __setitem__(&self, key: impl ExtractPyObject, value: impl ExtractPyObject) -> PyResult<()>`
Called by Python `self[key] = value`.
* `def __delitem__(&self, key: impl ExtractPyObject) -> PyResult<()>`
Called by Python `del self[key]`.
## Other Special Methods
* `def __bool__(&self) -> PyResult<bool>`
@ -339,6 +347,10 @@ macro_rules! py_class {
/* as_number */ [ /* slot: expr, */ ]
/* as_sequence */ [ /* slot: expr, */ ]
/* as_mapping */ [ /* slot: expr, */ ]
/* setitem_delitem */ [
sdi_setitem: {},
sdi_delitem: {},
]
}
/* impls: */ { /* impl body */ }
/* members: */ { /* ident = expr; */ }

View File

@ -226,10 +226,11 @@ def write(text):
last_char = line[-1]
slot_groups = (
('tp', 'type_slots'),
('nb', 'as_number'),
('sq', 'as_sequence'),
('mp', 'as_mapping'),
('tp', 'type_slots', None),
('nb', 'as_number', None),
('sq', 'as_sequence', None),
('mp', 'as_mapping', None),
('sdi', 'setdelitem', ['sdi_setitem', 'sdi_delitem'])
)
def generate_case(pattern, old_info=None, new_info=None, new_impl=None, new_slots=None, new_members=None):
@ -248,10 +249,19 @@ def generate_case(pattern, old_info=None, new_info=None, new_impl=None, new_slot
write('$info:tt')
if new_slots:
write('\n/* slots: */ {\n')
for prefix, group_name in slot_groups:
for prefix, group_name, explicit_slots in slot_groups:
if any(s.startswith(prefix) for s, v in new_slots):
write('\n/* %s */ [ $( $%s_slot_name:ident : $%s_slot_value:expr, )* ]\n'
% (group_name, prefix, prefix))
if explicit_slots is None:
write('\n/* %s */ [ $( $%s_slot_name:ident : $%s_slot_value:expr, )* ]\n'
% (group_name, prefix, prefix))
else:
write('\n/* %s */ [\n' % group_name)
for slot in explicit_slots:
if any(s == slot for s, v in new_slots):
write('%s: {},\n' % slot)
else:
write('%s: $%s_slot_value:tt,\n' % (slot, slot))
write(']\n')
else:
write('$%s:tt' % group_name)
write('\n}\n')
@ -271,13 +281,21 @@ def generate_case(pattern, old_info=None, new_info=None, new_impl=None, new_slot
write(new_info or '$info')
if new_slots:
write('\n/* slots: */ {\n')
for prefix, group_name in slot_groups:
for prefix, group_name, explicit_slots in slot_groups:
if any(s.startswith(prefix) for s, v in new_slots):
write('\n/* %s */ [\n' % group_name)
write('$( $%s_slot_name : $%s_slot_value, )*\n' % (prefix, prefix))
for s, v in new_slots:
if s.startswith(prefix):
write('%s: %s,\n' % (s, v))
if explicit_slots is None:
write('$( $%s_slot_name : $%s_slot_value, )*\n' % (prefix, prefix))
for s, v in new_slots:
if s.startswith(prefix):
write('%s: %s,\n' % (s, v))
else:
for slot in explicit_slots:
slot_value = next((v for s, v in new_slots if s == slot), None)
if slot_value is None:
write('%s: $%s_slot_value,\n' % (slot, slot))
else:
write('%s: { %s },\n' % (slot, slot_value))
write(']\n')
else:
write('$%s' % group_name)
@ -498,7 +516,10 @@ def operator(special_name, slot,
additional_slots=()
):
if res_conv is None:
if res_type == 'PyObject':
if res_type == '()':
res_conv = '$crate::py_class::slots::UnitCallbackConverter'
res_ffi_type = '$crate::_detail::libc::c_int'
elif res_type == 'PyObject':
res_conv = '$crate::_detail::PyObjectCallbackConverter'
else:
res_conv = '$crate::_detail::PythonObjectCallbackConverter::<$crate::%s>(::std::marker::PhantomData)' % res_type
@ -512,7 +533,10 @@ def operator(special_name, slot,
% (special_name, res_ffi_type, res_conv))]
elif len(args) == 1:
new_slots = [(slot, 'py_class_binary_slot!($class::%s, $%s_type, %s, %s)'
% (special_name, arg.name, res_ffi_type, res_conv))]
% (special_name, args[0].name, res_ffi_type, res_conv))]
elif len(args) == 2:
new_slots = [(slot, 'py_class_ternary_slot!($class::%s, $%s_type, $%s_type, %s, %s)'
% (special_name, args[0].name, args[1].name, res_ffi_type, res_conv))]
else:
raise ValueError('Unsupported argument count')
generate_case(
@ -523,7 +547,7 @@ def operator(special_name, slot,
)
# Generate fall-back matcher that produces an error
# when using the wrong method signature
error('Invalid signature for unary operator %s' % special_name)(special_name)
error('Invalid signature for operator %s' % special_name)(special_name)
@special_method
def call_operator(special_name, slot):
@ -588,13 +612,18 @@ special_names = {
('mp_length', 'Some($crate::_detail::ffi::PySequence_Size)')
]),
'__length_hint__': normal_method(),
'__getitem__': operator('mp_subscript', args=[Argument('x', '&PyObject')],
'__getitem__': operator('mp_subscript',
args=[Argument('key', '&PyObject')],
additional_slots=[
('sq_item', 'Some($crate::py_class::slots::sq_item)')
]),
'__missing__': normal_method(),
'__setitem__': unimplemented(),
'__delitem__': unimplemented(),
'__setitem__': operator('sdi_setitem',
args=[Argument('key', '&PyObject'), Argument('value', '&PyObject')],
res_type='()'),
'__delitem__': operator('sdi_delitem',
args=[Argument('key', '&PyObject')],
res_type='()'),
'__iter__': operator('tp_iter'),
'__next__': operator('tp_iternext',
res_conv='$crate::py_class::slots::IterNextResultConverter'),
@ -677,6 +706,12 @@ special_names = {
}
def main():
if sys.argv[1:] == ['--format']:
while True:
line = sys.stdin.readline()
if len(line) == 0:
return
write(line)
print(header)
print('')
print('// !!!!!!!!!!!!!!!!!!!!!!!!!!!')

View File

@ -269,7 +269,7 @@ macro_rules! py_class_impl {
$class:ident $py:ident $info:tt
/* slots: */ {
/* type_slots */ [ $( $tp_slot_name:ident : $tp_slot_value:expr, )* ]
$as_number:tt $as_sequence:tt $as_mapping:tt
$as_number:tt $as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
@ -281,7 +281,7 @@ macro_rules! py_class_impl {
$( $tp_slot_name : $tp_slot_value, )*
tp_clear: py_class_tp_clear!($class),
]
$as_number $as_sequence $as_mapping
$as_number $as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
@ -326,7 +326,7 @@ macro_rules! py_class_impl {
/* slots: */ {
$type_slots:tt
/* as_number */ [ $( $nb_slot_name:ident : $nb_slot_value:expr, )* ]
$as_sequence:tt $as_mapping:tt
$as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
@ -339,7 +339,7 @@ macro_rules! py_class_impl {
$( $nb_slot_name : $nb_slot_value, )*
nb_nonzero: py_class_unary_slot!($class::__bool__, $crate::_detail::libc::c_int, $crate::py_class::slots::BoolConverter),
]
$as_sequence $as_mapping
$as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
@ -349,13 +349,13 @@ macro_rules! py_class_impl {
}};
{ { def __bool__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "Invalid signature for unary operator __bool__" }
py_error! { "Invalid signature for operator __bool__" }
};
{ { def __call__ (&$slf:ident) -> $res_type:ty { $( $body:tt )* } $($tail:tt)* }
$class:ident $py:ident $info:tt
/* slots: */ {
/* type_slots */ [ $( $tp_slot_name:ident : $tp_slot_value:expr, )* ]
$as_number:tt $as_sequence:tt $as_mapping:tt
$as_number:tt $as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
@ -367,7 +367,7 @@ macro_rules! py_class_impl {
$( $tp_slot_name : $tp_slot_value, )*
tp_call: py_class_call_slot!{$class::__call__ []},
]
$as_number $as_sequence $as_mapping
$as_number $as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
@ -379,7 +379,7 @@ macro_rules! py_class_impl {
$class:ident $py:ident $info:tt
/* slots: */ {
/* type_slots */ [ $( $tp_slot_name:ident : $tp_slot_value:expr, )* ]
$as_number:tt $as_sequence:tt $as_mapping:tt
$as_number:tt $as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
@ -391,7 +391,7 @@ macro_rules! py_class_impl {
$( $tp_slot_name : $tp_slot_value, )*
tp_call: py_argparse_parse_plist_impl!{py_class_call_slot {$class::__call__} [] ($($p)+,)},
]
$as_number $as_sequence $as_mapping
$as_number $as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
@ -430,9 +430,36 @@ macro_rules! py_class_impl {
{ { def __delete__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__delete__ is not supported by py_class! yet." }
};
{ { def __delitem__(&$slf:ident, $key:ident : $key_type:ty) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
$class:ident $py:ident $info:tt
/* slots: */ {
$type_slots:tt $as_number:tt $as_sequence:tt $as_mapping:tt
/* setdelitem */ [
sdi_setitem: $sdi_setitem_slot_value:tt,
sdi_delitem: {},
]
}
{ $( $imp:item )* }
$members:tt
} => { py_class_impl! {
{ $($tail)* }
$class $py $info
/* slots: */ {
$type_slots $as_number $as_sequence $as_mapping
/* setdelitem */ [
sdi_setitem: $sdi_setitem_slot_value,
sdi_delitem: { py_class_binary_slot!($class::__delitem__, $key_type, $crate::_detail::libc::c_int, $crate::py_class::slots::UnitCallbackConverter) },
]
}
/* impl: */ {
$($imp)*
py_class_impl_item! { $class, $py, __delitem__(&$slf,) $res_type; { $($body)* } [{ $key : $key_type = {} }] }
}
$members
}};
{ { def __delitem__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__delitem__ is not supported by py_class! yet." }
py_error! { "Invalid signature for operator __delitem__" }
};
{ { def __dir__ $($tail:tt)* } $( $stuff:tt )* } => {
@ -482,12 +509,13 @@ macro_rules! py_class_impl {
{ { def __getattribute__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__getattribute__ is not supported by py_class! yet." }
};
{ { def __getitem__(&$slf:ident, $x:ident : $x_type:ty) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
{ { def __getitem__(&$slf:ident, $key:ident : $key_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 */ [ $( $mp_slot_name:ident : $mp_slot_value:expr, )* ]
$setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
@ -502,18 +530,19 @@ macro_rules! py_class_impl {
]
/* as_mapping */ [
$( $mp_slot_name : $mp_slot_value, )*
mp_subscript: py_class_binary_slot!($class::__getitem__, $x_type, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
mp_subscript: py_class_binary_slot!($class::__getitem__, $key_type, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
]
$setdelitem
}
/* impl: */ {
$($imp)*
py_class_impl_item! { $class, $py, __getitem__(&$slf,) $res_type; { $($body)* } [{ $x : $x_type = {} }] }
py_class_impl_item! { $class, $py, __getitem__(&$slf,) $res_type; { $($body)* } [{ $key : $key_type = {} }] }
}
$members
}};
{ { def __getitem__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "Invalid signature for unary operator __getitem__" }
py_error! { "Invalid signature for operator __getitem__" }
};
{ { def __gt__ $($tail:tt)* } $( $stuff:tt )* } => {
@ -523,7 +552,7 @@ macro_rules! py_class_impl {
$class:ident $py:ident $info:tt
/* slots: */ {
/* type_slots */ [ $( $tp_slot_name:ident : $tp_slot_value:expr, )* ]
$as_number:tt $as_sequence:tt $as_mapping:tt
$as_number:tt $as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
@ -535,7 +564,7 @@ macro_rules! py_class_impl {
$( $tp_slot_name : $tp_slot_value, )*
tp_hash: py_class_unary_slot!($class::__hash__, $crate::Py_hash_t, $crate::py_class::slots::HashConverter),
]
$as_number $as_sequence $as_mapping
$as_number $as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
@ -545,7 +574,7 @@ macro_rules! py_class_impl {
}};
{ { def __hash__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "Invalid signature for unary operator __hash__" }
py_error! { "Invalid signature for operator __hash__" }
};
{ { def __iadd__ $($tail:tt)* } $( $stuff:tt )* } => {
@ -623,7 +652,7 @@ macro_rules! py_class_impl {
$class:ident $py:ident $info:tt
/* slots: */ {
/* type_slots */ [ $( $tp_slot_name:ident : $tp_slot_value:expr, )* ]
$as_number:tt $as_sequence:tt $as_mapping:tt
$as_number:tt $as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
@ -635,7 +664,7 @@ macro_rules! py_class_impl {
$( $tp_slot_name : $tp_slot_value, )*
tp_iter: py_class_unary_slot!($class::__iter__, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
]
$as_number $as_sequence $as_mapping
$as_number $as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
@ -645,7 +674,7 @@ macro_rules! py_class_impl {
}};
{ { def __iter__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "Invalid signature for unary operator __iter__" }
py_error! { "Invalid signature for operator __iter__" }
};
{ { def __itruediv__ $($tail:tt)* } $( $stuff:tt )* } => {
@ -665,6 +694,7 @@ macro_rules! py_class_impl {
$type_slots:tt $as_number:tt
/* as_sequence */ [ $( $sq_slot_name:ident : $sq_slot_value:expr, )* ]
/* as_mapping */ [ $( $mp_slot_name:ident : $mp_slot_value:expr, )* ]
$setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
@ -681,6 +711,7 @@ macro_rules! py_class_impl {
$( $mp_slot_name : $mp_slot_value, )*
mp_length: Some($crate::_detail::ffi::PySequence_Size),
]
$setdelitem
}
/* impl: */ {
$($imp)*
@ -690,7 +721,7 @@ macro_rules! py_class_impl {
}};
{ { def __len__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "Invalid signature for unary operator __len__" }
py_error! { "Invalid signature for operator __len__" }
};
{ { def __long__ $($tail:tt)* } $( $stuff:tt )* } => {
@ -728,7 +759,7 @@ macro_rules! py_class_impl {
$class:ident $py:ident $info:tt
/* slots: */ {
/* type_slots */ [ $( $tp_slot_name:ident : $tp_slot_value:expr, )* ]
$as_number:tt $as_sequence:tt $as_mapping:tt
$as_number:tt $as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
@ -740,7 +771,7 @@ macro_rules! py_class_impl {
$( $tp_slot_name : $tp_slot_value, )*
tp_new: py_class_wrap_newfunc!{$class::__new__ []},
]
$as_number $as_sequence $as_mapping
$as_number $as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
@ -752,7 +783,7 @@ macro_rules! py_class_impl {
$class:ident $py:ident $info:tt
/* slots: */ {
/* type_slots */ [ $( $tp_slot_name:ident : $tp_slot_value:expr, )* ]
$as_number:tt $as_sequence:tt $as_mapping:tt
$as_number:tt $as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
@ -764,7 +795,7 @@ macro_rules! py_class_impl {
$( $tp_slot_name : $tp_slot_value, )*
tp_new: py_argparse_parse_plist_impl!{py_class_wrap_newfunc {$class::__new__} [] ($($p)+,)},
]
$as_number $as_sequence $as_mapping
$as_number $as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
@ -779,7 +810,7 @@ macro_rules! py_class_impl {
$class:ident $py:ident $info:tt
/* slots: */ {
/* type_slots */ [ $( $tp_slot_name:ident : $tp_slot_value:expr, )* ]
$as_number:tt $as_sequence:tt $as_mapping:tt
$as_number:tt $as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
@ -791,7 +822,7 @@ macro_rules! py_class_impl {
$( $tp_slot_name : $tp_slot_value, )*
tp_iternext: py_class_unary_slot!($class::__next__, *mut $crate::_detail::ffi::PyObject, $crate::py_class::slots::IterNextResultConverter),
]
$as_number $as_sequence $as_mapping
$as_number $as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
@ -801,7 +832,7 @@ macro_rules! py_class_impl {
}};
{ { def __next__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "Invalid signature for unary operator __next__" }
py_error! { "Invalid signature for operator __next__" }
};
{ { def __nonzero__ $($tail:tt)* } $( $stuff:tt )* } => {
@ -839,7 +870,7 @@ macro_rules! py_class_impl {
$class:ident $py:ident $info:tt
/* slots: */ {
/* type_slots */ [ $( $tp_slot_name:ident : $tp_slot_value:expr, )* ]
$as_number:tt $as_sequence:tt $as_mapping:tt
$as_number:tt $as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
@ -851,7 +882,7 @@ macro_rules! py_class_impl {
$( $tp_slot_name : $tp_slot_value, )*
tp_repr: py_class_unary_slot!($class::__repr__, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PythonObjectCallbackConverter::<$crate::PyString>(::std::marker::PhantomData)),
]
$as_number $as_sequence $as_mapping
$as_number $as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
@ -861,7 +892,7 @@ macro_rules! py_class_impl {
}};
{ { def __repr__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "Invalid signature for unary operator __repr__" }
py_error! { "Invalid signature for operator __repr__" }
};
{ { def __reversed__ $($tail:tt)* } $( $stuff:tt )* } => {
@ -927,15 +958,42 @@ macro_rules! py_class_impl {
{ { def __setattr__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__setattr__ is not supported by py_class! yet." }
};
{ { def __setitem__(&$slf:ident, $key:ident : $key_type:ty, $value:ident : $value_type:ty) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
$class:ident $py:ident $info:tt
/* slots: */ {
$type_slots:tt $as_number:tt $as_sequence:tt $as_mapping:tt
/* setdelitem */ [
sdi_setitem: {},
sdi_delitem: $sdi_delitem_slot_value:tt,
]
}
{ $( $imp:item )* }
$members:tt
} => { py_class_impl! {
{ $($tail)* }
$class $py $info
/* slots: */ {
$type_slots $as_number $as_sequence $as_mapping
/* setdelitem */ [
sdi_setitem: { py_class_ternary_slot!($class::__setitem__, $key_type, $value_type, $crate::_detail::libc::c_int, $crate::py_class::slots::UnitCallbackConverter) },
sdi_delitem: $sdi_delitem_slot_value,
]
}
/* impl: */ {
$($imp)*
py_class_impl_item! { $class, $py, __setitem__(&$slf,) $res_type; { $($body)* } [{ $key : $key_type = {} } { $value : $value_type = {} }] }
}
$members
}};
{ { def __setitem__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__setitem__ is not supported by py_class! yet." }
py_error! { "Invalid signature for operator __setitem__" }
};
{ { def __str__(&$slf:ident) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
$class:ident $py:ident $info:tt
/* slots: */ {
/* type_slots */ [ $( $tp_slot_name:ident : $tp_slot_value:expr, )* ]
$as_number:tt $as_sequence:tt $as_mapping:tt
$as_number:tt $as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
@ -947,7 +1005,7 @@ macro_rules! py_class_impl {
$( $tp_slot_name : $tp_slot_value, )*
tp_str: py_class_unary_slot!($class::__str__, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PythonObjectCallbackConverter::<$crate::PyString>(::std::marker::PhantomData)),
]
$as_number $as_sequence $as_mapping
$as_number $as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
@ -957,7 +1015,7 @@ macro_rules! py_class_impl {
}};
{ { def __str__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "Invalid signature for unary operator __str__" }
py_error! { "Invalid signature for operator __str__" }
};
{ { def __sub__ $($tail:tt)* } $( $stuff:tt )* } => {

View File

@ -269,7 +269,7 @@ macro_rules! py_class_impl {
$class:ident $py:ident $info:tt
/* slots: */ {
/* type_slots */ [ $( $tp_slot_name:ident : $tp_slot_value:expr, )* ]
$as_number:tt $as_sequence:tt $as_mapping:tt
$as_number:tt $as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
@ -281,7 +281,7 @@ macro_rules! py_class_impl {
$( $tp_slot_name : $tp_slot_value, )*
tp_clear: py_class_tp_clear!($class),
]
$as_number $as_sequence $as_mapping
$as_number $as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
@ -326,7 +326,7 @@ macro_rules! py_class_impl {
/* slots: */ {
$type_slots:tt
/* as_number */ [ $( $nb_slot_name:ident : $nb_slot_value:expr, )* ]
$as_sequence:tt $as_mapping:tt
$as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
@ -339,7 +339,7 @@ macro_rules! py_class_impl {
$( $nb_slot_name : $nb_slot_value, )*
nb_bool: py_class_unary_slot!($class::__bool__, $crate::_detail::libc::c_int, $crate::py_class::slots::BoolConverter),
]
$as_sequence $as_mapping
$as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
@ -349,13 +349,13 @@ macro_rules! py_class_impl {
}};
{ { def __bool__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "Invalid signature for unary operator __bool__" }
py_error! { "Invalid signature for operator __bool__" }
};
{ { def __call__ (&$slf:ident) -> $res_type:ty { $( $body:tt )* } $($tail:tt)* }
$class:ident $py:ident $info:tt
/* slots: */ {
/* type_slots */ [ $( $tp_slot_name:ident : $tp_slot_value:expr, )* ]
$as_number:tt $as_sequence:tt $as_mapping:tt
$as_number:tt $as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
@ -367,7 +367,7 @@ macro_rules! py_class_impl {
$( $tp_slot_name : $tp_slot_value, )*
tp_call: py_class_call_slot!{$class::__call__ []},
]
$as_number $as_sequence $as_mapping
$as_number $as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
@ -379,7 +379,7 @@ macro_rules! py_class_impl {
$class:ident $py:ident $info:tt
/* slots: */ {
/* type_slots */ [ $( $tp_slot_name:ident : $tp_slot_value:expr, )* ]
$as_number:tt $as_sequence:tt $as_mapping:tt
$as_number:tt $as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
@ -391,7 +391,7 @@ macro_rules! py_class_impl {
$( $tp_slot_name : $tp_slot_value, )*
tp_call: py_argparse_parse_plist_impl!{py_class_call_slot {$class::__call__} [] ($($p)+,)},
]
$as_number $as_sequence $as_mapping
$as_number $as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
@ -430,9 +430,36 @@ macro_rules! py_class_impl {
{ { def __delete__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__delete__ is not supported by py_class! yet." }
};
{ { def __delitem__(&$slf:ident, $key:ident : $key_type:ty) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
$class:ident $py:ident $info:tt
/* slots: */ {
$type_slots:tt $as_number:tt $as_sequence:tt $as_mapping:tt
/* setdelitem */ [
sdi_setitem: $sdi_setitem_slot_value:tt,
sdi_delitem: {},
]
}
{ $( $imp:item )* }
$members:tt
} => { py_class_impl! {
{ $($tail)* }
$class $py $info
/* slots: */ {
$type_slots $as_number $as_sequence $as_mapping
/* setdelitem */ [
sdi_setitem: $sdi_setitem_slot_value,
sdi_delitem: { py_class_binary_slot!($class::__delitem__, $key_type, $crate::_detail::libc::c_int, $crate::py_class::slots::UnitCallbackConverter) },
]
}
/* impl: */ {
$($imp)*
py_class_impl_item! { $class, $py, __delitem__(&$slf,) $res_type; { $($body)* } [{ $key : $key_type = {} }] }
}
$members
}};
{ { def __delitem__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__delitem__ is not supported by py_class! yet." }
py_error! { "Invalid signature for operator __delitem__" }
};
{ { def __dir__ $($tail:tt)* } $( $stuff:tt )* } => {
@ -482,12 +509,13 @@ macro_rules! py_class_impl {
{ { def __getattribute__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__getattribute__ is not supported by py_class! yet." }
};
{ { def __getitem__(&$slf:ident, $x:ident : $x_type:ty) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
{ { def __getitem__(&$slf:ident, $key:ident : $key_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 */ [ $( $mp_slot_name:ident : $mp_slot_value:expr, )* ]
$setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
@ -502,18 +530,19 @@ macro_rules! py_class_impl {
]
/* as_mapping */ [
$( $mp_slot_name : $mp_slot_value, )*
mp_subscript: py_class_binary_slot!($class::__getitem__, $x_type, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
mp_subscript: py_class_binary_slot!($class::__getitem__, $key_type, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
]
$setdelitem
}
/* impl: */ {
$($imp)*
py_class_impl_item! { $class, $py, __getitem__(&$slf,) $res_type; { $($body)* } [{ $x : $x_type = {} }] }
py_class_impl_item! { $class, $py, __getitem__(&$slf,) $res_type; { $($body)* } [{ $key : $key_type = {} }] }
}
$members
}};
{ { def __getitem__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "Invalid signature for unary operator __getitem__" }
py_error! { "Invalid signature for operator __getitem__" }
};
{ { def __gt__ $($tail:tt)* } $( $stuff:tt )* } => {
@ -523,7 +552,7 @@ macro_rules! py_class_impl {
$class:ident $py:ident $info:tt
/* slots: */ {
/* type_slots */ [ $( $tp_slot_name:ident : $tp_slot_value:expr, )* ]
$as_number:tt $as_sequence:tt $as_mapping:tt
$as_number:tt $as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
@ -535,7 +564,7 @@ macro_rules! py_class_impl {
$( $tp_slot_name : $tp_slot_value, )*
tp_hash: py_class_unary_slot!($class::__hash__, $crate::Py_hash_t, $crate::py_class::slots::HashConverter),
]
$as_number $as_sequence $as_mapping
$as_number $as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
@ -545,7 +574,7 @@ macro_rules! py_class_impl {
}};
{ { def __hash__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "Invalid signature for unary operator __hash__" }
py_error! { "Invalid signature for operator __hash__" }
};
{ { def __iadd__ $($tail:tt)* } $( $stuff:tt )* } => {
@ -623,7 +652,7 @@ macro_rules! py_class_impl {
$class:ident $py:ident $info:tt
/* slots: */ {
/* type_slots */ [ $( $tp_slot_name:ident : $tp_slot_value:expr, )* ]
$as_number:tt $as_sequence:tt $as_mapping:tt
$as_number:tt $as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
@ -635,7 +664,7 @@ macro_rules! py_class_impl {
$( $tp_slot_name : $tp_slot_value, )*
tp_iter: py_class_unary_slot!($class::__iter__, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
]
$as_number $as_sequence $as_mapping
$as_number $as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
@ -645,7 +674,7 @@ macro_rules! py_class_impl {
}};
{ { def __iter__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "Invalid signature for unary operator __iter__" }
py_error! { "Invalid signature for operator __iter__" }
};
{ { def __itruediv__ $($tail:tt)* } $( $stuff:tt )* } => {
@ -665,6 +694,7 @@ macro_rules! py_class_impl {
$type_slots:tt $as_number:tt
/* as_sequence */ [ $( $sq_slot_name:ident : $sq_slot_value:expr, )* ]
/* as_mapping */ [ $( $mp_slot_name:ident : $mp_slot_value:expr, )* ]
$setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
@ -681,6 +711,7 @@ macro_rules! py_class_impl {
$( $mp_slot_name : $mp_slot_value, )*
mp_length: Some($crate::_detail::ffi::PySequence_Size),
]
$setdelitem
}
/* impl: */ {
$($imp)*
@ -690,7 +721,7 @@ macro_rules! py_class_impl {
}};
{ { def __len__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "Invalid signature for unary operator __len__" }
py_error! { "Invalid signature for operator __len__" }
};
{ { def __long__ $($tail:tt)* } $( $stuff:tt )* } => {
@ -728,7 +759,7 @@ macro_rules! py_class_impl {
$class:ident $py:ident $info:tt
/* slots: */ {
/* type_slots */ [ $( $tp_slot_name:ident : $tp_slot_value:expr, )* ]
$as_number:tt $as_sequence:tt $as_mapping:tt
$as_number:tt $as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
@ -740,7 +771,7 @@ macro_rules! py_class_impl {
$( $tp_slot_name : $tp_slot_value, )*
tp_new: py_class_wrap_newfunc!{$class::__new__ []},
]
$as_number $as_sequence $as_mapping
$as_number $as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
@ -752,7 +783,7 @@ macro_rules! py_class_impl {
$class:ident $py:ident $info:tt
/* slots: */ {
/* type_slots */ [ $( $tp_slot_name:ident : $tp_slot_value:expr, )* ]
$as_number:tt $as_sequence:tt $as_mapping:tt
$as_number:tt $as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
@ -764,7 +795,7 @@ macro_rules! py_class_impl {
$( $tp_slot_name : $tp_slot_value, )*
tp_new: py_argparse_parse_plist_impl!{py_class_wrap_newfunc {$class::__new__} [] ($($p)+,)},
]
$as_number $as_sequence $as_mapping
$as_number $as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
@ -779,7 +810,7 @@ macro_rules! py_class_impl {
$class:ident $py:ident $info:tt
/* slots: */ {
/* type_slots */ [ $( $tp_slot_name:ident : $tp_slot_value:expr, )* ]
$as_number:tt $as_sequence:tt $as_mapping:tt
$as_number:tt $as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
@ -791,7 +822,7 @@ macro_rules! py_class_impl {
$( $tp_slot_name : $tp_slot_value, )*
tp_iternext: py_class_unary_slot!($class::__next__, *mut $crate::_detail::ffi::PyObject, $crate::py_class::slots::IterNextResultConverter),
]
$as_number $as_sequence $as_mapping
$as_number $as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
@ -801,7 +832,7 @@ macro_rules! py_class_impl {
}};
{ { def __next__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "Invalid signature for unary operator __next__" }
py_error! { "Invalid signature for operator __next__" }
};
{ { def __nonzero__ $($tail:tt)* } $( $stuff:tt )* } => {
@ -839,7 +870,7 @@ macro_rules! py_class_impl {
$class:ident $py:ident $info:tt
/* slots: */ {
/* type_slots */ [ $( $tp_slot_name:ident : $tp_slot_value:expr, )* ]
$as_number:tt $as_sequence:tt $as_mapping:tt
$as_number:tt $as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
@ -851,7 +882,7 @@ macro_rules! py_class_impl {
$( $tp_slot_name : $tp_slot_value, )*
tp_repr: py_class_unary_slot!($class::__repr__, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PythonObjectCallbackConverter::<$crate::PyString>(::std::marker::PhantomData)),
]
$as_number $as_sequence $as_mapping
$as_number $as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
@ -861,7 +892,7 @@ macro_rules! py_class_impl {
}};
{ { def __repr__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "Invalid signature for unary operator __repr__" }
py_error! { "Invalid signature for operator __repr__" }
};
{ { def __reversed__ $($tail:tt)* } $( $stuff:tt )* } => {
@ -927,15 +958,42 @@ macro_rules! py_class_impl {
{ { def __setattr__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__setattr__ is not supported by py_class! yet." }
};
{ { def __setitem__(&$slf:ident, $key:ident : $key_type:ty, $value:ident : $value_type:ty) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
$class:ident $py:ident $info:tt
/* slots: */ {
$type_slots:tt $as_number:tt $as_sequence:tt $as_mapping:tt
/* setdelitem */ [
sdi_setitem: {},
sdi_delitem: $sdi_delitem_slot_value:tt,
]
}
{ $( $imp:item )* }
$members:tt
} => { py_class_impl! {
{ $($tail)* }
$class $py $info
/* slots: */ {
$type_slots $as_number $as_sequence $as_mapping
/* setdelitem */ [
sdi_setitem: { py_class_ternary_slot!($class::__setitem__, $key_type, $value_type, $crate::_detail::libc::c_int, $crate::py_class::slots::UnitCallbackConverter) },
sdi_delitem: $sdi_delitem_slot_value,
]
}
/* impl: */ {
$($imp)*
py_class_impl_item! { $class, $py, __setitem__(&$slf,) $res_type; { $($body)* } [{ $key : $key_type = {} } { $value : $value_type = {} }] }
}
$members
}};
{ { def __setitem__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "__setitem__ is not supported by py_class! yet." }
py_error! { "Invalid signature for operator __setitem__" }
};
{ { def __str__(&$slf:ident) -> $res_type:ty { $($body:tt)* } $($tail:tt)* }
$class:ident $py:ident $info:tt
/* slots: */ {
/* type_slots */ [ $( $tp_slot_name:ident : $tp_slot_value:expr, )* ]
$as_number:tt $as_sequence:tt $as_mapping:tt
$as_number:tt $as_sequence:tt $as_mapping:tt $setdelitem:tt
}
{ $( $imp:item )* }
$members:tt
@ -947,7 +1005,7 @@ macro_rules! py_class_impl {
$( $tp_slot_name : $tp_slot_value, )*
tp_str: py_class_unary_slot!($class::__str__, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PythonObjectCallbackConverter::<$crate::PyString>(::std::marker::PhantomData)),
]
$as_number $as_sequence $as_mapping
$as_number $as_sequence $as_mapping $setdelitem
}
/* impl: */ {
$($imp)*
@ -957,7 +1015,7 @@ macro_rules! py_class_impl {
}};
{ { def __str__ $($tail:tt)* } $( $stuff:tt )* } => {
py_error! { "Invalid signature for unary operator __str__" }
py_error! { "Invalid signature for operator __str__" }
};
{ { def __sub__ $($tail:tt)* } $( $stuff:tt )* } => {

View File

@ -18,7 +18,7 @@
use ffi;
use std::{mem, isize, ptr};
use libc::c_int;
use libc::{c_char, c_int};
use python::{Python, PythonObject};
use conversion::ToPyObject;
use function::CallbackConverter;
@ -36,6 +36,7 @@ macro_rules! py_class_type_object_static_init {
$as_number:tt
$as_sequence:tt
$as_mapping:tt
$setdelitem:tt
}) => (
$crate::_detail::ffi::PyTypeObject {
$( $slot_name : $slot_value, )*
@ -76,6 +77,7 @@ macro_rules! py_class_type_object_dynamic_init {
$as_number:tt
$as_sequence:tt
$as_mapping:tt
$setdelitem:tt
}
) => {
unsafe {
@ -86,7 +88,7 @@ macro_rules! py_class_type_object_dynamic_init {
// call slot macros outside of unsafe block
*(unsafe { &mut $type_object.tp_as_sequence }) = py_class_as_sequence!($as_sequence);
*(unsafe { &mut $type_object.tp_as_number }) = py_class_as_number!($as_number);
*(unsafe { &mut $type_object.tp_as_mapping }) = py_class_as_mapping!($as_mapping);
py_class_as_mapping!($type_object, $as_mapping, $setdelitem);
}
}
@ -162,18 +164,69 @@ macro_rules! py_class_as_number {
#[macro_export]
#[doc(hidden)]
macro_rules! py_class_as_mapping {
([]) => (0 as *mut $crate::_detail::ffi::PyMappingMethods);
([$( $slot_name:ident : $slot_value:expr ,)+]) => {{
( $type_object:ident, [], [
sdi_setitem: {},
sdi_delitem: {},
]) => {};
( $type_object:ident, [ $( $slot_name:ident : $slot_value:expr ,)+ ], [
sdi_setitem: {},
sdi_delitem: {},
]) => {
static mut MAPPING_METHODS : $crate::_detail::ffi::PyMappingMethods
= $crate::_detail::ffi::PyMappingMethods {
$( $slot_name : $slot_value, )*
..
$crate::_detail::ffi::PyMappingMethods_INIT
};
unsafe { &mut MAPPING_METHODS }
}}
unsafe { $type_object.tp_as_mapping = &mut MAPPING_METHODS; }
};
( $type_object:ident, [ $( $slot_name:ident : $slot_value:expr ,)* ], [
sdi_setitem: $setitem:tt,
sdi_delitem: $delitem:tt,
]) => {{
unsafe extern "C" fn mp_ass_subscript(
slf: *mut $crate::_detail::ffi::PyObject,
key: *mut $crate::_detail::ffi::PyObject,
val: *mut $crate::_detail::ffi::PyObject
) -> $crate::_detail::libc::c_int {
if val.is_null() {
py_class_mp_ass_subscript!($delitem, slf,
b"Subscript assignment not supported by %.200s\0",
key)
} else {
py_class_mp_ass_subscript!($setitem, slf,
b"Subscript deletion not supported by %.200s\0",
key, val)
}
}
static mut MAPPING_METHODS : $crate::_detail::ffi::PyMappingMethods
= $crate::_detail::ffi::PyMappingMethods {
$( $slot_name : $slot_value, )*
mp_ass_subscript: Some(mp_ass_subscript),
..
$crate::_detail::ffi::PyMappingMethods_INIT
};
unsafe { $type_object.tp_as_mapping = &mut MAPPING_METHODS; }
}};
}
#[macro_export]
#[doc(hidden)]
macro_rules! py_class_mp_ass_subscript {
({}, $slf:ident, $error:expr, $( $arg:expr ),+) => {
$crate::py_class::slots::mp_ass_subscript_error($slf, $error)
};
({$slot:expr}, $slf:ident, $error:expr, $( $arg:expr ),+) => {
$slot.unwrap()($slf, $( $arg ),+)
}
}
pub unsafe fn mp_ass_subscript_error(o: *mut ffi::PyObject, err: &[u8]) -> c_int {
ffi::PyErr_Format(ffi::PyExc_NotImplementedError,
err.as_ptr() as *const c_char,
(*ffi::Py_TYPE(o)).tp_name);
-1
}
#[macro_export]
#[doc(hidden)]
@ -201,7 +254,7 @@ macro_rules! py_class_unary_slot {
#[doc(hidden)]
macro_rules! py_class_binary_slot {
($class:ident :: $f:ident, $arg_type:ty, $res_type:ty, $conv:expr) => {{
unsafe extern "C" fn wrap_unary<DUMMY>(
unsafe extern "C" fn wrap_binary<DUMMY>(
slf: *mut $crate::_detail::ffi::PyObject,
arg: *mut $crate::_detail::ffi::PyObject)
-> $res_type
@ -226,10 +279,72 @@ macro_rules! py_class_binary_slot {
ret
})
}
Some(wrap_unary::<()>)
Some(wrap_binary::<()>)
}}
}
#[macro_export]
#[doc(hidden)]
macro_rules! py_class_ternary_slot {
($class:ident :: $f:ident, $arg1_type:ty, $arg2_type:ty, $res_type:ty, $conv:expr) => {{
unsafe extern "C" fn wrap_binary<DUMMY>(
slf: *mut $crate::_detail::ffi::PyObject,
arg1: *mut $crate::_detail::ffi::PyObject,
arg2: *mut $crate::_detail::ffi::PyObject)
-> $res_type
{
const LOCATION: &'static str = concat!(stringify!($class), ".", stringify!($f), "()");
$crate::_detail::handle_callback(
LOCATION, $conv,
|py| {
let slf = $crate::PyObject::from_borrowed_ptr(py, slf).unchecked_cast_into::<$class>();
let arg1 = $crate::PyObject::from_borrowed_ptr(py, arg1);
let arg2 = $crate::PyObject::from_borrowed_ptr(py, arg2);
let ret = match <$arg1_type as $crate::ExtractPyObject>::prepare_extract(py, &arg1) {
Ok(prepared1) => {
match <$arg1_type as $crate::ExtractPyObject>::extract(py, &prepared1) {
Ok(arg1) => {
match <$arg2_type as $crate::ExtractPyObject>::prepare_extract(py, &arg2) {
Ok(prepared2) => {
match <$arg2_type as $crate::ExtractPyObject>::extract(py, &prepared2) {
Ok(arg2) => slf.$f(py, arg1, arg2),
Err(e) => Err(e)
}
},
Err(e) => Err(e)
}
},
Err(e) => Err(e)
}
},
Err(e) => Err(e)
};
$crate::PyDrop::release_ref(arg1, py);
$crate::PyDrop::release_ref(arg2, py);
$crate::PyDrop::release_ref(slf, py);
ret
})
}
Some(wrap_binary::<()>)
}}
}
pub struct UnitCallbackConverter;
impl CallbackConverter<()> for UnitCallbackConverter {
type R = c_int;
#[inline]
fn convert(_: (), _: Python) -> c_int {
0
}
#[inline]
fn error_value() -> c_int {
-1
}
}
pub struct LenResultConverter;
impl CallbackConverter<usize> for LenResultConverter {
@ -244,6 +359,7 @@ impl CallbackConverter<usize> for LenResultConverter {
}
}
#[inline]
fn error_value() -> isize {
-1
}
@ -267,6 +383,7 @@ impl <T> CallbackConverter<Option<T>>
}
}
#[inline]
fn error_value() -> *mut ffi::PyObject {
ptr::null_mut()
}

View File

@ -5,26 +5,32 @@
use cpython::{PyObject, PythonObject, PyDrop, PyClone, PyResult, Python, NoArgs, ObjectProtocol,
PyDict, PyBytes, PyUnicode, PyErr, exc};
use std::{mem, isize, iter};
use std::cell::RefCell;
use std::cell::{Cell, RefCell};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use cpython::_detail::ffi;
macro_rules! py_assert {
($py:expr, $val:ident, $assertion:expr) => {{
macro_rules! py_run {
($py:expr, $val:ident, $code:expr) => {{
let d = PyDict::new($py);
d.set_item($py, stringify!($val), &$val).unwrap();
$py.run(concat!("assert ", $assertion), None, Some(&d)).expect(concat!("assert ", $assertion));
$py.run($code, None, Some(&d)).expect($code);
}}
}
macro_rules! py_assert {
($py:expr, $val:ident, $assertion:expr) => { py_run!($py, $val, concat!("assert ", $assertion)) };
}
macro_rules! py_expect_exception {
($py:expr, $val:ident, $code:expr, $err:ident) => {{
let d = PyDict::new($py);
d.set_item($py, stringify!($val), $val).unwrap();
let res = $py.eval($code, None, Some(&d));
let res = $py.run($code, None, Some(&d));
let err = res.unwrap_err();
assert!(err.matches($py, $py.get_type::<exc::$err>()));
if !err.matches($py, $py.get_type::<exc::$err>()) {
panic!(format!("Expected {} but got {:?}", stringify!($err), err))
}
}}
}
@ -465,3 +471,72 @@ fn callable() {
py_assert!(py, nc, "not callable(nc)");
}
py_class!(class SetItem |py| {
data key: Cell<i32>;
data val: Cell<i32>;
def __setitem__(&self, key: i32, val: i32) -> PyResult<()> {
self.key(py).set(key);
self.val(py).set(val);
Ok(())
}
});
#[test]
fn setitem() {
let gil = Python::acquire_gil();
let py = gil.python();
let c = SetItem::create_instance(py, Cell::new(0), Cell::new(0)).unwrap();
py_run!(py, c, "c[1] = 2");
assert_eq!(c.key(py).get(), 1);
assert_eq!(c.val(py).get(), 2);
py_expect_exception!(py, c, "del c[1]", NotImplementedError);
}
py_class!(class DelItem |py| {
data key: Cell<i32>;
def __delitem__(&self, key: i32) -> PyResult<()> {
self.key(py).set(key);
Ok(())
}
});
#[test]
fn delitem() {
let gil = Python::acquire_gil();
let py = gil.python();
let c = DelItem::create_instance(py, Cell::new(0)).unwrap();
py_run!(py, c, "del c[1]");
assert_eq!(c.key(py).get(), 1);
py_expect_exception!(py, c, "c[1] = 2", NotImplementedError);
}
py_class!(class SetDelItem |py| {
data val: Cell<Option<i32>>;
def __setitem__(&self, key: i32, val: i32) -> PyResult<()> {
self.val(py).set(Some(val));
Ok(())
}
def __delitem__(&self, key: i32) -> PyResult<()> {
self.val(py).set(None);
Ok(())
}
});
#[test]
fn setdelitem() {
let gil = Python::acquire_gil();
let py = gil.python();
let c = SetDelItem::create_instance(py, Cell::new(None)).unwrap();
py_run!(py, c, "c[1] = 2");
assert_eq!(c.val(py).get(), Some(2));
py_run!(py, c, "del c[1]");
assert_eq!(c.val(py).get(), None);
}