Skip to content

Commit c50498a

Browse files
committed
PyIterator, PyMapping, PySequence: implement PyTypeInfo
Returns the collections.abc type
1 parent c585999 commit c50498a

File tree

4 files changed

+73
-76
lines changed

4 files changed

+73
-76
lines changed

src/types/iterator.rs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use crate::ffi_ptr_ext::FfiPtrExt;
22
use crate::instance::Borrowed;
33
use crate::py_result_ext::PyResultExt;
4-
use crate::{ffi, Bound, PyAny, PyErr, PyResult, PyTypeCheck};
4+
use crate::sync::PyOnceLock;
5+
use crate::types::{PyType, PyTypeMethods};
6+
use crate::{ffi, Bound, Py, PyAny, PyErr, PyResult};
57

68
/// A Python iterator object.
79
///
@@ -29,7 +31,18 @@ use crate::{ffi, Bound, PyAny, PyErr, PyResult, PyTypeCheck};
2931
/// ```
3032
#[repr(transparent)]
3133
pub struct PyIterator(PyAny);
32-
pyobject_native_type_named!(PyIterator);
34+
35+
pyobject_native_type_core!(
36+
PyIterator,
37+
|py| {
38+
static TYPE: PyOnceLock<Py<PyType>> = PyOnceLock::new();
39+
TYPE.import(py, "collections.abc", "Iterator")
40+
.unwrap()
41+
.as_type_ptr()
42+
},
43+
#module=Some("collections.abc"),
44+
#checkfunction=ffi::PyIter_Check
45+
);
3346

3447
impl PyIterator {
3548
/// Builds an iterator for an iterable Python object; the equivalent of calling `iter(obj)` in Python.
@@ -117,16 +130,6 @@ impl<'py> IntoIterator for &Bound<'py, PyIterator> {
117130
}
118131
}
119132

120-
impl PyTypeCheck for PyIterator {
121-
const NAME: &'static str = "Iterator";
122-
#[cfg(feature = "experimental-inspect")]
123-
const PYTHON_TYPE: &'static str = "collections.abc.Iterator";
124-
125-
fn type_check(object: &Bound<'_, PyAny>) -> bool {
126-
unsafe { ffi::PyIter_Check(object.as_ptr()) != 0 }
127-
}
128-
}
129-
130133
#[cfg(test)]
131134
mod tests {
132135
use super::PyIterator;

src/types/mapping.rs

Lines changed: 24 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ use crate::py_result_ext::PyResultExt;
66
use crate::sync::PyOnceLock;
77
use crate::type_object::PyTypeInfo;
88
use crate::types::any::PyAnyMethods;
9-
use crate::types::{PyAny, PyDict, PyList, PyType};
10-
use crate::{ffi, Py, PyTypeCheck, Python};
9+
use crate::types::{PyAny, PyList, PyType, PyTypeMethods};
10+
use crate::{ffi, Py, Python};
1111

1212
/// Represents a reference to a Python object supporting the mapping protocol.
1313
///
@@ -18,15 +18,35 @@ use crate::{ffi, Py, PyTypeCheck, Python};
1818
/// [`Bound<'py, PyMapping>`][Bound].
1919
#[repr(transparent)]
2020
pub struct PyMapping(PyAny);
21-
pyobject_native_type_named!(PyMapping);
21+
22+
pyobject_native_type_core!(
23+
PyMapping,
24+
|py| {
25+
static TYPE: PyOnceLock<Py<PyType>> = PyOnceLock::new();
26+
TYPE.import(py, "collections.abc", "Mapping")
27+
.unwrap()
28+
.as_type_ptr()
29+
},
30+
#module=Some("collections.abc"),
31+
#pyo3checkfunction=|object| {
32+
// Using `is_instance` for `collections.abc.Mapping` is slow, so provide
33+
// optimized case dict as a well-known mapping
34+
PyDict::is_type_of(object)
35+
|| object.is_instance(&Self::type_object(object.py()).into_any())
36+
.unwrap_or_else(|err| {
37+
err.write_unraisable(object.py(), Some(object));
38+
false
39+
})
40+
}
41+
);
2242

