Use signed size to allow negative indexing. Add more tests.
This commit is contained in:
parent
f90d427454
commit
809e9ab227
|
@ -28,23 +28,17 @@ pub struct PySequence<'p>(PyObject<'p>);
|
||||||
pyobject_newtype!(PySequence, PySequence_Check);
|
pyobject_newtype!(PySequence, PySequence_Check);
|
||||||
|
|
||||||
impl <'p> PySequence<'p> {
|
impl <'p> PySequence<'p> {
|
||||||
/// Returns the number of objects in sequence.
|
/// Returns the number of objects in sequence. This is equivalent to Python `size` or `length`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn size(&self) -> PyResult<'p, usize> {
|
pub fn len(&self) -> PyResult<'p, isize> {
|
||||||
let v = unsafe { ffi::PySequence_Size(self.as_ptr()) };
|
let v = unsafe { ffi::PySequence_Size(self.as_ptr()) };
|
||||||
if v == -1 {
|
if v == -1 {
|
||||||
Err(PyErr::fetch(self.python()))
|
Err(PyErr::fetch(self.python()))
|
||||||
} else {
|
} else {
|
||||||
Ok(v as usize)
|
Ok(v as isize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of objects in sequence. Same as size but included for completeness.
|
|
||||||
#[inline]
|
|
||||||
pub fn length(&self) -> PyResult<'p, usize> {
|
|
||||||
self.size()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the concatenation of o1 and o2. Equivalent to python `o1 + o2`
|
/// Return the concatenation of o1 and o2. Equivalent to python `o1 + o2`
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn concat(&self, other: &PySequence<'p>) -> PyResult<'p, PySequence> {
|
pub fn concat(&self, other: &PySequence<'p>) -> PyResult<'p, PySequence> {
|
||||||
|
@ -57,8 +51,9 @@ impl <'p> PySequence<'p> {
|
||||||
|
|
||||||
/// Return the result of repeating sequence object o count times.
|
/// Return the result of repeating sequence object o count times.
|
||||||
/// Equivalent to python `o * count`
|
/// Equivalent to python `o * count`
|
||||||
|
/// NB: Python accepts negative counts; it returns an empty Sequence.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn repeat(&self, count: usize) -> PyResult<'p, PySequence> {
|
pub fn repeat(&self, count: isize) -> PyResult<'p, PySequence> {
|
||||||
let seq = try!(unsafe {
|
let seq = try!(unsafe {
|
||||||
let py = self.python();
|
let py = self.python();
|
||||||
result_from_owned_ptr(py, ffi::PySequence_Repeat(self.as_ptr(), count as Py_ssize_t))
|
result_from_owned_ptr(py, ffi::PySequence_Repeat(self.as_ptr(), count as Py_ssize_t))
|
||||||
|
@ -78,8 +73,9 @@ impl <'p> PySequence<'p> {
|
||||||
|
|
||||||
/// Return the result of repeating sequence object o count times.
|
/// Return the result of repeating sequence object o count times.
|
||||||
/// Equivalent to python `o *= count`
|
/// Equivalent to python `o *= count`
|
||||||
|
/// NB: Python accepts negative counts; it empties the Sequence.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn in_place_repeat(&self, count: usize) -> PyResult<'p, PySequence> {
|
pub fn in_place_repeat(&self, count: isize) -> PyResult<'p, PySequence> {
|
||||||
let seq = try!(unsafe {
|
let seq = try!(unsafe {
|
||||||
let py = self.python();
|
let py = self.python();
|
||||||
result_from_owned_ptr(py,
|
result_from_owned_ptr(py,
|
||||||
|
@ -90,18 +86,19 @@ impl <'p> PySequence<'p> {
|
||||||
|
|
||||||
/// Return the ith element of the Sequence. Equivalent to python `o[index]`
|
/// Return the ith element of the Sequence. Equivalent to python `o[index]`
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_item(&self, index: usize) -> PyObject<'p> {
|
pub fn get_item(&self, index: isize) -> PyObject<'p> {
|
||||||
assert!(index < self.length().unwrap());
|
assert!(index < self.len().unwrap());
|
||||||
unsafe {
|
unsafe {
|
||||||
let py = self.python();
|
let py = self.python();
|
||||||
PyObject::from_borrowed_ptr(py, ffi::PySequence_GetItem(self.as_ptr(), index as Py_ssize_t))
|
PyObject::from_owned_ptr(py,
|
||||||
|
ffi::PySequence_GetItem(self.as_ptr(), index as Py_ssize_t))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the slice of sequence object o between begin and end.
|
/// Return the slice of sequence object o between begin and end.
|
||||||
/// This is the equivalent of the Python expression `o[begin:end]`
|
/// This is the equivalent of the Python expression `o[begin:end]`
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_slice(&self, begin : usize, end : usize) -> PyResult<'p, PySequence> {
|
pub fn get_slice(&self, begin : isize, end : isize) -> PyResult<'p, PySequence> {
|
||||||
let slice = try!(unsafe {
|
let slice = try!(unsafe {
|
||||||
let py = self.python();
|
let py = self.python();
|
||||||
result_from_owned_ptr(py,
|
result_from_owned_ptr(py,
|
||||||
|
@ -113,7 +110,7 @@ impl <'p> PySequence<'p> {
|
||||||
/// Assign object v to the ith element of o.
|
/// Assign object v to the ith element of o.
|
||||||
/// Equivalent to Python statement `o[i] = v`
|
/// Equivalent to Python statement `o[i] = v`
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_item(&self, i: usize, v: &PyObject<'p>) -> PyResult<'p, ()> {
|
pub fn set_item(&self, i: isize, v: &PyObject<'p>) -> PyResult<'p, ()> {
|
||||||
let v = unsafe {
|
let v = unsafe {
|
||||||
ffi::PySequence_SetItem(self.as_ptr(), i as Py_ssize_t, v.as_ptr())
|
ffi::PySequence_SetItem(self.as_ptr(), i as Py_ssize_t, v.as_ptr())
|
||||||
};
|
};
|
||||||
|
@ -127,7 +124,7 @@ impl <'p> PySequence<'p> {
|
||||||
/// Delete the ith element of object o.
|
/// Delete the ith element of object o.
|
||||||
/// Python statement `del o[i]`
|
/// Python statement `del o[i]`
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn del_item(&self, i: usize) -> PyResult<'p, ()> {
|
pub fn del_item(&self, i: isize) -> PyResult<'p, ()> {
|
||||||
let v = unsafe { ffi::PySequence_DelItem(self.as_ptr(), i as Py_ssize_t) };
|
let v = unsafe { ffi::PySequence_DelItem(self.as_ptr(), i as Py_ssize_t) };
|
||||||
if v == -1 {
|
if v == -1 {
|
||||||
Err(PyErr::fetch(self.python()))
|
Err(PyErr::fetch(self.python()))
|
||||||
|
@ -139,7 +136,7 @@ impl <'p> PySequence<'p> {
|
||||||
/// Assign the sequence object v to the slice in sequence object o from i1 to i2.
|
/// Assign the sequence object v to the slice in sequence object o from i1 to i2.
|
||||||
/// This is the equivalent of the Python statement `o[i1:i2] = v`
|
/// This is the equivalent of the Python statement `o[i1:i2] = v`
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_slice(&self, i1: usize, i2: usize, v: &PyObject<'p>) -> PyResult<'p, ()> {
|
pub fn set_slice(&self, i1: isize, i2: isize, v: &PyObject<'p>) -> PyResult<'p, ()> {
|
||||||
let v = unsafe {
|
let v = unsafe {
|
||||||
ffi::PySequence_SetSlice(self.as_ptr(), i1 as Py_ssize_t, i2 as Py_ssize_t, v.as_ptr())
|
ffi::PySequence_SetSlice(self.as_ptr(), i1 as Py_ssize_t, i2 as Py_ssize_t, v.as_ptr())
|
||||||
};
|
};
|
||||||
|
@ -153,8 +150,10 @@ impl <'p> PySequence<'p> {
|
||||||
/// Delete the slice in sequence object o from i1 to i2.
|
/// Delete the slice in sequence object o from i1 to i2.
|
||||||
/// equivalent of the Python statement `del o[i1:i2]`
|
/// equivalent of the Python statement `del o[i1:i2]`
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn del_slice(&self, i1: i64, i2: i64) -> PyResult<'p, ()> {
|
pub fn del_slice(&self, i1: isize, i2: isize) -> PyResult<'p, ()> {
|
||||||
let v = unsafe { ffi::PySequence_DelSlice(self.as_ptr(), i1, i2) };
|
let v = unsafe {
|
||||||
|
ffi::PySequence_DelSlice(self.as_ptr(), i1 as Py_ssize_t, i2 as Py_ssize_t)
|
||||||
|
};
|
||||||
if v == -1 {
|
if v == -1 {
|
||||||
Err(PyErr::fetch(self.python()))
|
Err(PyErr::fetch(self.python()))
|
||||||
} else {
|
} else {
|
||||||
|
@ -220,7 +219,7 @@ impl <'p> PySequence<'p> {
|
||||||
|
|
||||||
pub struct PySequenceIterator<'p> {
|
pub struct PySequenceIterator<'p> {
|
||||||
sequence : PySequence<'p>,
|
sequence : PySequence<'p>,
|
||||||
index : usize
|
index : isize
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'p> IntoIterator for PySequence<'p> {
|
impl <'p> IntoIterator for PySequence<'p> {
|
||||||
|
@ -248,9 +247,9 @@ impl <'p> Iterator for PySequenceIterator<'p> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn next(&mut self) -> Option<PyObject<'p>> {
|
fn next(&mut self) -> Option<PyObject<'p>> {
|
||||||
// can't report any errors in underlying size check so we panic.
|
// can't report any errors in underlying size check so we panic.
|
||||||
let len = self.sequence.length().unwrap();
|
let len = self.sequence.len().unwrap();
|
||||||
if self.index < len {
|
if self.index < len {
|
||||||
let item = self.sequence.get_item(self.index) ;
|
let item = self.sequence.get_item(self.index);
|
||||||
self.index += 1;
|
self.index += 1;
|
||||||
Some(item)
|
Some(item)
|
||||||
} else {
|
} else {
|
||||||
|
@ -287,8 +286,7 @@ mod test {
|
||||||
let py = gil.python();
|
let py = gil.python();
|
||||||
let v : Vec<i32> = vec![];
|
let v : Vec<i32> = vec![];
|
||||||
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>().unwrap();
|
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>().unwrap();
|
||||||
assert_eq!(0, seq.length().unwrap());
|
assert_eq!(0, seq.len().unwrap());
|
||||||
assert_eq!(0, seq.size().unwrap());
|
|
||||||
|
|
||||||
let needle = 7i32.to_py_object(py).into_object();
|
let needle = 7i32.to_py_object(py).into_object();
|
||||||
assert_eq!(false, seq.contains(&needle).unwrap());
|
assert_eq!(false, seq.contains(&needle).unwrap());
|
||||||
|
@ -300,8 +298,7 @@ mod test {
|
||||||
let py = gil.python();
|
let py = gil.python();
|
||||||
let v : Vec<i32> = vec![1, 1, 2, 3, 5, 8];
|
let v : Vec<i32> = vec![1, 1, 2, 3, 5, 8];
|
||||||
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>().unwrap();
|
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>().unwrap();
|
||||||
assert_eq!(6, seq.length().unwrap());
|
assert_eq!(6, seq.len().unwrap());
|
||||||
assert_eq!(6, seq.size().unwrap());
|
|
||||||
|
|
||||||
let bad_needle = 7i32.to_py_object(py).into_object();
|
let bad_needle = 7i32.to_py_object(py).into_object();
|
||||||
assert_eq!(false, seq.contains(&bad_needle).unwrap());
|
assert_eq!(false, seq.contains(&bad_needle).unwrap());
|
||||||
|
@ -325,6 +322,11 @@ mod test {
|
||||||
assert_eq!(3, seq.get_item(3).extract::<i32>().unwrap());
|
assert_eq!(3, seq.get_item(3).extract::<i32>().unwrap());
|
||||||
assert_eq!(5, seq.get_item(4).extract::<i32>().unwrap());
|
assert_eq!(5, seq.get_item(4).extract::<i32>().unwrap());
|
||||||
assert_eq!(8, seq.get_item(5).extract::<i32>().unwrap());
|
assert_eq!(8, seq.get_item(5).extract::<i32>().unwrap());
|
||||||
|
assert_eq!(8, seq.get_item(-1).extract::<i32>().unwrap());
|
||||||
|
assert_eq!(5, seq.get_item(-2).extract::<i32>().unwrap());
|
||||||
|
assert_eq!(3, seq.get_item(-3).extract::<i32>().unwrap());
|
||||||
|
assert_eq!(2, seq.get_item(-4).extract::<i32>().unwrap());
|
||||||
|
assert_eq!(1, seq.get_item(-5).extract::<i32>().unwrap());
|
||||||
//assert!(seq.get_item(5).extract::<i32>().is_err()); // panics.
|
//assert!(seq.get_item(5).extract::<i32>().is_err()); // panics.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,7 +353,7 @@ mod test {
|
||||||
assert!(seq.del_item(0).is_ok());
|
assert!(seq.del_item(0).is_ok());
|
||||||
assert_eq!(8, seq.get_item(0).extract::<i32>().unwrap());
|
assert_eq!(8, seq.get_item(0).extract::<i32>().unwrap());
|
||||||
assert!(seq.del_item(0).is_ok());
|
assert!(seq.del_item(0).is_ok());
|
||||||
assert_eq!(0, seq.length().unwrap());
|
assert_eq!(0, seq.len().unwrap());
|
||||||
assert!(seq.del_item(0).is_err());
|
assert!(seq.del_item(0).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,7 +434,7 @@ mod test {
|
||||||
let v : Vec<i32> = vec![1, 2, 3];
|
let v : Vec<i32> = vec![1, 2, 3];
|
||||||
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>().unwrap();
|
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>().unwrap();
|
||||||
let concat_seq = seq.concat(&seq).unwrap();
|
let concat_seq = seq.concat(&seq).unwrap();
|
||||||
assert_eq!(6, concat_seq.length().unwrap());
|
assert_eq!(6, concat_seq.len().unwrap());
|
||||||
//let concat_v : Vec<i32> = vec![1, 2, 3, 1, 2, 3];
|
//let concat_v : Vec<i32> = vec![1, 2, 3, 1, 2, 3];
|
||||||
//assert_eq!(concat_v, concat_seq.into_object().extract::<Vec<i32>>().unwrap());
|
//assert_eq!(concat_v, concat_seq.into_object().extract::<Vec<i32>>().unwrap());
|
||||||
}
|
}
|
||||||
|
@ -444,7 +446,7 @@ mod test {
|
||||||
let v = "string";
|
let v = "string";
|
||||||
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>().unwrap();
|
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>().unwrap();
|
||||||
let concat_seq = seq.concat(&seq).unwrap();
|
let concat_seq = seq.concat(&seq).unwrap();
|
||||||
assert_eq!(12, concat_seq.length().unwrap());
|
assert_eq!(12, concat_seq.len().unwrap());
|
||||||
//let concat_v = "stringstring";
|
//let concat_v = "stringstring";
|
||||||
//assert_eq!(concat_v, concat_seq.into_object().extract::<String>().unwrap());
|
//assert_eq!(concat_v, concat_seq.into_object().extract::<String>().unwrap());
|
||||||
}
|
}
|
||||||
|
@ -456,7 +458,7 @@ mod test {
|
||||||
let v = vec!["foo", "bar"];
|
let v = vec!["foo", "bar"];
|
||||||
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>().unwrap();
|
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>().unwrap();
|
||||||
let repeat_seq = seq.repeat(3).unwrap();
|
let repeat_seq = seq.repeat(3).unwrap();
|
||||||
assert_eq!(6, repeat_seq.length().unwrap());
|
assert_eq!(6, repeat_seq.len().unwrap());
|
||||||
//let repeated = vec!["foo", "bar", "foo", "bar", "foo", "bar"];
|
//let repeated = vec!["foo", "bar", "foo", "bar", "foo", "bar"];
|
||||||
//assert_eq!(repeated, repeat_seq.into_object().extract::<Vec<String>>().unwrap());
|
//assert_eq!(repeated, repeat_seq.into_object().extract::<Vec<String>>().unwrap());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue