diff --git a/src/class/macros.rs b/src/class/macros.rs index e6789b19e24..48468a6396a 100644 --- a/src/class/macros.rs +++ b/src/class/macros.rs @@ -8,37 +8,17 @@ macro_rules! py_unary_func { }; ($trait:ident, $class:ident :: $f:ident, $conv:expr, $res_type:ty) => {{ unsafe extern "C" fn wrap(slf: *mut $crate::ffi::PyObject) -> $res_type - where T: $trait + PythonObject + where T: $trait { 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::(); let ret = slf.$f(py); $crate::PyDrop::release_ref(slf, py); - ret + ret.into() }) } - Some(wrap::) - }} -} - -#[macro_export] -#[doc(hidden)] - macro_rules! py_len_func { - ($trait:ident, $class:ident :: $f:ident, $conv:expr) => {{ - unsafe extern "C" fn wrap(slf: *mut $crate::ffi::PyObject) - -> $crate::ffi::Py_ssize_t - where T: $trait + PythonObject - { - 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::(); - let ret = slf.$f(py); - $crate::PyDrop::release_ref(slf, py); - ret - }) - } - Some(wrap::) + Some(wrap::<$class>) }} } @@ -46,22 +26,26 @@ macro_rules! py_unary_func { #[doc(hidden)] macro_rules! py_binary_func { ($trait:ident, $class:ident :: $f:ident, $conv:expr) => {{ - unsafe extern "C" fn wrap(slf: *mut $crate::ffi::PyObject, - arg: *mut $crate::ffi::PyObject) - -> *mut $crate::ffi::PyObject - where T: $trait + PythonObject + unsafe extern "C" fn wrap( + 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::_detail::handle_callback(LOCATION, $conv, |py| { let slf = $crate::PyObject::from_borrowed_ptr(py, slf).unchecked_cast_into::(); let arg = $crate::PyObject::from_borrowed_ptr(py, arg); - let ret = slf.$f(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::) + Some(wrap::<$class>) }} } @@ -72,10 +56,12 @@ macro_rules! py_ternary_func { py_ternary_func!($trait, $class::$f, $conv, *mut $crate::ffi::PyObject); }; ($trait:ident, $class:ident :: $f:ident, $conv:expr, $res_type:ty) => {{ - unsafe extern "C" fn wrap(slf: *mut $crate::ffi::PyObject, - arg1: *mut $crate::ffi::PyObject, - arg2: *mut $crate::ffi::PyObject) -> $res_type - where T: $trait + PythonObject + unsafe extern "C" fn wrap( + slf: *mut $crate::ffi::PyObject, + arg1: *mut $crate::ffi::PyObject, + arg2: *mut $crate::ffi::PyObject, + ) -> $res_type + where T: $trait { const LOCATION: &'static str = concat!(stringify!($class), ".", stringify!($f), "()"); $crate::_detail::handle_callback(LOCATION, $conv, |py| { @@ -86,30 +72,50 @@ macro_rules! py_ternary_func { $crate::PyDrop::release_ref(arg1, py); $crate::PyDrop::release_ref(arg2, py); $crate::PyDrop::release_ref(slf, py); - ret + ret.into() }) } - Some(wrap::) + Some(wrap::<$class>) }} } +#[macro_export] +#[doc(hidden)] +macro_rules! py_len_func { + ($trait:ident, $class:ident :: $f:ident, $conv:expr) => {{ + unsafe extern "C" fn wrap(slf: *mut $crate::ffi::PyObject) -> $crate::ffi::Py_ssize_t + where T: $trait + { + 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::(); + let ret = slf.$f(py); + $crate::PyDrop::release_ref(slf, py); + ret.into() + }) + } + Some(wrap::<$class>) + }} +} #[macro_export] #[doc(hidden)] macro_rules! py_ssizearg_func { ($trait:ident, $class:ident :: $f:ident, $conv:expr) => {{ - unsafe extern "C" fn wrap(slf: *mut $crate::ffi::PyObject, - arg: $crate::Py_ssize_t) -> *mut $crate::ffi::PyObject - where T: $trait + PythonObject + unsafe extern "C" fn wrap( + slf: *mut $crate::ffi::PyObject, + arg: $crate::Py_ssize_t, + ) -> *mut $crate::ffi::PyObject + where T: $trait { 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::(); let ret = slf.$f(py, arg as isize); $crate::PyDrop::release_ref(slf, py); - ret + ret.into() }) } - Some(wrap::) + Some(wrap::<$class>) }} } @@ -118,15 +124,20 @@ macro_rules! py_ssizearg_func { #[doc(hidden)] macro_rules! py_objobj_proc { ($trait:ident, $class:ident :: $f:ident, $conv:expr) => {{ - unsafe extern "C" fn wrap(slf: *mut $crate::ffi::PyObject, - arg: *mut $crate::ffi::PyObject) -> $crate::c_int + unsafe extern "C" fn wrap( + slf: *mut $crate::ffi::PyObject, + arg: *mut $crate::ffi::PyObject, + ) -> $crate::c_int where T: $trait + PythonObject { 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::(); let arg = PyObject::from_borrowed_ptr(py, arg); - let ret = slf.$f(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 @@ -144,7 +155,8 @@ macro_rules! py_ternary_slot { unsafe extern "C" fn wrap( slf: *mut $crate::ffi::PyObject, arg1: *mut $crate::ffi::PyObject, - arg2: *mut $crate::ffi::PyObject) -> $res_type + arg2: *mut $crate::ffi::PyObject, + ) -> $res_type where T: $trait + PythonObject { const LOCATION: &'static str = concat!(stringify!($class), ".", stringify!($f), "()"); diff --git a/src/class/mapping.rs b/src/class/mapping.rs index ab144d48903..82599878402 100644 --- a/src/class/mapping.rs +++ b/src/class/mapping.rs @@ -6,121 +6,162 @@ use std::os::raw::c_int; use ffi; -use err::{PyErr, PyResult}; +use err::PyResult; use python::{Python, PythonObject, PyDrop}; -use objects::{exc, PyObject}; +use objects::PyObject; use py_class::slots::{LenResultConverter, UnitCallbackConverter}; -use function::{handle_callback, PyObjectCallbackConverter}; -use class::NO_METHODS; - +use function::PyObjectCallbackConverter; +use conversion::{ToPyObject, FromPyObject}; /// Mapping interface -pub trait PyMappingProtocol { - fn __len__(&self, py: Python) -> PyResult; - - fn __getitem__(&self, py: Python, key: &PyObject) -> PyResult; +pub trait PyMappingProtocol: PythonObject { + fn __len__(&self, py: Python) -> Self::Result + where Self: PyMappingLenProtocol; - fn __setitem__(&self, py: Python, key: &PyObject, value: &PyObject) -> PyResult<()>; + fn __getitem__(&self, py: Python, key: Self::Key) -> Self::Result + where Self: PyMappingGetItemProtocol; - fn __delitem__(&self, py: Python, key: &PyObject) -> PyResult<()>; + fn __setitem__(&self, py: Python, key: Self::Key, value: Option) -> Self::Result + where Self: PyMappingSetItemProtocol; } -impl PyMappingProtocol for T where T: PythonObject { - default fn __len__(&self, _py: Python) -> PyResult { - Ok(0) - } +// The following are a bunch of marker traits used to detect +// the existance of a slotted method. - default fn __getitem__(&self, py: Python, _: &PyObject) -> PyResult { - Ok(py.None()) - } +pub trait PyMappingLenProtocol: PyMappingProtocol { + type Result: Into>; +} - default fn __setitem__(&self, py: Python, _: &PyObject, _: &PyObject) -> PyResult<()> { - Err(PyErr::new::( - py, format!("Subscript assignment not supported by {:?}", self.as_object()))) - } +pub trait PyMappingGetItemProtocol: PyMappingProtocol { + type Key: for<'a> FromPyObject<'a>; + type Success: ToPyObject; + type Result: Into>; +} - default fn __delitem__(&self, py: Python, _: &PyObject) -> PyResult<()> { - Err(PyErr::new::( - py, format!("Subscript deletion not supported by {:?}", self.as_object()))) - } +pub trait PyMappingSetItemProtocol: PyMappingProtocol { + type Key: for<'a> FromPyObject<'a>; + type Value: for<'a> FromPyObject<'a>; + type Result: Into>; } #[doc(hidden)] pub trait PyMappingProtocolImpl { - fn methods() -> &'static [&'static str]; + fn tp_as_mapping() -> Option; } impl PyMappingProtocolImpl for T { - default fn methods() -> &'static [&'static str] { - NO_METHODS + #[inline] + default fn tp_as_mapping() -> Option { + None } } -impl ffi::PyMappingMethods { +impl PyMappingProtocolImpl for T where T: PyMappingProtocol { + #[inline] + fn tp_as_mapping() -> Option { + Some(ffi::PyMappingMethods { + mp_length: Self::mp_length(), + mp_subscript: Self::mp_subscript(), + mp_ass_subscript: Self::mp_ass_subscript(), + }) + } +} - /// Construct PyMappingMethods struct for PyTypeObject.tp_as_mapping - pub fn new() -> Option - where T: PyMappingProtocol + PyMappingProtocolImpl + PythonObject - { - let methods = T::methods(); - if methods.is_empty() { - return None - } +trait PyMappingLenProtocolImpl { + fn mp_length() -> Option; +} - 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!(), - } - } +impl PyMappingLenProtocolImpl for T + where T: PyMappingProtocol +{ + #[inline] + default fn mp_length() -> Option { + None + } +} + +impl PyMappingLenProtocolImpl for T + where T: PyMappingLenProtocol +{ + #[inline] + fn mp_length() -> Option { + py_len_func!(PyMappingLenProtocol, T::__len__, LenResultConverter) + } +} - // always set - meth.mp_ass_subscript = Some(mp_ass_subscript::()); +trait PyMappingGetItemProtocolImpl { + fn mp_subscript() -> Option; +} - Some(meth) +impl PyMappingGetItemProtocolImpl for T + where T: PyMappingProtocol +{ + #[inline] + default fn mp_subscript() -> Option { + None } } +impl PyMappingGetItemProtocolImpl for T + where T: PyMappingGetItemProtocol +{ + #[inline] + fn mp_subscript() -> Option { + py_binary_func!(PyMappingGetItemProtocol, T::__getitem__, PyObjectCallbackConverter) + } +} -fn mp_ass_subscript() -> ffi::objobjargproc - where T: PyMappingProtocol + PythonObject +trait PyMappingSetItemProtocolImpl { + fn mp_ass_subscript() -> Option; +} + +impl PyMappingSetItemProtocolImpl for T + where T: PyMappingProtocol +{ + #[inline] + default fn mp_ass_subscript() -> Option { + None + } +} + +impl PyMappingSetItemProtocolImpl for T + where T: PyMappingSetItemProtocol { - unsafe extern "C" fn wrap(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__()"); - - handle_callback( - LOCATION, UnitCallbackConverter, |py| - { + #[inline] + fn mp_ass_subscript() -> Option { + unsafe extern "C" fn wrap( + slf: *mut ffi::PyObject, + key: *mut ffi::PyObject, + value: *mut ffi::PyObject, + ) -> c_int + where T: PyMappingSetItemProtocol + { + const LOCATION: &'static str = "T.__setitem__()"; + ::_detail::handle_callback(LOCATION, UnitCallbackConverter, |py| { let slf = PyObject::from_borrowed_ptr(py, slf).unchecked_cast_into::(); 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() { + slf.__setitem__(py, key, None).into() + } else { + let value = PyObject::from_borrowed_ptr(py, value); + let ret = match value.extract(py) { + Ok(value) => slf.__setitem__(py, key, Some(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::) } - wrap:: -} +} \ No newline at end of file diff --git a/src/class/mod.rs b/src/class/mod.rs index 67ec718c243..3343371480f 100644 --- a/src/class/mod.rs +++ b/src/class/mod.rs @@ -2,30 +2,30 @@ #[macro_use] mod macros; -pub mod async; -pub mod basic; -pub mod buffer; -pub mod context; -pub mod descr; +//pub mod async; +//pub mod basic; +//pub mod buffer; +//pub mod context; +//pub mod descr; pub mod mapping; -pub mod methods; -pub mod number; -pub mod gc; +//pub mod methods; +//pub mod number; +//pub mod gc; pub mod sequence; -pub mod typeob; +//pub mod typeob; -pub use self::basic::PyObjectProtocol; -pub use self::async::PyAsyncProtocol; -pub use self::buffer::PyBufferProtocol; -pub use self::context::PyContextProtocol; -pub use self::descr::PyDescrProtocol; -pub use self::number::PyNumberProtocol; +//pub use self::basic::PyObjectProtocol; +//pub use self::async::PyAsyncProtocol; +//pub use self::buffer::PyBufferProtocol; +//pub use self::context::PyContextProtocol; +//pub use self::descr::PyDescrProtocol; +//pub use self::number::PyNumberProtocol; pub use self::mapping::PyMappingProtocol; pub use self::sequence::PySequenceProtocol; -pub use self::gc::{PyVisit, PyGCProtocol, PyTraverseError}; -pub use self::methods::{PyMethodDef, PyMethodDefType, PyMethodType, - PyGetterDef, PySetterDef}; +//pub use self::gc::{PyVisit, PyGCProtocol, PyTraverseError}; +//pub use self::methods::{PyMethodDef, PyMethodDefType, PyMethodType, + // PyGetterDef, PySetterDef}; -pub static NO_METHODS: &'static [&'static str] = &[]; -pub static NO_PY_METHODS: &'static [PyMethodDefType] = &[]; +//pub static NO_METHODS: &'static [&'static str] = &[]; +//pub static NO_PY_METHODS: &'static [PyMethodDefType] = &[]; diff --git a/src/class/sequence.rs b/src/class/sequence.rs index 03faac11b02..acdf193e978 100644 --- a/src/class/sequence.rs +++ b/src/class/sequence.rs @@ -6,163 +6,193 @@ use std::os::raw::c_int; use ffi; -use err::{PyErr, PyResult}; +use err::PyResult; use python::{Python, PythonObject, PyDrop}; -use objects::{exc, PyObject}; -use py_class::slots::{LenResultConverter, UnitCallbackConverter, BoolConverter}; -use function::{handle_callback, PyObjectCallbackConverter}; -use class::NO_METHODS; +use objects::PyObject; +use py_class::slots::{LenResultConverter, BoolConverter, UnitCallbackConverter}; +use function::PyObjectCallbackConverter; +use conversion::{ToPyObject, FromPyObject}; +/// Sequence interface +pub trait PySequenceProtocol: PythonObject { + fn __len__(&self, py: Python) -> Self::Result + where Self: PySequenceLenProtocol; -/// Mapping interface -pub trait PySequenceProtocol { - fn __len__(&self, py: Python) -> PyResult; + fn __getitem__(&self, py: Python, key: isize) -> Self::Result + where Self: PySequenceGetItemProtocol; - fn __getitem__(&self, py: Python, key: isize) -> PyResult; + fn __setitem__(&self, py: Python, key: isize, value: Option) -> Self::Result + where Self: PySequenceSetItemProtocol; - fn __setitem__(&self, py: Python, key: isize, value: &PyObject) -> PyResult<()>; + fn __contains__(&self, py: Python, value: Self::Value) -> Self::Result + where Self: PySequenceContainsProtocol; - fn __delitem__(&self, py: Python, key: isize) -> PyResult<()>; + fn __concat__(&self, py: Python, other: Self::Other) -> Self::Result + where Self: PySequenceConcatProtocol; - fn __contains__(&self, py: Python, value: &PyObject) -> PyResult; + fn __repeat__(&self, py: Python, count: isize) -> Self::Result + where Self: PySequenceRepeatProtocol; - fn __concat__(&self, py: Python, other: &PyObject) -> PyResult; + fn __inplace_concat__(&self, py: Python, other: Self::Other) -> Self::Result + where Self: PySequenceInplaceConcatProtocol; - fn __repeat__(&self, py: Python, count: isize) -> PyResult; + fn __inplace_repeat__(&self, py: Python, count: isize) -> Self::Result + where Self: PySequenceInplaceRepeatProtocol; +} - fn __inplace_concat__(&self, py: Python, other: &PyObject) -> PyResult; +// The following are a bunch of marker traits used to detect +// the existance of a slotted method. - fn __inplace_repeat__(&self, py: Python, count: isize) -> PyResult; +pub trait PySequenceLenProtocol: PySequenceProtocol { + type Result: Into>; +} +pub trait PySequenceGetItemProtocol: PySequenceProtocol { + type Success: ToPyObject; + type Result: Into>; } -impl PySequenceProtocol for T where T: PythonObject { - default fn __len__(&self, py: Python) -> PyResult { - Err(PyErr::new::(py, "Not implemented")) - } +pub trait PySequenceSetItemProtocol: PySequenceProtocol { + type Value: for<'a> FromPyObject<'a>; + type Result: Into>; +} - default fn __getitem__(&self, py: Python, _: isize) -> PyResult { - Err(PyErr::new::(py, "Not implemented")) - } +pub trait PySequenceContainsProtocol: PySequenceProtocol { + type Value: for<'a> FromPyObject<'a>; + type Result: Into>; +} - default fn __setitem__(&self, py: Python, _: isize, _: &PyObject) -> PyResult<()> { - Err(PyErr::new::( - py, format!("Subscript assignment not supported by {:?}", self.as_object()))) - } +pub trait PySequenceConcatProtocol: PySequenceProtocol { + type Other: for<'a> FromPyObject<'a>; + type Success: ToPyObject; + type Result: Into>; +} - default fn __delitem__(&self, py: Python, _: isize) -> PyResult<()> { - Err(PyErr::new::( - py, format!("Subscript deletion not supported by {:?}", self.as_object()))) - } +pub trait PySequenceRepeatProtocol: PySequenceProtocol { + type Success: ToPyObject; + type Result: Into>; +} - default fn __contains__(&self, py: Python, _: &PyObject) -> PyResult { - Err(PyErr::new::(py, "Not implemented")) - } +pub trait PySequenceInplaceConcatProtocol: PySequenceProtocol { + type Other: for<'a> FromPyObject<'a>; + type Result: Into>; +} - default fn __concat__(&self, py: Python, _: &PyObject) -> PyResult { - Err(PyErr::new::(py, "Not implemented")) - } +pub trait PySequenceInplaceRepeatProtocol: PySequenceProtocol { + type Result: Into>; +} - default fn __repeat__(&self, py: Python, _: isize) -> PyResult { - Err(PyErr::new::(py, "Not implemented")) - } +#[doc(hidden)] +pub trait PySequenceProtocolImpl { + fn tp_as_sequence() -> Option; +} - default fn __inplace_concat__(&self, py: Python, _: &PyObject) -> PyResult { - Err(PyErr::new::(py, "Not implemented")) +impl PySequenceProtocolImpl for T { + #[inline] + default fn tp_as_sequence() -> Option { + None } +} - default fn __inplace_repeat__(&self, py: Python, _: isize) -> PyResult { - Err(PyErr::new::(py, "Not implemented")) +impl PySequenceProtocolImpl for T where T: PySequenceProtocol { + #[inline] + fn tp_as_sequence() -> Option { + Some(ffi::PySequenceMethods { + sq_length: Self::sq_length(), + sq_concat: Self::sq_concat(), + sq_repeat: Self::sq_repeat(), + sq_item: Self::sq_item(), + was_sq_slice: 0 as *mut _, + sq_ass_item: Self::sq_ass_item(), + was_sq_ass_slice: 0 as *mut _, + sq_contains: Self::sq_contains(), + sq_inplace_concat: Self::sq_inplace_concat(), + sq_inplace_repeat: Self::sq_inplace_repeat(), + }) } } -#[doc(hidden)] -pub trait PySequenceProtocolImpl { - fn methods() -> &'static [&'static str]; +trait PySequenceLenProtocolImpl { + fn sq_length() -> Option; } -impl PySequenceProtocolImpl for T { - default fn methods() -> &'static [&'static str] { - NO_METHODS +impl PySequenceLenProtocolImpl for T + where T: PySequenceProtocol +{ + #[inline] + default fn sq_length() -> Option { + None } } -impl ffi::PySequenceMethods { - - /// Construct PySequenceMethods struct for PyTypeObject.tp_as_sequence - pub fn new() -> Option - where T: PySequenceProtocol + PySequenceProtocolImpl + PythonObject - { - let methods = T::methods(); - if methods.is_empty() { - return None - } +impl PySequenceLenProtocolImpl for T + where T: PySequenceLenProtocol +{ + #[inline] + fn sq_length() -> Option { + py_len_func!(PySequenceLenProtocol, T::__len__, LenResultConverter) + } +} - let mut meth: ffi::PySequenceMethods = ffi::PySequenceMethods_INIT; - - for name in methods { - match name { - &"__len__" => { - meth.sq_length = py_len_func!( - PySequenceProtocol, T::__len__, LenResultConverter); - }, - &"__getitem__" => { - meth.sq_item = py_ssizearg_func!( - PySequenceProtocol, T::__getitem__, PyObjectCallbackConverter); - }, - &"__repeat__" => { - meth.sq_repeat = py_ssizearg_func!( - PySequenceProtocol, T::__repeat__, PyObjectCallbackConverter); - }, - &"__contains__" => { - meth.sq_contains = py_objobj_proc!( - PySequenceProtocol, T::__contains__, BoolConverter); - }, - &"__concat__" => { - meth.sq_concat = py_binary_func!( - PySequenceProtocol, T::__concat__, PyObjectCallbackConverter); - }, - &"__inplace_concat__" => { - meth.sq_inplace_concat = py_binary_func!( - PySequenceProtocol, T::__inplace_concat__, PyObjectCallbackConverter); - }, - &"__inplace_repeat__" => { - meth.sq_inplace_repeat = py_ssizearg_func!( - PySequenceProtocol, T::__inplace_repeat__, PyObjectCallbackConverter); - }, - _ => unreachable!(), - } - } +trait PySequenceGetItemProtocolImpl { + fn sq_item() -> Option; +} - // always set - meth.sq_ass_item = Some(sq_ass_subscript::()); +impl PySequenceGetItemProtocolImpl for T + where T: PySequenceProtocol +{ + #[inline] + default fn sq_item() -> Option { + None + } +} - Some(meth) +impl PySequenceGetItemProtocolImpl for T + where T: PySequenceGetItemProtocol +{ + #[inline] + fn sq_item() -> Option { + py_ssizearg_func!(PySequenceGetItemProtocol, T::__getitem__, PyObjectCallbackConverter) } } +trait PySequenceSetItemProtocolImpl { + fn sq_ass_item() -> Option; +} -fn sq_ass_subscript() -> ffi::ssizeobjargproc - where T: PySequenceProtocol + PythonObject +impl PySequenceSetItemProtocolImpl for T + where T: PySequenceProtocol { - unsafe extern "C" fn wrap(slf: *mut ffi::PyObject, - key: ffi::Py_ssize_t, - value: *mut ffi::PyObject) -> c_int - where T: PySequenceProtocol + PythonObject - { - const LOCATION: &'static str = concat!(stringify!($class), ".__setitem__()"); + #[inline] + default fn sq_ass_item() -> Option { + None + } +} - handle_callback( - LOCATION, UnitCallbackConverter, |py| - { +impl PySequenceSetItemProtocolImpl for T + where T: PySequenceSetItemProtocol +{ + #[inline] + fn sq_ass_item() -> Option { + unsafe extern "C" fn wrap( + slf: *mut ffi::PyObject, + key: ffi::Py_ssize_t, + value: *mut ffi::PyObject, + ) -> c_int + where T: PySequenceSetItemProtocol + { + const LOCATION: &'static str = "foo.__setitem__()"; + ::_detail::handle_callback(LOCATION, UnitCallbackConverter, |py| { let slf = PyObject::from_borrowed_ptr(py, slf).unchecked_cast_into::(); - - // if value is none, then __delitem__ + let ret = if value.is_null() { - slf.__delitem__(py, key as isize) + slf.__setitem__(py, key as isize, None).into() } else { let value = PyObject::from_borrowed_ptr(py, value); - let ret = slf.__setitem__(py, key as isize, &value); + let ret = match value.extract(py) { + Ok(value) => slf.__setitem__(py, key as isize, Some(value)).into(), + Err(e) => Err(e), + }; PyDrop::release_ref(value, py); ret }; @@ -170,6 +200,117 @@ fn sq_ass_subscript() -> ffi::ssizeobjargproc PyDrop::release_ref(slf, py); ret }) + } + Some(wrap::) + } +} + +trait PySequenceContainsProtocolImpl { + fn sq_contains() -> Option; +} + +impl PySequenceContainsProtocolImpl for T + where T: PySequenceProtocol +{ + #[inline] + default fn sq_contains() -> Option { + None + } +} + +impl PySequenceContainsProtocolImpl for T + where T: PySequenceContainsProtocol +{ + #[inline] + fn sq_contains() -> Option { + py_objobj_proc!(PySequenceContainsProtocol, T::__contains__, BoolConverter) + } +} + +trait PySequenceConcatProtocolImpl { + fn sq_concat() -> Option; +} + +impl PySequenceConcatProtocolImpl for T + where T: PySequenceProtocol +{ + #[inline] + default fn sq_concat() -> Option { + None } - wrap:: } + +impl PySequenceConcatProtocolImpl for T + where T: PySequenceConcatProtocol +{ + #[inline] + fn sq_concat() -> Option { + py_binary_func!(PySequenceConcatProtocol, T::__concat__, PyObjectCallbackConverter) + } +} + +trait PySequenceRepeatProtocolImpl { + fn sq_repeat() -> Option; +} + +impl PySequenceRepeatProtocolImpl for T + where T: PySequenceProtocol +{ + #[inline] + default fn sq_repeat() -> Option { + None + } +} + +impl PySequenceRepeatProtocolImpl for T + where T: PySequenceRepeatProtocol +{ + #[inline] + fn sq_repeat() -> Option { + py_ssizearg_func!(PySequenceRepeatProtocol, T::__repeat__, PyObjectCallbackConverter) + } +} + +trait PySequenceInplaceConcatProtocolImpl { + fn sq_inplace_concat() -> Option; +} + +impl PySequenceInplaceConcatProtocolImpl for T + where T: PySequenceProtocol +{ + #[inline] + default fn sq_inplace_concat() -> Option { + None + } +} + +impl PySequenceInplaceConcatProtocolImpl for T + where T: PySequenceInplaceConcatProtocol +{ + #[inline] + fn sq_inplace_concat() -> Option { + py_binary_func!(PySequenceInplaceConcatProtocol, T::__inplace_concat__, PyObjectCallbackConverter) + } +} + +trait PySequenceInplaceRepeatProtocolImpl { + fn sq_inplace_repeat() -> Option; +} + +impl PySequenceInplaceRepeatProtocolImpl for T + where T: PySequenceProtocol +{ + #[inline] + default fn sq_inplace_repeat() -> Option { + None + } +} + +impl PySequenceInplaceRepeatProtocolImpl for T + where T: PySequenceInplaceRepeatProtocol +{ + #[inline] + fn sq_inplace_repeat() -> Option { + py_ssizearg_func!(PySequenceInplaceRepeatProtocol, T::__inplace_repeat__, PyObjectCallbackConverter) + } +} \ No newline at end of file