implement PyListMethods
This commit is contained in:
parent
7f626b26d4
commit
337e48328f
|
@ -32,6 +32,7 @@ pub use crate::wrap_pyfunction;
|
||||||
// pub(crate) use crate::types::bytes::PyBytesMethods;
|
// pub(crate) use crate::types::bytes::PyBytesMethods;
|
||||||
// pub(crate) use crate::types::dict::PyDictMethods;
|
// pub(crate) use crate::types::dict::PyDictMethods;
|
||||||
// pub(crate) use crate::types::float::PyFloatMethods;
|
// pub(crate) use crate::types::float::PyFloatMethods;
|
||||||
|
// pub(crate) use crate::types::list::PyListMethods;
|
||||||
// pub(crate) use crate::types::mapping::PyMappingMethods;
|
// pub(crate) use crate::types::mapping::PyMappingMethods;
|
||||||
// pub(crate) use crate::types::sequence::PySequenceMethods;
|
// pub(crate) use crate::types::sequence::PySequenceMethods;
|
||||||
// pub(crate) use crate::types::string::PyStringMethods;
|
// pub(crate) use crate::types::string::PyStringMethods;
|
||||||
|
|
|
@ -3,9 +3,13 @@ use std::iter::FusedIterator;
|
||||||
|
|
||||||
use crate::err::{self, PyResult};
|
use crate::err::{self, PyResult};
|
||||||
use crate::ffi::{self, Py_ssize_t};
|
use crate::ffi::{self, Py_ssize_t};
|
||||||
|
use crate::ffi_ptr_ext::FfiPtrExt;
|
||||||
use crate::internal_tricks::get_ssize_index;
|
use crate::internal_tricks::get_ssize_index;
|
||||||
use crate::types::{PySequence, PyTuple};
|
use crate::types::{PySequence, PyTuple};
|
||||||
use crate::{Py, PyAny, PyObject, Python, ToPyObject};
|
use crate::{Py2, PyAny, PyObject, Python, ToPyObject};
|
||||||
|
|
||||||
|
use crate::types::any::PyAnyMethods;
|
||||||
|
use crate::types::sequence::PySequenceMethods;
|
||||||
|
|
||||||
/// Represents a Python `list`.
|
/// Represents a Python `list`.
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
|
@ -15,10 +19,10 @@ pyobject_native_type_core!(PyList, pyobject_native_static_type_object!(ffi::PyLi
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub(crate) fn new_from_iter(
|
pub(crate) fn new_from_iter<'py>(
|
||||||
py: Python<'_>,
|
py: Python<'py>,
|
||||||
elements: &mut dyn ExactSizeIterator<Item = PyObject>,
|
elements: &mut dyn ExactSizeIterator<Item = PyObject>,
|
||||||
) -> Py<PyList> {
|
) -> Py2<'py, PyList> {
|
||||||
unsafe {
|
unsafe {
|
||||||
// PyList_New checks for overflow but has a bad error message, so we check ourselves
|
// PyList_New checks for overflow but has a bad error message, so we check ourselves
|
||||||
let len: Py_ssize_t = elements
|
let len: Py_ssize_t = elements
|
||||||
|
@ -28,10 +32,10 @@ pub(crate) fn new_from_iter(
|
||||||
|
|
||||||
let ptr = ffi::PyList_New(len);
|
let ptr = ffi::PyList_New(len);
|
||||||
|
|
||||||
// We create the `Py` pointer here for two reasons:
|
// We create the `Py2` pointer here for two reasons:
|
||||||
// - panics if the ptr is null
|
// - panics if the ptr is null
|
||||||
// - its Drop cleans up the list if user code or the asserts panic.
|
// - its Drop cleans up the list if user code or the asserts panic.
|
||||||
let list: Py<PyList> = Py::from_owned_ptr(py, ptr);
|
let list = ptr.assume_owned(py).downcast_into_unchecked();
|
||||||
|
|
||||||
let mut counter: Py_ssize_t = 0;
|
let mut counter: Py_ssize_t = 0;
|
||||||
|
|
||||||
|
@ -83,31 +87,22 @@ impl PyList {
|
||||||
U: ExactSizeIterator<Item = T>,
|
U: ExactSizeIterator<Item = T>,
|
||||||
{
|
{
|
||||||
let mut iter = elements.into_iter().map(|e| e.to_object(py));
|
let mut iter = elements.into_iter().map(|e| e.to_object(py));
|
||||||
let list = new_from_iter(py, &mut iter);
|
new_from_iter(py, &mut iter).into_gil_ref()
|
||||||
list.into_ref(py)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a new empty list.
|
/// Constructs a new empty list.
|
||||||
pub fn empty(py: Python<'_>) -> &PyList {
|
pub fn empty(py: Python<'_>) -> &PyList {
|
||||||
unsafe { py.from_owned_ptr::<PyList>(ffi::PyList_New(0)) }
|
unsafe { py.from_owned_ptr(ffi::PyList_New(0)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the length of the list.
|
/// Returns the length of the list.
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
unsafe {
|
Py2::borrowed_from_gil_ref(&self).len()
|
||||||
#[cfg(not(Py_LIMITED_API))]
|
|
||||||
let size = ffi::PyList_GET_SIZE(self.as_ptr());
|
|
||||||
#[cfg(Py_LIMITED_API)]
|
|
||||||
let size = ffi::PyList_Size(self.as_ptr());
|
|
||||||
|
|
||||||
// non-negative Py_ssize_t should always fit into Rust usize
|
|
||||||
size as usize
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if the list is empty.
|
/// Checks if the list is empty.
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.len() == 0
|
Py2::borrowed_from_gil_ref(&self).is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `self` cast as a `PySequence`.
|
/// Returns `self` cast as a `PySequence`.
|
||||||
|
@ -126,12 +121,9 @@ impl PyList {
|
||||||
/// });
|
/// });
|
||||||
/// ```
|
/// ```
|
||||||
pub fn get_item(&self, index: usize) -> PyResult<&PyAny> {
|
pub fn get_item(&self, index: usize) -> PyResult<&PyAny> {
|
||||||
unsafe {
|
Py2::borrowed_from_gil_ref(&self)
|
||||||
let item = ffi::PyList_GetItem(self.as_ptr(), index as Py_ssize_t);
|
.get_item(index)
|
||||||
// PyList_GetItem return borrowed ptr; must make owned for safety (see #890).
|
.map(Py2::into_gil_ref)
|
||||||
ffi::Py_XINCREF(item);
|
|
||||||
self.py().from_owned_ptr_or_err(item)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the list item at the specified index. Undefined behavior on bad index. Use with caution.
|
/// Gets the list item at the specified index. Undefined behavior on bad index. Use with caution.
|
||||||
|
@ -141,10 +133,9 @@ impl PyList {
|
||||||
/// Caller must verify that the index is within the bounds of the list.
|
/// Caller must verify that the index is within the bounds of the list.
|
||||||
#[cfg(not(Py_LIMITED_API))]
|
#[cfg(not(Py_LIMITED_API))]
|
||||||
pub unsafe fn get_item_unchecked(&self, index: usize) -> &PyAny {
|
pub unsafe fn get_item_unchecked(&self, index: usize) -> &PyAny {
|
||||||
let item = ffi::PyList_GET_ITEM(self.as_ptr(), index as Py_ssize_t);
|
Py2::borrowed_from_gil_ref(&self)
|
||||||
// PyList_GET_ITEM return borrowed ptr; must make owned for safety (see #890).
|
.get_item_unchecked(index)
|
||||||
ffi::Py_XINCREF(item);
|
.into_gil_ref()
|
||||||
self.py().from_owned_ptr(item)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Takes the slice `self[low:high]` and returns it as a new list.
|
/// Takes the slice `self[low:high]` and returns it as a new list.
|
||||||
|
@ -152,13 +143,9 @@ impl PyList {
|
||||||
/// Indices must be nonnegative, and out-of-range indices are clipped to
|
/// Indices must be nonnegative, and out-of-range indices are clipped to
|
||||||
/// `self.len()`.
|
/// `self.len()`.
|
||||||
pub fn get_slice(&self, low: usize, high: usize) -> &PyList {
|
pub fn get_slice(&self, low: usize, high: usize) -> &PyList {
|
||||||
unsafe {
|
Py2::borrowed_from_gil_ref(&self)
|
||||||
self.py().from_owned_ptr(ffi::PyList_GetSlice(
|
.get_slice(low, high)
|
||||||
self.as_ptr(),
|
.into_gil_ref()
|
||||||
get_ssize_index(low),
|
|
||||||
get_ssize_index(high),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the item at the specified index.
|
/// Sets the item at the specified index.
|
||||||
|
@ -168,13 +155,7 @@ impl PyList {
|
||||||
where
|
where
|
||||||
I: ToPyObject,
|
I: ToPyObject,
|
||||||
{
|
{
|
||||||
fn inner(list: &PyList, index: usize, item: PyObject) -> PyResult<()> {
|
Py2::borrowed_from_gil_ref(&self).set_item(index, item)
|
||||||
err::error_on_minusone(list.py(), unsafe {
|
|
||||||
ffi::PyList_SetItem(list.as_ptr(), get_ssize_index(index), item.into_ptr())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
inner(self, index, item.to_object(self.py()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deletes the `index`th element of self.
|
/// Deletes the `index`th element of self.
|
||||||
|
@ -182,7 +163,7 @@ impl PyList {
|
||||||
/// This is equivalent to the Python statement `del self[i]`.
|
/// This is equivalent to the Python statement `del self[i]`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn del_item(&self, index: usize) -> PyResult<()> {
|
pub fn del_item(&self, index: usize) -> PyResult<()> {
|
||||||
self.as_sequence().del_item(index)
|
Py2::borrowed_from_gil_ref(&self).del_item(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Assigns the sequence `seq` to the slice of `self` from `low` to `high`.
|
/// Assigns the sequence `seq` to the slice of `self` from `low` to `high`.
|
||||||
|
@ -190,6 +171,285 @@ impl PyList {
|
||||||
/// This is equivalent to the Python statement `self[low:high] = v`.
|
/// This is equivalent to the Python statement `self[low:high] = v`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_slice(&self, low: usize, high: usize, seq: &PyAny) -> PyResult<()> {
|
pub fn set_slice(&self, low: usize, high: usize, seq: &PyAny) -> PyResult<()> {
|
||||||
|
Py2::borrowed_from_gil_ref(&self).set_slice(low, high, Py2::borrowed_from_gil_ref(&seq))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deletes the slice from `low` to `high` from `self`.
|
||||||
|
///
|
||||||
|
/// This is equivalent to the Python statement `del self[low:high]`.
|
||||||
|
#[inline]
|
||||||
|
pub fn del_slice(&self, low: usize, high: usize) -> PyResult<()> {
|
||||||
|
Py2::borrowed_from_gil_ref(&self).del_slice(low, high)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Appends an item to the list.
|
||||||
|
pub fn append<I>(&self, item: I) -> PyResult<()>
|
||||||
|
where
|
||||||
|
I: ToPyObject,
|
||||||
|
{
|
||||||
|
Py2::borrowed_from_gil_ref(&self).append(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Inserts an item at the specified index.
|
||||||
|
///
|
||||||
|
/// If `index >= self.len()`, inserts at the end.
|
||||||
|
pub fn insert<I>(&self, index: usize, item: I) -> PyResult<()>
|
||||||
|
where
|
||||||
|
I: ToPyObject,
|
||||||
|
{
|
||||||
|
Py2::borrowed_from_gil_ref(&self).insert(index, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determines if self contains `value`.
|
||||||
|
///
|
||||||
|
/// This is equivalent to the Python expression `value in self`.
|
||||||
|
#[inline]
|
||||||
|
pub fn contains<V>(&self, value: V) -> PyResult<bool>
|
||||||
|
where
|
||||||
|
V: ToPyObject,
|
||||||
|
{
|
||||||
|
Py2::borrowed_from_gil_ref(&self).contains(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the first index `i` for which `self[i] == value`.
|
||||||
|
///
|
||||||
|
/// This is equivalent to the Python expression `self.index(value)`.
|
||||||
|
#[inline]
|
||||||
|
pub fn index<V>(&self, value: V) -> PyResult<usize>
|
||||||
|
where
|
||||||
|
V: ToPyObject,
|
||||||
|
{
|
||||||
|
Py2::borrowed_from_gil_ref(&self).index(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator over this list's items.
|
||||||
|
pub fn iter(&self) -> PyListIterator<'_> {
|
||||||
|
PyListIterator(Py2::borrowed_from_gil_ref(&self).iter())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sorts the list in-place. Equivalent to the Python expression `l.sort()`.
|
||||||
|
pub fn sort(&self) -> PyResult<()> {
|
||||||
|
Py2::borrowed_from_gil_ref(&self).sort()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reverses the list in-place. Equivalent to the Python expression `l.reverse()`.
|
||||||
|
pub fn reverse(&self) -> PyResult<()> {
|
||||||
|
Py2::borrowed_from_gil_ref(&self).reverse()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a new tuple containing the contents of the list; equivalent to the Python expression `tuple(list)`.
|
||||||
|
///
|
||||||
|
/// This method is equivalent to `self.as_sequence().to_tuple()` and faster than `PyTuple::new(py, this_list)`.
|
||||||
|
pub fn to_tuple(&self) -> &PyTuple {
|
||||||
|
Py2::borrowed_from_gil_ref(&self).to_tuple().into_gil_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
index_impls!(PyList, "list", PyList::len, PyList::get_slice);
|
||||||
|
|
||||||
|
/// Implementation of functionality for [`PyList`].
|
||||||
|
///
|
||||||
|
/// These methods are defined for the `Py2<'py, PyList>` smart pointer, so to use method call
|
||||||
|
/// syntax these methods are separated into a trait, because stable Rust does not yet support
|
||||||
|
/// `arbitrary_self_types`.
|
||||||
|
#[doc(alias = "PyList")]
|
||||||
|
pub(crate) trait PyListMethods<'py> {
|
||||||
|
/// Returns the length of the list.
|
||||||
|
fn len(&self) -> usize;
|
||||||
|
|
||||||
|
/// Checks if the list is empty.
|
||||||
|
fn is_empty(&self) -> bool;
|
||||||
|
|
||||||
|
/// Returns `self` cast as a `PySequence`.
|
||||||
|
fn as_sequence(&self) -> &Py2<'py, PySequence>;
|
||||||
|
|
||||||
|
/// Gets the list item at the specified index.
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// use pyo3::{prelude::*, types::PyList};
|
||||||
|
/// Python::with_gil(|py| {
|
||||||
|
/// let list = PyList::new(py, [2, 3, 5, 7]);
|
||||||
|
/// let obj = list.get_item(0);
|
||||||
|
/// assert_eq!(obj.unwrap().extract::<i32>().unwrap(), 2);
|
||||||
|
/// });
|
||||||
|
/// ```
|
||||||
|
fn get_item(&self, index: usize) -> PyResult<Py2<'py, PyAny>>;
|
||||||
|
|
||||||
|
/// Gets the list item at the specified index. Undefined behavior on bad index. Use with caution.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// Caller must verify that the index is within the bounds of the list.
|
||||||
|
#[cfg(not(Py_LIMITED_API))]
|
||||||
|
unsafe fn get_item_unchecked(&self, index: usize) -> Py2<'py, PyAny>;
|
||||||
|
|
||||||
|
/// Takes the slice `self[low:high]` and returns it as a new list.
|
||||||
|
///
|
||||||
|
/// Indices must be nonnegative, and out-of-range indices are clipped to
|
||||||
|
/// `self.len()`.
|
||||||
|
fn get_slice(&self, low: usize, high: usize) -> Py2<'py, PyList>;
|
||||||
|
|
||||||
|
/// Sets the item at the specified index.
|
||||||
|
///
|
||||||
|
/// Raises `IndexError` if the index is out of range.
|
||||||
|
fn set_item<I>(&self, index: usize, item: I) -> PyResult<()>
|
||||||
|
where
|
||||||
|
I: ToPyObject;
|
||||||
|
|
||||||
|
/// Deletes the `index`th element of self.
|
||||||
|
///
|
||||||
|
/// This is equivalent to the Python statement `del self[i]`.
|
||||||
|
fn del_item(&self, index: usize) -> PyResult<()>;
|
||||||
|
|
||||||
|
/// Assigns the sequence `seq` to the slice of `self` from `low` to `high`.
|
||||||
|
///
|
||||||
|
/// This is equivalent to the Python statement `self[low:high] = v`.
|
||||||
|
fn set_slice(&self, low: usize, high: usize, seq: &Py2<'_, PyAny>) -> PyResult<()>;
|
||||||
|
|
||||||
|
/// Deletes the slice from `low` to `high` from `self`.
|
||||||
|
///
|
||||||
|
/// This is equivalent to the Python statement `del self[low:high]`.
|
||||||
|
fn del_slice(&self, low: usize, high: usize) -> PyResult<()>;
|
||||||
|
|
||||||
|
/// Appends an item to the list.
|
||||||
|
fn append<I>(&self, item: I) -> PyResult<()>
|
||||||
|
where
|
||||||
|
I: ToPyObject;
|
||||||
|
|
||||||
|
/// Inserts an item at the specified index.
|
||||||
|
///
|
||||||
|
/// If `index >= self.len()`, inserts at the end.
|
||||||
|
fn insert<I>(&self, index: usize, item: I) -> PyResult<()>
|
||||||
|
where
|
||||||
|
I: ToPyObject;
|
||||||
|
|
||||||
|
/// Determines if self contains `value`.
|
||||||
|
///
|
||||||
|
/// This is equivalent to the Python expression `value in self`.
|
||||||
|
fn contains<V>(&self, value: V) -> PyResult<bool>
|
||||||
|
where
|
||||||
|
V: ToPyObject;
|
||||||
|
|
||||||
|
/// Returns the first index `i` for which `self[i] == value`.
|
||||||
|
///
|
||||||
|
/// This is equivalent to the Python expression `self.index(value)`.
|
||||||
|
fn index<V>(&self, value: V) -> PyResult<usize>
|
||||||
|
where
|
||||||
|
V: ToPyObject;
|
||||||
|
|
||||||
|
/// Returns an iterator over this list's items.
|
||||||
|
fn iter(&self) -> PyListIterator2<'py>;
|
||||||
|
|
||||||
|
/// Sorts the list in-place. Equivalent to the Python expression `l.sort()`.
|
||||||
|
fn sort(&self) -> PyResult<()>;
|
||||||
|
|
||||||
|
/// Reverses the list in-place. Equivalent to the Python expression `l.reverse()`.
|
||||||
|
fn reverse(&self) -> PyResult<()>;
|
||||||
|
|
||||||
|
/// Return a new tuple containing the contents of the list; equivalent to the Python expression `tuple(list)`.
|
||||||
|
///
|
||||||
|
/// This method is equivalent to `self.as_sequence().to_tuple()` and faster than `PyTuple::new(py, this_list)`.
|
||||||
|
fn to_tuple(&self) -> Py2<'py, PyTuple>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'py> PyListMethods<'py> for Py2<'py, PyList> {
|
||||||
|
/// Returns the length of the list.
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
unsafe {
|
||||||
|
#[cfg(not(Py_LIMITED_API))]
|
||||||
|
let size = ffi::PyList_GET_SIZE(self.as_ptr());
|
||||||
|
#[cfg(Py_LIMITED_API)]
|
||||||
|
let size = ffi::PyList_Size(self.as_ptr());
|
||||||
|
|
||||||
|
// non-negative Py_ssize_t should always fit into Rust usize
|
||||||
|
size as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if the list is empty.
|
||||||
|
fn is_empty(&self) -> bool {
|
||||||
|
self.len() == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `self` cast as a `PySequence`.
|
||||||
|
fn as_sequence(&self) -> &Py2<'py, PySequence> {
|
||||||
|
unsafe { self.downcast_unchecked() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the list item at the specified index.
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// use pyo3::{prelude::*, types::PyList};
|
||||||
|
/// Python::with_gil(|py| {
|
||||||
|
/// let list = PyList::new(py, [2, 3, 5, 7]);
|
||||||
|
/// let obj = list.get_item(0);
|
||||||
|
/// assert_eq!(obj.unwrap().extract::<i32>().unwrap(), 2);
|
||||||
|
/// });
|
||||||
|
/// ```
|
||||||
|
fn get_item(&self, index: usize) -> PyResult<Py2<'py, PyAny>> {
|
||||||
|
unsafe {
|
||||||
|
// PyList_GetItem return borrowed ptr; must make owned for safety (see #890).
|
||||||
|
ffi::PyList_GetItem(self.as_ptr(), index as Py_ssize_t)
|
||||||
|
.assume_borrowed_or_err(self.py())
|
||||||
|
.map(|borrowed_any| borrowed_any.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the list item at the specified index. Undefined behavior on bad index. Use with caution.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// Caller must verify that the index is within the bounds of the list.
|
||||||
|
#[cfg(not(Py_LIMITED_API))]
|
||||||
|
unsafe fn get_item_unchecked(&self, index: usize) -> Py2<'py, PyAny> {
|
||||||
|
// PyList_GET_ITEM return borrowed ptr; must make owned for safety (see #890).
|
||||||
|
ffi::PyList_GET_ITEM(self.as_ptr(), index as Py_ssize_t)
|
||||||
|
.assume_borrowed(self.py())
|
||||||
|
.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Takes the slice `self[low:high]` and returns it as a new list.
|
||||||
|
///
|
||||||
|
/// Indices must be nonnegative, and out-of-range indices are clipped to
|
||||||
|
/// `self.len()`.
|
||||||
|
fn get_slice(&self, low: usize, high: usize) -> Py2<'py, PyList> {
|
||||||
|
unsafe {
|
||||||
|
ffi::PyList_GetSlice(self.as_ptr(), get_ssize_index(low), get_ssize_index(high))
|
||||||
|
.assume_owned(self.py())
|
||||||
|
.downcast_into_unchecked()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the item at the specified index.
|
||||||
|
///
|
||||||
|
/// Raises `IndexError` if the index is out of range.
|
||||||
|
fn set_item<I>(&self, index: usize, item: I) -> PyResult<()>
|
||||||
|
where
|
||||||
|
I: ToPyObject,
|
||||||
|
{
|
||||||
|
fn inner(list: &Py2<'_, PyList>, index: usize, item: Py2<'_, PyAny>) -> PyResult<()> {
|
||||||
|
err::error_on_minusone(list.py(), unsafe {
|
||||||
|
ffi::PyList_SetItem(list.as_ptr(), get_ssize_index(index), item.into_ptr())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let py = self.py();
|
||||||
|
inner(self, index, item.to_object(py).attach_into(py))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deletes the `index`th element of self.
|
||||||
|
///
|
||||||
|
/// This is equivalent to the Python statement `del self[i]`.
|
||||||
|
#[inline]
|
||||||
|
fn del_item(&self, index: usize) -> PyResult<()> {
|
||||||
|
self.as_sequence().del_item(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Assigns the sequence `seq` to the slice of `self` from `low` to `high`.
|
||||||
|
///
|
||||||
|
/// This is equivalent to the Python statement `self[low:high] = v`.
|
||||||
|
#[inline]
|
||||||
|
fn set_slice(&self, low: usize, high: usize, seq: &Py2<'_, PyAny>) -> PyResult<()> {
|
||||||
err::error_on_minusone(self.py(), unsafe {
|
err::error_on_minusone(self.py(), unsafe {
|
||||||
ffi::PyList_SetSlice(
|
ffi::PyList_SetSlice(
|
||||||
self.as_ptr(),
|
self.as_ptr(),
|
||||||
|
@ -204,45 +464,47 @@ impl PyList {
|
||||||
///
|
///
|
||||||
/// This is equivalent to the Python statement `del self[low:high]`.
|
/// This is equivalent to the Python statement `del self[low:high]`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn del_slice(&self, low: usize, high: usize) -> PyResult<()> {
|
fn del_slice(&self, low: usize, high: usize) -> PyResult<()> {
|
||||||
self.as_sequence().del_slice(low, high)
|
self.as_sequence().del_slice(low, high)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Appends an item to the list.
|
/// Appends an item to the list.
|
||||||
pub fn append<I>(&self, item: I) -> PyResult<()>
|
fn append<I>(&self, item: I) -> PyResult<()>
|
||||||
where
|
where
|
||||||
I: ToPyObject,
|
I: ToPyObject,
|
||||||
{
|
{
|
||||||
fn inner(list: &PyList, item: PyObject) -> PyResult<()> {
|
fn inner(list: &Py2<'_, PyList>, item: Py2<'_, PyAny>) -> PyResult<()> {
|
||||||
err::error_on_minusone(list.py(), unsafe {
|
err::error_on_minusone(list.py(), unsafe {
|
||||||
ffi::PyList_Append(list.as_ptr(), item.as_ptr())
|
ffi::PyList_Append(list.as_ptr(), item.as_ptr())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
inner(self, item.to_object(self.py()))
|
let py = self.py();
|
||||||
|
inner(self, item.to_object(py).attach_into(py))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inserts an item at the specified index.
|
/// Inserts an item at the specified index.
|
||||||
///
|
///
|
||||||
/// If `index >= self.len()`, inserts at the end.
|
/// If `index >= self.len()`, inserts at the end.
|
||||||
pub fn insert<I>(&self, index: usize, item: I) -> PyResult<()>
|
fn insert<I>(&self, index: usize, item: I) -> PyResult<()>
|
||||||
where
|
where
|
||||||
I: ToPyObject,
|
I: ToPyObject,
|
||||||
{
|
{
|
||||||
fn inner(list: &PyList, index: usize, item: PyObject) -> PyResult<()> {
|
fn inner(list: &Py2<'_, PyList>, index: usize, item: Py2<'_, PyAny>) -> PyResult<()> {
|
||||||
err::error_on_minusone(list.py(), unsafe {
|
err::error_on_minusone(list.py(), unsafe {
|
||||||
ffi::PyList_Insert(list.as_ptr(), get_ssize_index(index), item.as_ptr())
|
ffi::PyList_Insert(list.as_ptr(), get_ssize_index(index), item.as_ptr())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
inner(self, index, item.to_object(self.py()))
|
let py = self.py();
|
||||||
|
inner(self, index, item.to_object(py).attach_into(py))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determines if self contains `value`.
|
/// Determines if self contains `value`.
|
||||||
///
|
///
|
||||||
/// This is equivalent to the Python expression `value in self`.
|
/// This is equivalent to the Python expression `value in self`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn contains<V>(&self, value: V) -> PyResult<bool>
|
fn contains<V>(&self, value: V) -> PyResult<bool>
|
||||||
where
|
where
|
||||||
V: ToPyObject,
|
V: ToPyObject,
|
||||||
{
|
{
|
||||||
|
@ -253,7 +515,7 @@ impl PyList {
|
||||||
///
|
///
|
||||||
/// This is equivalent to the Python expression `self.index(value)`.
|
/// This is equivalent to the Python expression `self.index(value)`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn index<V>(&self, value: V) -> PyResult<usize>
|
fn index<V>(&self, value: V) -> PyResult<usize>
|
||||||
where
|
where
|
||||||
V: ToPyObject,
|
V: ToPyObject,
|
||||||
{
|
{
|
||||||
|
@ -261,43 +523,91 @@ impl PyList {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator over this list's items.
|
/// Returns an iterator over this list's items.
|
||||||
pub fn iter(&self) -> PyListIterator<'_> {
|
fn iter(&self) -> PyListIterator2<'py> {
|
||||||
PyListIterator {
|
PyListIterator2::new(self.clone())
|
||||||
list: self,
|
|
||||||
index: 0,
|
|
||||||
length: self.len(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sorts the list in-place. Equivalent to the Python expression `l.sort()`.
|
/// Sorts the list in-place. Equivalent to the Python expression `l.sort()`.
|
||||||
pub fn sort(&self) -> PyResult<()> {
|
fn sort(&self) -> PyResult<()> {
|
||||||
err::error_on_minusone(self.py(), unsafe { ffi::PyList_Sort(self.as_ptr()) })
|
err::error_on_minusone(self.py(), unsafe { ffi::PyList_Sort(self.as_ptr()) })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reverses the list in-place. Equivalent to the Python expression `l.reverse()`.
|
/// Reverses the list in-place. Equivalent to the Python expression `l.reverse()`.
|
||||||
pub fn reverse(&self) -> PyResult<()> {
|
fn reverse(&self) -> PyResult<()> {
|
||||||
err::error_on_minusone(self.py(), unsafe { ffi::PyList_Reverse(self.as_ptr()) })
|
err::error_on_minusone(self.py(), unsafe { ffi::PyList_Reverse(self.as_ptr()) })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a new tuple containing the contents of the list; equivalent to the Python expression `tuple(list)`.
|
/// Return a new tuple containing the contents of the list; equivalent to the Python expression `tuple(list)`.
|
||||||
///
|
///
|
||||||
/// This method is equivalent to `self.as_sequence().to_tuple()` and faster than `PyTuple::new(py, this_list)`.
|
/// This method is equivalent to `self.as_sequence().to_tuple()` and faster than `PyTuple::new(py, this_list)`.
|
||||||
pub fn to_tuple(&self) -> &PyTuple {
|
fn to_tuple(&self) -> Py2<'py, PyTuple> {
|
||||||
unsafe { self.py().from_owned_ptr(ffi::PyList_AsTuple(self.as_ptr())) }
|
unsafe {
|
||||||
|
ffi::PyList_AsTuple(self.as_ptr())
|
||||||
|
.assume_owned(self.py())
|
||||||
|
.downcast_into_unchecked()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
index_impls!(PyList, "list", PyList::len, PyList::get_slice);
|
/// Used by `PyList::iter()`.
|
||||||
|
pub struct PyListIterator<'a>(PyListIterator2<'a>);
|
||||||
|
|
||||||
|
impl<'a> Iterator for PyListIterator<'a> {
|
||||||
|
type Item = &'a PyAny;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
self.0.next().map(Py2::into_gil_ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
self.0.size_hint()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DoubleEndedIterator for PyListIterator<'a> {
|
||||||
|
#[inline]
|
||||||
|
fn next_back(&mut self) -> Option<Self::Item> {
|
||||||
|
self.0.next_back().map(Py2::into_gil_ref)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ExactSizeIterator for PyListIterator<'a> {
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.0.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FusedIterator for PyListIterator<'_> {}
|
||||||
|
|
||||||
|
impl<'a> IntoIterator for &'a PyList {
|
||||||
|
type Item = &'a PyAny;
|
||||||
|
type IntoIter = PyListIterator<'a>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Used by `PyList::iter()`.
|
/// Used by `PyList::iter()`.
|
||||||
pub struct PyListIterator<'a> {
|
pub(crate) struct PyListIterator2<'py> {
|
||||||
list: &'a PyList,
|
list: Py2<'py, PyList>,
|
||||||
index: usize,
|
index: usize,
|
||||||
length: usize,
|
length: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PyListIterator<'a> {
|
impl<'py> PyListIterator2<'py> {
|
||||||
unsafe fn get_item(&self, index: usize) -> &'a PyAny {
|
fn new(list: Py2<'py, PyList>) -> Self {
|
||||||
|
let length: usize = list.len();
|
||||||
|
PyListIterator2 {
|
||||||
|
list,
|
||||||
|
index: 0,
|
||||||
|
length,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn get_item(&self, index: usize) -> Py2<'py, PyAny> {
|
||||||
#[cfg(any(Py_LIMITED_API, PyPy))]
|
#[cfg(any(Py_LIMITED_API, PyPy))]
|
||||||
let item = self.list.get_item(index).expect("list.get failed");
|
let item = self.list.get_item(index).expect("list.get failed");
|
||||||
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
|
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
|
||||||
|
@ -306,8 +616,8 @@ impl<'a> PyListIterator<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for PyListIterator<'a> {
|
impl<'py> Iterator for PyListIterator2<'py> {
|
||||||
type Item = &'a PyAny;
|
type Item = Py2<'py, PyAny>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
@ -329,7 +639,7 @@ impl<'a> Iterator for PyListIterator<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DoubleEndedIterator for PyListIterator<'a> {
|
impl DoubleEndedIterator for PyListIterator2<'_> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn next_back(&mut self) -> Option<Self::Item> {
|
fn next_back(&mut self) -> Option<Self::Item> {
|
||||||
let length = self.length.min(self.list.len());
|
let length = self.length.min(self.list.len());
|
||||||
|
@ -344,23 +654,32 @@ impl<'a> DoubleEndedIterator for PyListIterator<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ExactSizeIterator for PyListIterator<'a> {
|
impl ExactSizeIterator for PyListIterator2<'_> {
|
||||||
fn len(&self) -> usize {
|
fn len(&self) -> usize {
|
||||||
self.length.saturating_sub(self.index)
|
self.length.saturating_sub(self.index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FusedIterator for PyListIterator<'_> {}
|
impl FusedIterator for PyListIterator2<'_> {}
|
||||||
|
|
||||||
impl<'a> IntoIterator for &'a PyList {
|
impl<'a, 'py> IntoIterator for &'a Py2<'py, PyList> {
|
||||||
type Item = &'a PyAny;
|
type Item = Py2<'py, PyAny>;
|
||||||
type IntoIter = PyListIterator<'a>;
|
type IntoIter = PyListIterator2<'py>;
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
self.iter()
|
self.iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'py> IntoIterator for Py2<'py, PyList> {
|
||||||
|
type Item = Py2<'py, PyAny>;
|
||||||
|
type IntoIter = PyListIterator2<'py>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
PyListIterator2::new(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::types::{PyList, PyTuple};
|
use crate::types::{PyList, PyTuple};
|
||||||
|
|
Loading…
Reference in a new issue