Merge pull request #3678 from davidhewitt/mapping2

implement `PyMappingMethods`
This commit is contained in:
Adam Reichold 2023-12-21 09:47:35 +00:00 committed by GitHub
commit 7f626b26d4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 152 additions and 21 deletions

View file

@ -32,5 +32,6 @@ pub use crate::wrap_pyfunction;
// pub(crate) use crate::types::bytes::PyBytesMethods;
// pub(crate) use crate::types::dict::PyDictMethods;
// pub(crate) use crate::types::float::PyFloatMethods;
// pub(crate) use crate::types::mapping::PyMappingMethods;
// pub(crate) use crate::types::sequence::PySequenceMethods;
// pub(crate) use crate::types::string::PyStringMethods;

View file

@ -1,6 +1,10 @@
use crate::err::{PyDowncastError, PyResult};
use crate::ffi_ptr_ext::FfiPtrExt;
use crate::instance::Py2;
use crate::py_result_ext::PyResultExt;
use crate::sync::GILOnceCell;
use crate::type_object::PyTypeInfo;
use crate::types::any::PyAnyMethods;
use crate::types::{PyAny, PyDict, PySequence, PyType};
use crate::{ffi, Py, PyNativeType, PyTypeCheck, Python, ToPyObject};
@ -16,15 +20,13 @@ impl PyMapping {
/// This is equivalent to the Python expression `len(self)`.
#[inline]
pub fn len(&self) -> PyResult<usize> {
let v = unsafe { ffi::PyMapping_Size(self.as_ptr()) };
crate::err::error_on_minusone(self.py(), v)?;
Ok(v as usize)
Py2::borrowed_from_gil_ref(&self).len()
}
/// Returns whether the mapping is empty.
#[inline]
pub fn is_empty(&self) -> PyResult<bool> {
self.len().map(|l| l == 0)
Py2::borrowed_from_gil_ref(&self).is_empty()
}
/// Determines if the mapping contains the specified key.
@ -34,7 +36,7 @@ impl PyMapping {
where
K: ToPyObject,
{
PyAny::contains(self, key)
Py2::borrowed_from_gil_ref(&self).contains(key)
}
/// Gets the item in self with key `key`.
@ -47,7 +49,9 @@ impl PyMapping {
where
K: ToPyObject,
{
PyAny::get_item(self, key)
Py2::borrowed_from_gil_ref(&self)
.get_item(key)
.map(Py2::into_gil_ref)
}
/// Sets the item in self with key `key`.
@ -59,7 +63,7 @@ impl PyMapping {
K: ToPyObject,
V: ToPyObject,
{
PyAny::set_item(self, key, value)
Py2::borrowed_from_gil_ref(&self).set_item(key, value)
}
/// Deletes the item with key `key`.
@ -70,34 +74,31 @@ impl PyMapping {
where
K: ToPyObject,
{
PyAny::del_item(self, key)
Py2::borrowed_from_gil_ref(&self).del_item(key)
}
/// Returns a sequence containing all keys in the mapping.
#[inline]
pub fn keys(&self) -> PyResult<&PySequence> {
unsafe {
self.py()
.from_owned_ptr_or_err(ffi::PyMapping_Keys(self.as_ptr()))
}
Py2::borrowed_from_gil_ref(&self)
.keys()
.map(Py2::into_gil_ref)
}
/// Returns a sequence containing all values in the mapping.
#[inline]
pub fn values(&self) -> PyResult<&PySequence> {
unsafe {
self.py()
.from_owned_ptr_or_err(ffi::PyMapping_Values(self.as_ptr()))
}
Py2::borrowed_from_gil_ref(&self)
.values()
.map(Py2::into_gil_ref)
}
/// Returns a sequence of tuples of all (key, value) pairs in the mapping.
#[inline]
pub fn items(&self) -> PyResult<&PySequence> {
unsafe {
self.py()
.from_owned_ptr_or_err(ffi::PyMapping_Items(self.as_ptr()))
}
Py2::borrowed_from_gil_ref(&self)
.items()
.map(Py2::into_gil_ref)
}
/// Register a pyclass as a subclass of `collections.abc.Mapping` (from the Python standard
@ -110,6 +111,135 @@ impl PyMapping {
}
}
/// Implementation of functionality for [`PyMapping`].
///
/// These methods are defined for the `Py2<'py, PyMapping>` 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 = "PyMapping")]
pub(crate) trait PyMappingMethods<'py> {
/// Returns the number of objects in the mapping.
///
/// This is equivalent to the Python expression `len(self)`.
fn len(&self) -> PyResult<usize>;
/// Returns whether the mapping is empty.
fn is_empty(&self) -> PyResult<bool>;
/// Determines if the mapping contains the specified key.
///
/// This is equivalent to the Python expression `key in self`.
fn contains<K>(&self, key: K) -> PyResult<bool>
where
K: ToPyObject;
/// Gets the item in self with key `key`.
///
/// Returns an `Err` if the item with specified key is not found, usually `KeyError`.
///
/// This is equivalent to the Python expression `self[key]`.
fn get_item<K>(&self, key: K) -> PyResult<Py2<'py, PyAny>>
where
K: ToPyObject;
/// Sets the item in self with key `key`.
///
/// This is equivalent to the Python expression `self[key] = value`.
fn set_item<K, V>(&self, key: K, value: V) -> PyResult<()>
where
K: ToPyObject,
V: ToPyObject;
/// Deletes the item with key `key`.
///
/// This is equivalent to the Python statement `del self[key]`.
fn del_item<K>(&self, key: K) -> PyResult<()>
where
K: ToPyObject;
/// Returns a sequence containing all keys in the mapping.
fn keys(&self) -> PyResult<Py2<'py, PySequence>>;
/// Returns a sequence containing all values in the mapping.
fn values(&self) -> PyResult<Py2<'py, PySequence>>;
/// Returns a sequence of tuples of all (key, value) pairs in the mapping.
fn items(&self) -> PyResult<Py2<'py, PySequence>>;
}
impl<'py> PyMappingMethods<'py> for Py2<'py, PyMapping> {
#[inline]
fn len(&self) -> PyResult<usize> {
let v = unsafe { ffi::PyMapping_Size(self.as_ptr()) };
crate::err::error_on_minusone(self.py(), v)?;
Ok(v as usize)
}
#[inline]
fn is_empty(&self) -> PyResult<bool> {
self.len().map(|l| l == 0)
}
fn contains<K>(&self, key: K) -> PyResult<bool>
where
K: ToPyObject,
{
PyAnyMethods::contains(&**self, key)
}
#[inline]
fn get_item<K>(&self, key: K) -> PyResult<Py2<'py, PyAny>>
where
K: ToPyObject,
{
PyAnyMethods::get_item(&**self, key)
}
#[inline]
fn set_item<K, V>(&self, key: K, value: V) -> PyResult<()>
where
K: ToPyObject,
V: ToPyObject,
{
PyAnyMethods::set_item(&**self, key, value)
}
#[inline]
fn del_item<K>(&self, key: K) -> PyResult<()>
where
K: ToPyObject,
{
PyAnyMethods::del_item(&**self, key)
}
#[inline]
fn keys(&self) -> PyResult<Py2<'py, PySequence>> {
unsafe {
ffi::PyMapping_Keys(self.as_ptr())
.assume_owned_or_err(self.py())
.downcast_into_unchecked()
}
}
#[inline]
fn values(&self) -> PyResult<Py2<'py, PySequence>> {
unsafe {
ffi::PyMapping_Values(self.as_ptr())
.assume_owned_or_err(self.py())
.downcast_into_unchecked()
}
}
#[inline]
fn items(&self) -> PyResult<Py2<'py, PySequence>> {
unsafe {
ffi::PyMapping_Items(self.as_ptr())
.assume_owned_or_err(self.py())
.downcast_into_unchecked()
}
}
}
static MAPPING_ABC: GILOnceCell<Py<PyType>> = GILOnceCell::new();
fn get_mapping_abc(py: Python<'_>) -> PyResult<&PyType> {

View file

@ -290,7 +290,7 @@ mod frozenset;
mod function;
mod iterator;
pub(crate) mod list;
mod mapping;
pub(crate) mod mapping;
mod memoryview;
mod module;
mod none;