Merge pull request #624 from kngwyu/seq-setitem
Fix PySequenceProtocol::set_item
This commit is contained in:
commit
f6f607ef68
|
@ -212,60 +212,6 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait PySequenceSetItemProtocolImpl {
|
|
||||||
fn sq_ass_item() -> Option<ffi::ssizeobjargproc>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'p, T> PySequenceSetItemProtocolImpl for T
|
|
||||||
where
|
|
||||||
T: PySequenceProtocol<'p>,
|
|
||||||
{
|
|
||||||
default fn sq_ass_item() -> Option<ffi::ssizeobjargproc> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> PySequenceSetItemProtocolImpl for T
|
|
||||||
where
|
|
||||||
T: for<'p> PySequenceSetItemProtocol<'p>,
|
|
||||||
{
|
|
||||||
fn sq_ass_item() -> Option<ffi::ssizeobjargproc> {
|
|
||||||
unsafe extern "C" fn wrap<T>(
|
|
||||||
slf: *mut ffi::PyObject,
|
|
||||||
key: ffi::Py_ssize_t,
|
|
||||||
value: *mut ffi::PyObject,
|
|
||||||
) -> c_int
|
|
||||||
where
|
|
||||||
T: for<'p> PySequenceSetItemProtocol<'p>,
|
|
||||||
{
|
|
||||||
let py = Python::assume_gil_acquired();
|
|
||||||
let _pool = crate::GILPool::new(py);
|
|
||||||
let slf = py.mut_from_borrowed_ptr::<T>(slf);
|
|
||||||
|
|
||||||
let result = if value.is_null() {
|
|
||||||
Err(PyErr::new::<exceptions::NotImplementedError, _>(format!(
|
|
||||||
"Item deletion not supported by {:?}",
|
|
||||||
stringify!(T)
|
|
||||||
)))
|
|
||||||
} else {
|
|
||||||
let value = py.from_borrowed_ptr::<PyAny>(value);
|
|
||||||
match value.extract() {
|
|
||||||
Ok(value) => slf.__setitem__(key.into(), value).into(),
|
|
||||||
Err(e) => Err(e),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
match result {
|
|
||||||
Ok(_) => 0,
|
|
||||||
Err(e) => {
|
|
||||||
e.restore(py);
|
|
||||||
-1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(wrap::<T>)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// It can be possible to delete and set items (PySequenceSetItemProtocol and
|
/// It can be possible to delete and set items (PySequenceSetItemProtocol and
|
||||||
/// PySequenceDelItemProtocol implemented), only to delete (PySequenceDelItemProtocol implemented)
|
/// PySequenceDelItemProtocol implemented), only to delete (PySequenceDelItemProtocol implemented)
|
||||||
/// or no deleting or setting is possible
|
/// or no deleting or setting is possible
|
||||||
|
@ -286,11 +232,68 @@ mod sq_ass_item_impl {
|
||||||
Some(del_set_item)
|
Some(del_set_item)
|
||||||
} else if let Some(del_item) = T::del_item() {
|
} else if let Some(del_item) = T::del_item() {
|
||||||
Some(del_item)
|
Some(del_item)
|
||||||
|
} else if let Some(set_item) = T::set_item() {
|
||||||
|
Some(set_item)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait SetItem {
|
||||||
|
fn set_item() -> Option<ffi::ssizeobjargproc>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'p, T> SetItem for T
|
||||||
|
where
|
||||||
|
T: PySequenceProtocol<'p>,
|
||||||
|
{
|
||||||
|
default fn set_item() -> Option<ffi::ssizeobjargproc> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> SetItem for T
|
||||||
|
where
|
||||||
|
T: for<'p> PySequenceSetItemProtocol<'p>,
|
||||||
|
{
|
||||||
|
fn set_item() -> Option<ffi::ssizeobjargproc> {
|
||||||
|
unsafe extern "C" fn wrap<T>(
|
||||||
|
slf: *mut ffi::PyObject,
|
||||||
|
key: ffi::Py_ssize_t,
|
||||||
|
value: *mut ffi::PyObject,
|
||||||
|
) -> c_int
|
||||||
|
where
|
||||||
|
T: for<'p> PySequenceSetItemProtocol<'p>,
|
||||||
|
{
|
||||||
|
let py = Python::assume_gil_acquired();
|
||||||
|
let _pool = crate::GILPool::new(py);
|
||||||
|
let slf = py.mut_from_borrowed_ptr::<T>(slf);
|
||||||
|
|
||||||
|
let result = if value.is_null() {
|
||||||
|
Err(PyErr::new::<exceptions::NotImplementedError, _>(format!(
|
||||||
|
"Item deletion is not supported by {:?}",
|
||||||
|
stringify!(T)
|
||||||
|
)))
|
||||||
|
} else {
|
||||||
|
let value = py.from_borrowed_ptr::<PyAny>(value);
|
||||||
|
match value.extract() {
|
||||||
|
Ok(value) => slf.__setitem__(key.into(), value).into(),
|
||||||
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(_) => 0,
|
||||||
|
Err(e) => {
|
||||||
|
e.restore(py);
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(wrap::<T>)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
trait DelItem {
|
trait DelItem {
|
||||||
fn del_item() -> Option<ffi::ssizeobjargproc>;
|
fn del_item() -> Option<ffi::ssizeobjargproc>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ use pyo3::prelude::*;
|
||||||
use pyo3::py_run;
|
use pyo3::py_run;
|
||||||
use pyo3::types::{IntoPyDict, PyAny, PyBytes, PySlice, PyType};
|
use pyo3::types::{IntoPyDict, PyAny, PyBytes, PySlice, PyType};
|
||||||
use pyo3::AsPyPointer;
|
use pyo3::AsPyPointer;
|
||||||
|
use std::convert::TryFrom;
|
||||||
use std::{isize, iter};
|
use std::{isize, iter};
|
||||||
|
|
||||||
mod common;
|
mod common;
|
||||||
|
@ -147,20 +148,44 @@ fn comparisons() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
struct Sequence {}
|
#[derive(Debug)]
|
||||||
|
struct Sequence {
|
||||||
|
fields: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Sequence {
|
||||||
|
fn default() -> Sequence {
|
||||||
|
let mut fields = vec![];
|
||||||
|
for s in &["A", "B", "C", "D", "E", "F", "G"] {
|
||||||
|
fields.push(s.to_string());
|
||||||
|
}
|
||||||
|
Sequence { fields }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[pyproto]
|
#[pyproto]
|
||||||
impl PySequenceProtocol for Sequence {
|
impl PySequenceProtocol for Sequence {
|
||||||
fn __len__(&self) -> PyResult<usize> {
|
fn __len__(&self) -> PyResult<usize> {
|
||||||
Ok(5)
|
Ok(self.fields.len())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __getitem__(&self, key: isize) -> PyResult<usize> {
|
fn __getitem__(&self, key: isize) -> PyResult<String> {
|
||||||
let idx: usize = std::convert::TryFrom::try_from(key)?;
|
let idx = usize::try_from(key)?;
|
||||||
if idx == 5 {
|
if let Some(s) = self.fields.get(idx) {
|
||||||
return Err(PyErr::new::<IndexError, _>(()));
|
Ok(s.clone())
|
||||||
|
} else {
|
||||||
|
Err(PyErr::new::<IndexError, _>(()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn __setitem__(&mut self, idx: isize, value: String) -> PyResult<()> {
|
||||||
|
let idx = usize::try_from(idx)?;
|
||||||
|
if let Some(elem) = self.fields.get_mut(idx) {
|
||||||
|
*elem = value;
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(PyErr::new::<IndexError, _>(()))
|
||||||
}
|
}
|
||||||
Ok(idx)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,9 +194,17 @@ fn sequence() {
|
||||||
let gil = Python::acquire_gil();
|
let gil = Python::acquire_gil();
|
||||||
let py = gil.python();
|
let py = gil.python();
|
||||||
|
|
||||||
let c = Py::new(py, Sequence {}).unwrap();
|
let c = Py::new(py, Sequence::default()).unwrap();
|
||||||
py_assert!(py, c, "list(c) == [0, 1, 2, 3, 4]");
|
py_assert!(py, c, "list(c) == ['A', 'B', 'C', 'D', 'E', 'F', 'G']");
|
||||||
py_assert!(py, c, "c[-1] == 4");
|
py_assert!(py, c, "c[-1] == 'G'");
|
||||||
|
py_run!(
|
||||||
|
py,
|
||||||
|
c,
|
||||||
|
r#"
|
||||||
|
c[0] = 'H'
|
||||||
|
assert c[0] == 'H'
|
||||||
|
"#
|
||||||
|
);
|
||||||
py_expect_exception!(py, c, "c['abc']", TypeError);
|
py_expect_exception!(py, c, "c['abc']", TypeError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue