better slot trait definition
This commit is contained in:
parent
c9aefd7e5f
commit
2eea45e9fa
110
pyo3cls/src/func.rs
Normal file
110
pyo3cls/src/func.rs
Normal file
|
@ -0,0 +1,110 @@
|
|||
use syn;
|
||||
use quote::Tokens;
|
||||
|
||||
// TODO:
|
||||
// Add lifetime support for args with Rptr
|
||||
|
||||
pub enum MethodProto {
|
||||
Len{name: &'static str, proto: &'static str},
|
||||
//Unary(&'static str),
|
||||
Binary{name: &'static str, arg: &'static str, proto: &'static str},
|
||||
Ternary{name: &'static str, arg1: &'static str, arg2: &'static str, proto: &'static str},
|
||||
}
|
||||
|
||||
impl MethodProto {
|
||||
|
||||
pub fn eq(&self, name: &str) -> bool {
|
||||
match *self {
|
||||
MethodProto::Len{name: n, proto: _} => n == name,
|
||||
//MethodProto::Unary(n) => n == name,
|
||||
MethodProto::Binary{name: n, arg: _, proto: _} => n == name,
|
||||
MethodProto::Ternary{name: n, arg1: _, arg2: _, proto: _} => n == name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn impl_method_proto(cls: &Box<syn::Ty>,
|
||||
sig: &syn::MethodSig,
|
||||
meth: &MethodProto) -> Tokens {
|
||||
match sig.decl.output {
|
||||
syn::FunctionRetTy::Ty(ref ty) => {
|
||||
match *meth {
|
||||
MethodProto::Len{name: _, proto} => {
|
||||
let p = syn::Ident::from(proto);
|
||||
quote! {
|
||||
impl #p for #cls {
|
||||
type Result = #ty;
|
||||
}
|
||||
}
|
||||
},
|
||||
MethodProto::Binary{name: _, arg, proto} => {
|
||||
let p = syn::Ident::from(proto);
|
||||
let arg_name = syn::Ident::from(arg);
|
||||
let arg_ty = get_arg_ty(sig, 2);
|
||||
let succ = get_res_success(ty);
|
||||
|
||||
quote! {
|
||||
impl #p for #cls {
|
||||
type #arg_name = #arg_ty;
|
||||
type Success = #succ;
|
||||
type Result = #ty;
|
||||
}
|
||||
}
|
||||
},
|
||||
MethodProto::Ternary{name: _, arg1, arg2, proto} => {
|
||||
let p = syn::Ident::from(proto);
|
||||
let arg1_name = syn::Ident::from(arg1);
|
||||
let arg1_ty = get_arg_ty(sig, 2);
|
||||
let arg2_name = syn::Ident::from(arg2);
|
||||
let arg2_ty = get_arg_ty(sig, 3);
|
||||
let succ = get_res_success(ty);
|
||||
|
||||
quote! {
|
||||
impl #p for #cls {
|
||||
type #arg1_name = #arg1_ty;
|
||||
type #arg2_name = #arg2_ty;
|
||||
type Success = #succ;
|
||||
type Result = #ty;
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
_ => panic!("not supported"),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn get_arg_ty(sig: &syn::MethodSig, idx: usize) -> syn::Ty {
|
||||
match sig.decl.inputs[idx] {
|
||||
syn::FnArg::Captured(_, ref arg_ty) => {
|
||||
arg_ty.clone()
|
||||
},
|
||||
_ =>
|
||||
panic!("not supported"),
|
||||
}
|
||||
}
|
||||
|
||||
// Success
|
||||
fn get_res_success(ty: &syn::Ty) -> syn::Ty {
|
||||
match ty {
|
||||
&syn::Ty::Path(_, ref path) => {
|
||||
if let Some(segment) = path.segments.last() {
|
||||
match segment.ident.as_ref() {
|
||||
// check result type
|
||||
"PyResult" => match segment.parameters {
|
||||
syn::PathParameters::AngleBracketed(ref data) => {
|
||||
data.types[0].clone()
|
||||
},
|
||||
_ => panic!("not supported"),
|
||||
},
|
||||
_ => panic!("not supported"),
|
||||
}
|
||||
} else {
|
||||
panic!("not supported")
|
||||
}
|
||||
}
|
||||
_ => panic!("not supported"),
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@ mod py_class;
|
|||
mod py_impl;
|
||||
mod py_proto;
|
||||
mod py_method;
|
||||
mod func;
|
||||
mod utils;
|
||||
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ use syn;
|
|||
use quote::{Tokens, ToTokens};
|
||||
|
||||
use py_method;
|
||||
use func::{MethodProto, impl_method_proto};
|
||||
|
||||
|
||||
struct Methods {
|
||||
|
@ -12,6 +13,11 @@ struct Methods {
|
|||
no_adjust: bool,
|
||||
}
|
||||
|
||||
struct Proto {
|
||||
//py_methods: &'static [&'static str],
|
||||
methods: &'static [MethodProto],
|
||||
}
|
||||
|
||||
static DEFAULT_METHODS: Methods = Methods {
|
||||
methods: &[],
|
||||
non_pyobj_result: &[],
|
||||
|
@ -42,12 +48,6 @@ static DESCR_METHODS: Methods = Methods {
|
|||
no_adjust: true,
|
||||
};
|
||||
|
||||
static MAPPING_METHODS: Methods = Methods {
|
||||
methods: &[],
|
||||
non_pyobj_result: &["__setitem__", "__len__"],
|
||||
no_adjust: false,
|
||||
};
|
||||
|
||||
static NUM_METHODS: Methods = Methods {
|
||||
methods: &[
|
||||
"__radd__", "__rsub__", "__rmul__", "__rmatmul__", "__rtruediv__",
|
||||
|
@ -59,6 +59,28 @@ static NUM_METHODS: Methods = Methods {
|
|||
no_adjust: true,
|
||||
};
|
||||
|
||||
static MAPPING: Proto = Proto {
|
||||
//py_methods: &[],
|
||||
methods: &[
|
||||
MethodProto::Len{
|
||||
name: "__len__",
|
||||
proto: "class::mapping::PyMappingLenProtocol"},
|
||||
MethodProto::Binary{
|
||||
name: "__getitem__",
|
||||
arg: "Key",
|
||||
proto: "class::mapping::PyMappingGetItemProtocol"},
|
||||
MethodProto::Ternary{
|
||||
name: "__setitem__",
|
||||
arg1: "Key",
|
||||
arg2: "Value",
|
||||
proto: "class::mapping::PyMappingSetItemProtocol"},
|
||||
MethodProto::Binary{
|
||||
name: "__delitem__",
|
||||
arg: "Key",
|
||||
proto: "class::mapping::PyMappingDelItemProtocol"},
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
enum ImplType {
|
||||
Object,
|
||||
|
@ -95,15 +117,14 @@ pub fn build_py_proto(ast: &mut syn::Item) -> Tokens {
|
|||
ImplType::GC =>
|
||||
impl_protocol("pyo3::class::gc::PyGCProtocolImpl",
|
||||
path.clone(), ty, impl_items, &GC_METHODS),
|
||||
ImplType::Mapping =>
|
||||
impl_protocol("pyo3::class::mapping::PyMappingProtocolImpl",
|
||||
path.clone(), ty, impl_items, &MAPPING_METHODS),
|
||||
ImplType::Sequence =>
|
||||
impl_protocol("pyo3::class::mapping::PySequenceProtocolImpl",
|
||||
path.clone(), ty, impl_items, &DEFAULT_METHODS),
|
||||
ImplType::Number =>
|
||||
impl_protocol("pyo3::class::number::PyNumberProtocolImpl",
|
||||
path.clone(), ty, impl_items, &NUM_METHODS),
|
||||
ImplType::Mapping =>
|
||||
impl_proto_impl(ty, impl_items, &MAPPING),
|
||||
}
|
||||
} else {
|
||||
panic!("#[proto] can only be used with protocol trait implementations")
|
||||
|
@ -132,6 +153,24 @@ fn process_path(path: &syn::Path) -> ImplType {
|
|||
}
|
||||
}
|
||||
|
||||
fn impl_proto_impl(ty: &Box<syn::Ty>, impls: &mut Vec<syn::ImplItem>, proto: &Proto) -> Tokens {
|
||||
let mut tokens = Tokens::new();
|
||||
|
||||
for iimpl in impls.iter_mut() {
|
||||
match iimpl.node {
|
||||
syn::ImplItemKind::Method(ref mut sig, _) => {
|
||||
for m in proto.methods {
|
||||
if m.eq(iimpl.ident.as_ref()) {
|
||||
impl_method_proto(ty, sig, m).to_tokens(&mut tokens);
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
tokens
|
||||
}
|
||||
|
||||
fn impl_protocol(name: &'static str,
|
||||
path: syn::Path, ty: &Box<syn::Ty>,
|
||||
impls: &mut Vec<syn::ImplItem>, methods: &Methods) -> Tokens {
|
||||
|
|
|
@ -42,6 +42,25 @@ macro_rules! py_unary_func {
|
|||
}}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! py_len_func_ {
|
||||
($trait:ident, $class:ident :: $f:ident, $conv:expr) => {{
|
||||
unsafe extern "C" fn wrap<T>(slf: *mut $crate::ffi::PyObject) -> $crate::ffi::Py_ssize_t
|
||||
where T: $trait
|
||||
{
|
||||
const LOCATION: &'static str = concat!(stringify!($class), ".", stringify!($f), "()");
|
||||
$crate::callback::handle_callback(LOCATION, $conv, |py| {
|
||||
let slf = $crate::PyObject::from_borrowed_ptr(py, slf).unchecked_cast_into::<T>();
|
||||
let ret = slf.$f(py);
|
||||
$crate::PyDrop::release_ref(slf, py);
|
||||
ret.into()
|
||||
})
|
||||
}
|
||||
Some(wrap::<$class>)
|
||||
}}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! py_binary_func {
|
||||
|
@ -65,6 +84,32 @@ macro_rules! py_binary_func {
|
|||
}}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! py_binary_func_ {
|
||||
($trait:ident, $class:ident :: $f:ident, $conv:expr) => {{
|
||||
unsafe extern "C" fn wrap<T>(slf: *mut $crate::ffi::PyObject,
|
||||
arg: *mut $crate::ffi::PyObject)
|
||||
-> *mut $crate::ffi::PyObject
|
||||
where T: $trait
|
||||
{
|
||||
const LOCATION: &'static str = concat!(stringify!($class), ".", stringify!($f), "()");
|
||||
$crate::callback::handle_callback(LOCATION, $conv, |py| {
|
||||
let slf = $crate::PyObject::from_borrowed_ptr(py, slf).unchecked_cast_into::<T>();
|
||||
let arg = $crate::PyObject::from_borrowed_ptr(py, arg);
|
||||
let ret = match arg.extract(py) {
|
||||
Ok(arg) => slf.$f(py, arg).into(),
|
||||
Err(e) => Err(e),
|
||||
};
|
||||
$crate::PyDrop::release_ref(arg, py);
|
||||
$crate::PyDrop::release_ref(slf, py);
|
||||
ret
|
||||
})
|
||||
}
|
||||
Some(wrap::<$class>)
|
||||
}}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! py_ternary_func {
|
||||
|
|
|
@ -9,118 +9,276 @@ use ffi;
|
|||
use err::{PyErr, PyResult};
|
||||
use python::{Python, PythonObject, PyDrop};
|
||||
use objects::{exc, PyObject};
|
||||
use callback::{handle_callback, PyObjectCallbackConverter,
|
||||
LenResultConverter, UnitCallbackConverter};
|
||||
use class::NO_METHODS;
|
||||
use callback::{PyObjectCallbackConverter, LenResultConverter, UnitCallbackConverter};
|
||||
use conversion::{ToPyObject, FromPyObject};
|
||||
|
||||
|
||||
/// Mapping interface
|
||||
pub trait PyMappingProtocol {
|
||||
fn __len__(&self, py: Python) -> PyResult<usize>;
|
||||
#[allow(unused_variables)]
|
||||
pub trait PyMappingProtocol: PythonObject {
|
||||
fn __len__(&self, py: Python) -> Self::Result
|
||||
where Self: PyMappingLenProtocol
|
||||
{ unimplemented!() }
|
||||
|
||||
fn __getitem__(&self, py: Python, key: &PyObject) -> PyResult<PyObject>;
|
||||
fn __getitem__(&self, py: Python, key: Self::Key) -> Self::Result
|
||||
where Self: PyMappingGetItemProtocol
|
||||
{ unimplemented!() }
|
||||
|
||||
fn __setitem__(&self, py: Python, key: &PyObject, value: &PyObject) -> PyResult<()>;
|
||||
fn __setitem__(&self, py: Python, key: Self::Key, value: Self::Value) -> Self::Result
|
||||
where Self: PyMappingSetItemProtocol
|
||||
{ unimplemented!() }
|
||||
|
||||
fn __delitem__(&self, py: Python, key: Self::Key) -> Self::Result
|
||||
where Self: PyMappingDelItemProtocol
|
||||
{ unimplemented!() }
|
||||
|
||||
fn __delitem__(&self, py: Python, key: &PyObject) -> PyResult<()>;
|
||||
}
|
||||
|
||||
impl<T> PyMappingProtocol for T where T: PythonObject {
|
||||
default fn __len__(&self, _py: Python) -> PyResult<usize> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
default fn __getitem__(&self, py: Python, _: &PyObject) -> PyResult<PyObject> {
|
||||
Ok(py.None())
|
||||
}
|
||||
// The following are a bunch of marker traits used to detect
|
||||
// the existance of a slotted method.
|
||||
|
||||
default fn __setitem__(&self, py: Python, _: &PyObject, _: &PyObject) -> PyResult<()> {
|
||||
Err(PyErr::new::<exc::NotImplementedError, _>(
|
||||
py, format!("Subscript assignment not supported by {:?}", self.as_object())))
|
||||
}
|
||||
pub trait PyMappingLenProtocol: PyMappingProtocol {
|
||||
type Result: Into<PyResult<usize>>;
|
||||
}
|
||||
|
||||
default fn __delitem__(&self, py: Python, _: &PyObject) -> PyResult<()> {
|
||||
Err(PyErr::new::<exc::NotImplementedError, _>(
|
||||
py, format!("Subscript deletion not supported by {:?}", self.as_object())))
|
||||
}
|
||||
pub trait PyMappingGetItemProtocol: PyMappingProtocol {
|
||||
type Key: for<'a> FromPyObject<'a>;
|
||||
type Success: ToPyObject;
|
||||
type Result: Into<PyResult<Self::Success>>;
|
||||
}
|
||||
|
||||
pub trait PyMappingSetItemProtocol: PyMappingProtocol {
|
||||
type Key: for<'a> FromPyObject<'a>;
|
||||
type Value: for<'a> FromPyObject<'a>;
|
||||
type Success: ToPyObject;
|
||||
type Result: Into<PyResult<()>>;
|
||||
}
|
||||
|
||||
pub trait PyMappingDelItemProtocol: PyMappingProtocol {
|
||||
type Key: for<'a> FromPyObject<'a>;
|
||||
type Success: ToPyObject;
|
||||
type Result: Into<PyResult<()>>;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait PyMappingProtocolImpl {
|
||||
fn methods() -> &'static [&'static str];
|
||||
fn tp_as_mapping() -> Option<ffi::PyMappingMethods>;
|
||||
}
|
||||
|
||||
impl<T> PyMappingProtocolImpl for T {
|
||||
default fn methods() -> &'static [&'static str] {
|
||||
NO_METHODS
|
||||
#[inline]
|
||||
default fn tp_as_mapping() -> Option<ffi::PyMappingMethods> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl ffi::PyMappingMethods {
|
||||
impl<T> PyMappingProtocolImpl for T where T: PyMappingProtocol {
|
||||
#[inline]
|
||||
fn tp_as_mapping() -> Option<ffi::PyMappingMethods> {
|
||||
let mut f = Self::mp_ass_subscript();
|
||||
|
||||
/// Construct PyMappingMethods struct for PyTypeObject.tp_as_mapping
|
||||
pub fn new<T>() -> Option<ffi::PyMappingMethods>
|
||||
where T: PyMappingProtocol + PyMappingProtocolImpl + PythonObject
|
||||
{
|
||||
let methods = T::methods();
|
||||
if methods.is_empty() {
|
||||
return None
|
||||
if let Some(df) = Self::mp_del_subscript() {
|
||||
f = Some(df)
|
||||
}
|
||||
|
||||
let mut meth: ffi::PyMappingMethods = ffi::PyMappingMethods_INIT;
|
||||
|
||||
for name in methods {
|
||||
match name {
|
||||
&"__len__" => {
|
||||
meth.mp_length = py_len_func!(
|
||||
PyMappingProtocol, T::__len__, LenResultConverter);
|
||||
},
|
||||
&"__getitem__" => {
|
||||
meth.mp_subscript = py_binary_func!(
|
||||
PyMappingProtocol, T::__getitem__, PyObjectCallbackConverter);
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
// always set
|
||||
meth.mp_ass_subscript = Some(mp_ass_subscript::<T>());
|
||||
|
||||
Some(meth)
|
||||
Some(ffi::PyMappingMethods {
|
||||
mp_length: Self::mp_length(),
|
||||
mp_subscript: Self::mp_subscript(),
|
||||
mp_ass_subscript: f,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
trait PyMappingLenProtocolImpl {
|
||||
fn mp_length() -> Option<ffi::lenfunc>;
|
||||
}
|
||||
|
||||
fn mp_ass_subscript<T>() -> ffi::objobjargproc
|
||||
where T: PyMappingProtocol + PythonObject
|
||||
impl<T> PyMappingLenProtocolImpl for T
|
||||
where T: PyMappingProtocol
|
||||
{
|
||||
unsafe extern "C" fn wrap<T>(slf: *mut ffi::PyObject,
|
||||
key: *mut ffi::PyObject,
|
||||
value: *mut ffi::PyObject) -> c_int
|
||||
where T: PyMappingProtocol + PythonObject
|
||||
{
|
||||
const LOCATION: &'static str = concat!(stringify!($class), ".__setitem__()");
|
||||
#[inline]
|
||||
default fn mp_length() -> Option<ffi::lenfunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
handle_callback(
|
||||
LOCATION, UnitCallbackConverter, |py|
|
||||
{
|
||||
impl<T> PyMappingLenProtocolImpl for T
|
||||
where T: PyMappingLenProtocol
|
||||
{
|
||||
#[inline]
|
||||
fn mp_length() -> Option<ffi::lenfunc> {
|
||||
py_len_func_!(PyMappingLenProtocol, T::__len__, LenResultConverter)
|
||||
}
|
||||
}
|
||||
|
||||
trait PyMappingGetItemProtocolImpl {
|
||||
fn mp_subscript() -> Option<ffi::binaryfunc>;
|
||||
}
|
||||
|
||||
impl<T> PyMappingGetItemProtocolImpl for T
|
||||
where T: PyMappingProtocol
|
||||
{
|
||||
#[inline]
|
||||
default fn mp_subscript() -> Option<ffi::binaryfunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PyMappingGetItemProtocolImpl for T
|
||||
where T: PyMappingGetItemProtocol
|
||||
{
|
||||
#[inline]
|
||||
fn mp_subscript() -> Option<ffi::binaryfunc> {
|
||||
py_binary_func_!(PyMappingGetItemProtocol, T::__getitem__, PyObjectCallbackConverter)
|
||||
}
|
||||
}
|
||||
|
||||
trait PyMappingSetItemProtocolImpl {
|
||||
fn mp_ass_subscript() -> Option<ffi::objobjargproc>;
|
||||
}
|
||||
|
||||
impl<T> PyMappingSetItemProtocolImpl for T
|
||||
where T: PyMappingProtocol
|
||||
{
|
||||
#[inline]
|
||||
default fn mp_ass_subscript() -> Option<ffi::objobjargproc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PyMappingSetItemProtocolImpl for T
|
||||
where T: PyMappingSetItemProtocol
|
||||
{
|
||||
#[inline]
|
||||
fn mp_ass_subscript() -> Option<ffi::objobjargproc> {
|
||||
unsafe extern "C" fn wrap<T>(slf: *mut ffi::PyObject,
|
||||
key: *mut ffi::PyObject,
|
||||
value: *mut ffi::PyObject) -> c_int
|
||||
where T: PyMappingSetItemProtocol
|
||||
{
|
||||
const LOCATION: &'static str = "T.__setitem__()";
|
||||
::callback::handle_callback(LOCATION, UnitCallbackConverter, |py| {
|
||||
let slf = PyObject::from_borrowed_ptr(py, slf).unchecked_cast_into::<T>();
|
||||
let key = PyObject::from_borrowed_ptr(py, key);
|
||||
|
||||
// if value is none, then __delitem__
|
||||
let ret = if value.is_null() {
|
||||
slf.__delitem__(py, &key)
|
||||
} else {
|
||||
let value = PyObject::from_borrowed_ptr(py, value);
|
||||
let ret = slf.__setitem__(py, &key, &value);
|
||||
PyDrop::release_ref(value, py);
|
||||
ret
|
||||
let ret = match key.extract(py) {
|
||||
Ok(key) =>
|
||||
if value.is_null() {
|
||||
Err(PyErr::new::<exc::NotImplementedError, _>(
|
||||
py, format!("Subscript deletion not supported by {:?}",
|
||||
stringify!(T))))
|
||||
} else {
|
||||
let value = PyObject::from_borrowed_ptr(py, value);
|
||||
let ret = match value.extract(py) {
|
||||
Ok(value) => slf.__setitem__(py, key, value).into(),
|
||||
Err(e) => Err(e),
|
||||
};
|
||||
PyDrop::release_ref(value, py);
|
||||
ret
|
||||
},
|
||||
Err(e) => Err(e),
|
||||
};
|
||||
|
||||
PyDrop::release_ref(key, py);
|
||||
PyDrop::release_ref(slf, py);
|
||||
ret
|
||||
})
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
trait PyMappingDelItemProtocolImpl {
|
||||
fn mp_del_subscript() -> Option<ffi::objobjargproc>;
|
||||
}
|
||||
|
||||
impl<T> PyMappingDelItemProtocolImpl for T
|
||||
where T: PyMappingProtocol
|
||||
{
|
||||
#[inline]
|
||||
default fn mp_del_subscript() -> Option<ffi::objobjargproc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PyMappingDelItemProtocolImpl for T
|
||||
where T: PyMappingDelItemProtocol
|
||||
{
|
||||
#[inline]
|
||||
default fn mp_del_subscript() -> Option<ffi::objobjargproc> {
|
||||
unsafe extern "C" fn wrap<T>(slf: *mut ffi::PyObject,
|
||||
key: *mut ffi::PyObject,
|
||||
value: *mut ffi::PyObject) -> c_int
|
||||
where T: PyMappingDelItemProtocol
|
||||
{
|
||||
const LOCATION: &'static str = "T.__detitem__()";
|
||||
::callback::handle_callback(LOCATION, UnitCallbackConverter, |py| {
|
||||
let slf = PyObject::from_borrowed_ptr(py, slf).unchecked_cast_into::<T>();
|
||||
let key = PyObject::from_borrowed_ptr(py, key);
|
||||
|
||||
let ret = match key.extract(py) {
|
||||
Ok(key) =>
|
||||
if value.is_null() {
|
||||
slf.__delitem__(py, key).into()
|
||||
} else {
|
||||
Err(PyErr::new::<exc::NotImplementedError, _>(
|
||||
py, format!("Subscript assignment not supported by {:?}",
|
||||
stringify!(T))))
|
||||
},
|
||||
Err(e) => Err(e),
|
||||
};
|
||||
|
||||
PyDrop::release_ref(key, py);
|
||||
PyDrop::release_ref(slf, py);
|
||||
ret
|
||||
})
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PyMappingDelItemProtocolImpl for T
|
||||
where T: PyMappingSetItemProtocol + PyMappingDelItemProtocol
|
||||
{
|
||||
#[inline]
|
||||
fn mp_del_subscript() -> Option<ffi::objobjargproc> {
|
||||
unsafe extern "C" fn wrap<T>(slf: *mut ffi::PyObject,
|
||||
key: *mut ffi::PyObject,
|
||||
value: *mut ffi::PyObject) -> c_int
|
||||
where T: PyMappingSetItemProtocol + PyMappingDelItemProtocol
|
||||
{
|
||||
const LOCATION: &'static str = "T.__set/del_item__()";
|
||||
::callback::handle_callback(LOCATION, UnitCallbackConverter, |py| {
|
||||
let slf = PyObject::from_borrowed_ptr(py, slf).unchecked_cast_into::<T>();
|
||||
let key = PyObject::from_borrowed_ptr(py, key);
|
||||
|
||||
let ret = if value.is_null() {
|
||||
match key.extract(py) {
|
||||
Ok(key) => slf.__delitem__(py, key).into(),
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
} else {
|
||||
match key.extract(py) {
|
||||
Ok(key) => {
|
||||
let value = PyObject::from_borrowed_ptr(py, value);
|
||||
let ret = match value.extract(py) {
|
||||
Ok(value) => slf.__setitem__(py, key, value).into(),
|
||||
Err(e) => Err(e),
|
||||
};
|
||||
PyDrop::release_ref(value, py);
|
||||
ret
|
||||
},
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
};
|
||||
|
||||
PyDrop::release_ref(key, py);
|
||||
PyDrop::release_ref(slf, py);
|
||||
ret
|
||||
})
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
}
|
||||
wrap::<T>
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ pub fn initialize_type<T>(py: Python, module_name: Option<&str>,
|
|||
}
|
||||
|
||||
// mapping methods
|
||||
if let Some(meth) = ffi::PyMappingMethods::new::<T>() {
|
||||
if let Some(meth) = <T as class::mapping::PyMappingProtocolImpl>::tp_as_mapping() {
|
||||
static mut MP_METHODS: ffi::PyMappingMethods = ffi::PyMappingMethods_INIT;
|
||||
*(unsafe { &mut MP_METHODS }) = meth;
|
||||
type_object.tp_as_mapping = unsafe { &mut MP_METHODS };
|
||||
|
|
Loading…
Reference in a new issue