Vendor deps.

This commit is contained in:
jimmy committed 2026-09-16 20:10:35 -04:00
1 parent 294527085e
commit 91e18fde3a
1714 files changed
+556667 -7

No files matched your search

+200
View File
@@ -0,0 +1,200 @@
// TODO https://github.com/PyO3/pyo3/issues/5487
#![allow(clippy::undocumented_unsafe_blocks)]
//! Contains initialization utilities for `#[pyclass]`.
use crate::exceptions::PyTypeError;
use crate::ffi_ptr_ext::FfiPtrExt;
use crate::impl_::pyclass::PyClassBaseType;
use crate::internal::get_slot::TP_NEW;
use crate::types::{PyTuple, PyType, PyTypeMethods};
use crate::{
ffi, IntoPyObject, IntoPyObjectExt, PyClass, PyClassInitializer, PyErr, PyResult, Python,
};
use crate::{ffi::PyTypeObject, type_object::PyTypeInfo};
use core::marker::PhantomData;
/// Initializer for Python types.
///
/// This trait is used internally for distinguishing `#[pyclass]` and
/// Python native types.
pub(crate) trait PyObjectInit<T>: Sized {
/// # Safety
/// - `subtype` must be a valid pointer to a type object of T or a subclass.
unsafe fn into_new_object(
self,
py: Python<'_>,
subtype: *mut PyTypeObject,
) -> PyResult<*mut ffi::PyObject>;
}
/// Initializer for Python native types, like `PyDict`.
pub struct PyNativeTypeInitializer<T: PyTypeInfo>(pub PhantomData<T>);
impl<T: PyTypeInfo> PyObjectInit<T> for PyNativeTypeInitializer<T> {
unsafe fn into_new_object(
self,
py: Python<'_>,
subtype: *mut PyTypeObject,
) -> PyResult<*mut ffi::PyObject> {
unsafe fn inner(
py: Python<'_>,
type_ptr: *mut PyTypeObject,
subtype: *mut PyTypeObject,
) -> PyResult<*mut ffi::PyObject> {
let tp_new = unsafe {
type_ptr
.cast::<ffi::PyObject>()
.assume_borrowed_unchecked(py)
.cast_unchecked::<PyType>()
.get_slot(TP_NEW)
.ok_or_else(|| PyTypeError::new_err("base type without tp_new"))?
};
// TODO: make it possible to provide real arguments to the base tp_new
let obj =
unsafe { tp_new(subtype, PyTuple::empty(py).as_ptr(), core::ptr::null_mut()) };
if obj.is_null() {
Err(PyErr::fetch(py))
} else {
Ok(obj)
}
}
unsafe { inner(py, T::type_object_raw(py), subtype) }
}
}
pub struct TpNewValueTypeResolver<ClassT, ValueT>(TpNewTupleResolver<ClassT, ValueT>);
pub struct TpNewTupleResolver<ClassT, ValueT>(
ResolveToArbitraryObject,
PhantomData<(ClassT, ValueT)>,
);
pub struct ResolveToArbitraryObject(());
/// First step of machinery for resolving the type of `#[new]` return values, which is used to
/// implement specialization for the various cases.
///
/// Call `.resolve()` on the returned tag to get the final tag type.
///
/// This resolution step is necessary in order to encode the preference to go via `PyClassInitializer<T>`
/// for new instances of `ClassT`. Without this step, the fallback to `IntoPyObject` conflicts for
/// `ClassT` because that implementation ignores the `cls` parameter for `PyClassInit` (and would
/// therefore be incorrect when instantiating subclasses).
pub fn tp_new_resolver<ClassT, ValueT>(_: &ValueT) -> TpNewValueTypeResolver<ClassT, ValueT> {
TpNewValueTypeResolver(TpNewTupleResolver(
ResolveToArbitraryObject(()),
PhantomData,
))
}
impl<ClassT, ValueT> core::ops::Deref for TpNewValueTypeResolver<ClassT, ValueT> {
type Target = TpNewTupleResolver<ClassT, ValueT>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<ClassT, ValueT> core::ops::Deref for TpNewTupleResolver<ClassT, ValueT> {
type Target = ResolveToArbitraryObject;
fn deref(&self) -> &Self::Target {
&self.0
}
}
/// Second stage of machinery for resolving the type of `#[new]` return values. This
/// is the specialized implementation for the case where the return type should be
/// used to build a new class object (`T`, `PyClassInitializer<T>`, `(S, B)` tuples).
#[expect(private_bounds, reason = "internal trait implementation")]
impl<ClassT, ValueT> TpNewValueTypeResolver<ClassT, ValueT>
where
ClassT: PyClass,
ValueT: IntoPyClassInitializer<ClassT>,
{
pub fn resolve(&self, value: ValueT) -> PyClassInitializer<ClassT> {
value.into_pyclass_initializer()
}
}
impl<S, B> TpNewTupleResolver<S, (S, B)>
where
S: PyClass<BaseType = B>,
B: PyClass + PyClassBaseType<Initializer = PyClassInitializer<B>>,
B::BaseType: PyClassBaseType<Initializer = PyNativeTypeInitializer<B::BaseType>>,
{
#[deprecated(
since = "0.29.0",
note = "Tuple syntax for super class initialization is phased out. Use `PyClassInitializer` instead."
)]
pub fn resolve(&self, value: (S, B)) -> PyClassInitializer<S> {
value.into()
}
}
/// All other conversions fall back to IntoPyObject via the deref implementation
impl ResolveToArbitraryObject {
pub fn resolve<ValueT>(&self, value: ValueT) -> ValueT {
value
}
}
#[diagnostic::on_unimplemented(
message = "`{Self}` cannot be used as the return value for `#[new]` methods",
note = "all types which implement `IntoPyObject` are suitable return values for `#[new]` methods",
note = "`PyClassInitializer<T: PyClass>` may also be used and is necessary for `#[pyclass(extends = '...')]` types",
label = "must be a type which implements `IntoPyObject`, a `PyClassInitializer<{Self}>`, or a `Result<T>` wrapping such types"
)]
pub(crate) trait PyClassInit<'py, T> {
/// # Safety
/// - `cls` must be the type object for `T` (or a subclass)
unsafe fn init(
self,
cls: crate::Borrowed<'_, 'py, crate::types::PyType>,
) -> PyResult<crate::Bound<'py, crate::PyAny>>;
}
impl<'py, ClassT, T> PyClassInit<'py, ClassT> for T
where
T: IntoPyObject<'py>,
{
unsafe fn init(
self,
cls: crate::Borrowed<'_, 'py, crate::types::PyType>,
) -> PyResult<crate::Bound<'py, crate::PyAny>> {
self.into_bound_py_any(cls.py())
}
}
impl<'py, T> PyClassInit<'py, T> for PyClassInitializer<T>
where
T: PyClass,
{
unsafe fn init(
self,
cls: crate::Borrowed<'_, 'py, crate::types::PyType>,
) -> PyResult<crate::Bound<'py, crate::PyAny>> {
// SAFETY: caller has guaranteed that `cls` is correct object
unsafe { self.create_class_object_of_type(cls.py(), cls.as_type_ptr()) }
.map(crate::Bound::into_any)
}
}
/// Analogous to `Into<PyClassInitializer<T>>`, but just an internal equivalent
/// to avoid allowing user code to define custom return types from `#[new]`.
trait IntoPyClassInitializer<T: PyClass>: Sized {
fn into_pyclass_initializer(self) -> PyClassInitializer<T>;
}
impl<T: PyClass> IntoPyClassInitializer<T> for PyClassInitializer<T> {
fn into_pyclass_initializer(self) -> PyClassInitializer<T> {
self
}
}
impl<T> IntoPyClassInitializer<T> for T
where
T: PyClass,
T::BaseType: PyClassBaseType<Initializer = PyNativeTypeInitializer<T::BaseType>>,
{
fn into_pyclass_initializer(self) -> PyClassInitializer<T> {
self.into()
}
}