2343
impl PyMapping {
2444
/// Register a pyclass as a subclass of `collections.abc.Mapping` (from the Python standard
2545
/// library). This is equivalent to `collections.abc.Mapping.register(T)` in Python.
2646
/// This registration is required for a pyclass to be castable from `PyAny` to `PyMapping`.
2747
pub fn register<T: PyTypeInfo>(py: Python<'_>) -> PyResult<()> {
2848
let ty = T::type_object(py);
29-
get_mapping_abc(py)?.call_method1("register", (ty,))?;
49+
Self::type_object(py).call_method1("register", (ty,))?;
3050
Ok(())
3151
}
3252
}
@@ -160,31 +180,6 @@ impl<'py> PyMappingMethods<'py> for Bound<'py, PyMapping> {
160180
}
161181
}
162182

163-
fn get_mapping_abc(py: Python<'_>) -> PyResult<&Bound<'_, PyType>> {
164-
static MAPPING_ABC: PyOnceLock<Py<PyType>> = PyOnceLock::new();
165-
166-
MAPPING_ABC.import(py, "collections.abc", "Mapping")
167-
}
168-
169-
impl PyTypeCheck for PyMapping {
170-
const NAME: &'static str = "Mapping";
171-
#[cfg(feature = "experimental-inspect")]
172-
const PYTHON_TYPE: &'static str = "collections.abc.Mapping";
173-
174-
#[inline]
175-
fn type_check(object: &Bound<'_, PyAny>) -> bool {
176-
// Using `is_instance` for `collections.abc.Mapping` is slow, so provide
177-
// optimized case dict as a well-known mapping
178-
PyDict::is_type_of(object)
179-
|| get_mapping_abc(object.py())
180-
.and_then(|abc| object.is_instance(abc))
181-
.unwrap_or_else(|err| {
182-
err.write_unraisable(object.py(), Some(object));
183-
false
184-
})
185-
}
186-
}
187-
188183
#[cfg(test)]
189184
mod tests {
190185
use std::collections::HashMap;

src/types/mod.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ macro_rules! pyobject_native_static_type_object(
139139
#[doc(hidden)]
140140
#[macro_export]
141141
macro_rules! pyobject_native_type_info(
142-
($name:ty, $typeobject:expr, $module:expr $(, #checkfunction=$checkfunction:path)? $(;$generics:ident)*) => {
142+
($name:ty, $typeobject:expr, $module:expr $(, #checkfunction=$checkfunction:path)? $(, #pyo3checkfunction=$pyo3checkfunction:expr)? $(;$generics:ident)*) => {
143143
unsafe impl<$($generics,)*> $crate::type_object::PyTypeInfo for $name {
144144
const NAME: &'static str = stringify!($name);
145145
const MODULE: ::std::option::Option<&'static str> = $module;
@@ -157,6 +157,13 @@ macro_rules! pyobject_native_type_info(
157157
unsafe { $checkfunction(obj.as_ptr()) > 0 }
158158
}
159159
)?
160+
161+
$(
162+
#[inline]
163+
fn is_type_of(obj: &$crate::Bound<'_, $crate::PyAny>) -> bool {
164+
$pyo3checkfunction(obj)
165+
}
166+
)?
160167
}
161168

162169
impl $name {
@@ -174,7 +181,7 @@ macro_rules! pyobject_native_type_info(
174181
#[doc(hidden)]
175182
#[macro_export]
176183
macro_rules! pyobject_native_type_core {
177-
($name:ty, $typeobject:expr, #module=$module:expr $(, #checkfunction=$checkfunction:path)? $(;$generics:ident)*) => {
184+
($name:ty, $typeobject:expr, #module=$module:expr $(, #checkfunction=$checkfunction:path)? $(, #pyo3checkfunction=$pyo3checkfunction:expr)? $(;$generics:ident)*) => {
178185
$crate::pyobject_native_type_named!($name $(;$generics)*);
179186
$crate::pyobject_native_type_info!($name, $typeobject, $module $(, #checkfunction=$checkfunction)? $(;$generics)*);
180187
};

src/types/sequence.rs

Lines changed: 25 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,8 @@ use crate::internal_tricks::get_ssize_index;
99
use crate::py_result_ext::PyResultExt;
1010
use crate::sync::PyOnceLock;
1111
use crate::type_object::PyTypeInfo;
12-
use crate::types::{any::PyAnyMethods, PyAny, PyList, PyString, PyTuple, PyType};
13-
use crate::{
14-
ffi, Borrowed, BoundObject, FromPyObject, IntoPyObject, IntoPyObjectExt, Py, PyTypeCheck,
15-
Python,
16-
};
12+
use crate::types::{any::PyAnyMethods, PyAny, PyList, PyString, PyTuple, PyType, PyTypeMethods};
13+
use crate::{ffi, Borrowed, BoundObject, FromPyObject, IntoPyObject, IntoPyObjectExt, Py, Python};
1714

1815
/// Represents a reference to a Python object supporting the sequence protocol.
1916
///
@@ -24,15 +21,36 @@ use crate::{
2421
/// [`Bound<'py, PySequence>`][Bound].
2522
#[repr(transparent)]
2623
pub struct PySequence(PyAny);
27-
pyobject_native_type_named!(PySequence);
24+
25+
pyobject_native_type_core!(
26+
PySequence,
27+
|py| {
28+
static TYPE: PyOnceLock<Py<PyType>> = PyOnceLock::new();
29+
TYPE.import(py, "collections.abc", "Sequence")
30+
.unwrap()
31+
.as_type_ptr()
32+
},
33+
#module=Some("collections.abc"),
34+
#pyo3checkfunction=|object| {
35+
// Using `is_instance` for `collections.abc.Sequence` is slow, so provide
36+
// optimized cases for list and tuples as common well-known sequences
37+
PyList::is_type_of(object)
38+
|| PyTuple::is_type_of(object)
39+
|| object.is_instance(&Self::type_object(object.py()).into_any())
40+
.unwrap_or_else(|err| {
41+
err.write_unraisable(object.py(), Some(object));
42+
false
43+
})
44+
}
45+
);
2846

2947
impl PySequence {
3048
/// Register a pyclass as a subclass of `collections.abc.Sequence` (from the Python standard
3149
/// library). This is equivalent to `collections.abc.Sequence.register(T)` in Python.
3250
/// This registration is required for a pyclass to be castable from `PyAny` to `PySequence`.
3351
pub fn register<T: PyTypeInfo>(py: Python<'_>) -> PyResult<()> {
3452
let ty = T::type_object(py);
35-
get_sequence_abc(py)?.call_method1("register", (ty,))?;
53+
Self::type_object(py).call_method1("register", (ty,))?;
3654
Ok(())
3755
}
3856
}
@@ -372,32 +390,6 @@ where
372390
Ok(v)
373391
}
374392

375-
fn get_sequence_abc(py: Python<'_>) -> PyResult<&Bound<'_, PyType>> {
376-
static SEQUENCE_ABC: PyOnceLock<Py<PyType>> = PyOnceLock::new();
377-
378-
SEQUENCE_ABC.import(py, "collections.abc", "Sequence")
379-
}
380-
381-
impl PyTypeCheck for PySequence {
382-
const NAME: &'static str = "Sequence";
383-
#[cfg(feature = "experimental-inspect")]
384-
const PYTHON_TYPE: &'static str = "collections.abc.Sequence";
385-
386-
#[inline]
387-
fn type_check(object: &Bound<'_, PyAny>) -> bool {
388-
// Using `is_instance` for `collections.abc.Sequence` is slow, so provide
389-
// optimized cases for list and tuples as common well-known sequences
390-
PyList::is_type_of(object)
391-
|| PyTuple::is_type_of(object)
392-
|| get_sequence_abc(object.py())
393-
.and_then(|abc| object.is_instance(abc))
394-
.unwrap_or_else(|err| {
395-
err.write_unraisable(object.py(), Some(object));
396-
false
397-
})
398-
}
399-
}
400-
401393
#[cfg(test)]
402394
mod tests {
403395
use crate::types::{PyAnyMethods, PyList, PySequence, PySequenceMethods, PyTuple};

0 commit comments

Comments
 (0)