use crate::ffi_ptr_ext::FfiPtrExt;
use crate::types::any::PyAnyMethods;
use crate::types::{PyAny, PyType};
#[cfg(feature = "gil-refs")]
use crate::PyNativeType;
use crate::{ffi, Bound, Python};
pub unsafe trait PyLayout<T> {}
pub trait PySizedLayout<T>: PyLayout<T> + Sized {}
#[cfg(feature = "gil-refs")]
pub unsafe trait HasPyGilRef {
type AsRefTarget: PyNativeType;
}
#[cfg(feature = "gil-refs")]
unsafe impl<T> HasPyGilRef for T
where
T: PyNativeType,
{
type AsRefTarget = Self;
}
#[cfg(feature = "gil-refs")]
pub unsafe trait PyTypeInfo: Sized + HasPyGilRef {
const NAME: &'static str;
const MODULE: Option<&'static str>;
fn type_object_raw(py: Python<'_>) -> *mut ffi::PyTypeObject;
#[inline]
#[cfg(feature = "gil-refs")]
#[deprecated(
since = "0.21.0",
note = "`PyTypeInfo::type_object` will be replaced by `PyTypeInfo::type_object_bound` in a future PyO3 version"
)]
fn type_object(py: Python<'_>) -> &PyType {
#[allow(deprecated)]
unsafe {
py.from_borrowed_ptr(Self::type_object_raw(py) as _)
}
}
#[inline]
fn type_object_bound(py: Python<'_>) -> Bound<'_, PyType> {
unsafe {
Self::type_object_raw(py)
.cast::<ffi::PyObject>()
.assume_borrowed_unchecked(py)
.to_owned()
.downcast_into_unchecked()
}
}
#[inline]
#[cfg(feature = "gil-refs")]
#[deprecated(
since = "0.21.0",
note = "`PyTypeInfo::is_type_of` will be replaced by `PyTypeInfo::is_type_of_bound` in a future PyO3 version"
)]
fn is_type_of(object: &PyAny) -> bool {
Self::is_type_of_bound(&object.as_borrowed())
}
#[inline]
fn is_type_of_bound(object: &Bound<'_, PyAny>) -> bool {
unsafe { ffi::PyObject_TypeCheck(object.as_ptr(), Self::type_object_raw(object.py())) != 0 }
}
#[inline]
#[cfg(feature = "gil-refs")]
#[deprecated(
since = "0.21.0",
note = "`PyTypeInfo::is_exact_type_of` will be replaced by `PyTypeInfo::is_exact_type_of_bound` in a future PyO3 version"
)]
fn is_exact_type_of(object: &PyAny) -> bool {
Self::is_exact_type_of_bound(&object.as_borrowed())
}
#[inline]
fn is_exact_type_of_bound(object: &Bound<'_, PyAny>) -> bool {
unsafe { ffi::Py_TYPE(object.as_ptr()) == Self::type_object_raw(object.py()) }
}
}
#[cfg(not(feature = "gil-refs"))]
pub unsafe trait PyTypeInfo: Sized {
const NAME: &'static str;
const MODULE: Option<&'static str>;
fn type_object_raw(py: Python<'_>) -> *mut ffi::PyTypeObject;
#[inline]
fn type_object_bound(py: Python<'_>) -> Bound<'_, PyType> {
unsafe {
Self::type_object_raw(py)
.cast::<ffi::PyObject>()
.assume_borrowed_unchecked(py)
.to_owned()
.downcast_into_unchecked()
}
}
#[inline]
fn is_type_of_bound(object: &Bound<'_, PyAny>) -> bool {
unsafe { ffi::PyObject_TypeCheck(object.as_ptr(), Self::type_object_raw(object.py())) != 0 }
}
#[inline]
fn is_exact_type_of_bound(object: &Bound<'_, PyAny>) -> bool {
unsafe { ffi::Py_TYPE(object.as_ptr()) == Self::type_object_raw(object.py()) }
}
}
#[cfg(feature = "gil-refs")]
pub trait PyTypeCheck: HasPyGilRef {
const NAME: &'static str;
fn type_check(object: &Bound<'_, PyAny>) -> bool;
}
#[cfg(not(feature = "gil-refs"))]
pub trait PyTypeCheck {
const NAME: &'static str;
fn type_check(object: &Bound<'_, PyAny>) -> bool;
}
impl<T> PyTypeCheck for T
where
T: PyTypeInfo,
{
const NAME: &'static str = <T as PyTypeInfo>::NAME;
#[inline]
fn type_check(object: &Bound<'_, PyAny>) -> bool {
T::is_type_of_bound(object)
}
}
#[inline]
pub(crate) unsafe fn get_tp_alloc(tp: *mut ffi::PyTypeObject) -> Option<ffi::allocfunc> {
#[cfg(not(Py_LIMITED_API))]
{
(*tp).tp_alloc
}
#[cfg(Py_LIMITED_API)]
{
let ptr = ffi::PyType_GetSlot(tp, ffi::Py_tp_alloc);
std::mem::transmute(ptr)
}
}
#[inline]
pub(crate) unsafe fn get_tp_free(tp: *mut ffi::PyTypeObject) -> ffi::freefunc {
#[cfg(not(Py_LIMITED_API))]
{
(*tp).tp_free.unwrap()
}
#[cfg(Py_LIMITED_API)]
{
let ptr = ffi::PyType_GetSlot(tp, ffi::Py_tp_free);
debug_assert_ne!(ptr, std::ptr::null_mut());
std::mem::transmute(ptr)
}
}