Use signed size to allow negative indexing. Add more tests.

This commit is contained in:
Ewan Higgs 2015-09-04 00:52:16 +02:00
parent f90d427454
commit 809e9ab227
1 changed files with 33 additions and 31 deletions

View File

@ -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());
} }