Skip to content

Commit 4a05f27

Browse files
authored
Merge pull request #1129 from alex/limit-tuples
Use CPython stable APIs for implementing tuples.
2 parents 729f2f4 + 958ce79 commit 4a05f27

File tree

1 file changed

+28
-10
lines changed

1 file changed

+28
-10
lines changed

src/types/tuple.rs

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ impl PyTuple {
4242
pub fn len(&self) -> usize {
4343
unsafe {
4444
// non-negative Py_ssize_t should always fit into Rust uint
45-
ffi::PyTuple_GET_SIZE(self.as_ptr()) as usize
45+
ffi::PyTuple_Size(self.as_ptr()) as usize
4646
}
4747
}
4848

@@ -62,8 +62,7 @@ impl PyTuple {
6262
/// Takes a slice of the tuple from `low` to the end and returns it as a new tuple.
6363
pub fn split_from(&self, low: isize) -> &PyTuple {
6464
unsafe {
65-
let ptr =
66-
ffi::PyTuple_GetSlice(self.as_ptr(), low, ffi::PyTuple_GET_SIZE(self.as_ptr()));
65+
let ptr = ffi::PyTuple_GetSlice(self.as_ptr(), low, self.len() as Py_ssize_t);
6766
self.py().from_owned_ptr(ptr)
6867
}
6968
}
@@ -75,11 +74,14 @@ impl PyTuple {
7574
assert!(index < self.len());
7675
unsafe {
7776
self.py()
78-
.from_borrowed_ptr(ffi::PyTuple_GET_ITEM(self.as_ptr(), index as Py_ssize_t))
77+
.from_borrowed_ptr(ffi::PyTuple_GetItem(self.as_ptr(), index as Py_ssize_t))
7978
}
8079
}
8180

8281
/// Returns `self` as a slice of objects.
82+
///
83+
/// Not available when compiled with Py_LIMITED_API.
84+
#[cfg(not(Py_LIMITED_API))]
8385
pub fn as_slice(&self) -> &[&PyAny] {
8486
// This is safe because &PyAny has the same memory layout as *mut ffi::PyObject,
8587
// and because tuples are immutable.
@@ -93,25 +95,27 @@ impl PyTuple {
9395
/// Returns an iterator over the tuple items.
9496
pub fn iter(&self) -> PyTupleIterator {
9597
PyTupleIterator {
96-
slice: self.as_slice(),
98+
tuple: self,
9799
index: 0,
100+
length: self.len(),
98101
}
99102
}
100103
}
101104

102105
/// Used by `PyTuple::iter()`.
103106
pub struct PyTupleIterator<'a> {
104-
slice: &'a [&'a PyAny],
107+
tuple: &'a PyTuple,
105108
index: usize,
109+
length: usize,
106110
}
107111

108112
impl<'a> Iterator for PyTupleIterator<'a> {
109113
type Item = &'a PyAny;
110114

111115
#[inline]
112116
fn next(&mut self) -> Option<&'a PyAny> {
113-
if self.index < self.slice.len() {
114-
let item = self.slice[self.index];
117+
if self.index < self.length {
118+
let item = self.tuple.get_item(self.index);
115119
self.index += 1;
116120
Some(item)
117121
} else {
@@ -172,10 +176,9 @@ macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+
172176
fn extract(obj: &'s PyAny) -> PyResult<Self>
173177
{
174178
let t = <PyTuple as PyTryFrom>::try_from(obj)?;
175-
let slice = t.as_slice();
176179
if t.len() == $length {
177180
Ok((
178-
$(slice[$n].extract::<$T>()?,)+
181+
$(t.get_item($n).extract::<$T>()?,)+
179182
))
180183
} else {
181184
Err(wrong_tuple_length(t, $length))
@@ -296,4 +299,19 @@ mod test {
296299
assert_eq!(i + 1, item.extract().unwrap());
297300
}
298301
}
302+
303+
#[test]
304+
#[cfg(not(Py_LIMITED_API))]
305+
fn test_as_slice() {
306+
let gil = Python::acquire_gil();
307+
let py = gil.python();
308+
let ob = (1, 2, 3).to_object(py);
309+
let tuple = <PyTuple as PyTryFrom>::try_from(ob.as_ref(py)).unwrap();
310+
311+
let slice = tuple.as_slice();
312+
assert_eq!(3, slice.len());
313+
assert_eq!(1, slice[0].extract().unwrap());
314+
assert_eq!(2, slice[1].extract().unwrap());
315+
assert_eq!(3, slice[2].extract().unwrap());
316+
}
299317
}

0 commit comments

Comments
 (0)