type_object: remove layout and base type from PyTypeInfo

This commit is contained in:
David Hewitt 2021-05-04 21:10:03 +01:00
parent 05db24ce33
commit 7536554ceb
15 changed files with 156 additions and 201 deletions

View file

@ -48,7 +48,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- `PyMethodDef_INIT` [#1426](https://github.com/PyO3/pyo3/pull/1426)
- `PyTypeObject_INIT` [#1429](https://github.com/PyO3/pyo3/pull/1429)
- `PyObject_Check`, `PySuper_Check`, and `FreeFunc` [#1438](https://github.com/PyO3/pyo3/pull/1438)
- Remove pyclass implementation details `Type`, `DESCRIPTION`, and `FLAGS` from `PyTypeInfo`. [#1456](https://github.com/PyO3/pyo3/pull/1456)
- Remove pyclass implementation details from `PyTypeInfo`:
- `Type`, `DESCRIPTION`, and `FLAGS` [#1456](https://github.com/PyO3/pyo3/pull/1456)
- `BaseType`, `BaseLayout`, `Layout`, `Initializer` [#1596](https://github.com/PyO3/pyo3/pull/1596)
- Remove `__doc__` from module's `__all__`. [#1509](https://github.com/PyO3/pyo3/pull/1509)
- Remove `PYO3_CROSS_INCLUDE_DIR` environment variable and the associated C header parsing functionality.

View file

@ -723,10 +723,6 @@ struct MyClass {
impl pyo3::pyclass::PyClassAlloc for MyClass {}
unsafe impl pyo3::PyTypeInfo for MyClass {
type BaseType = PyAny;
type BaseLayout = pyo3::pycell::PyCellBase<PyAny>;
type Layout = PyCell<Self>;
type Initializer = PyClassInitializer<Self>;
type AsRefTarget = PyCell<Self>;
const NAME: &'static str = "MyClass";
@ -757,6 +753,8 @@ impl pyo3::class::impl_::PyClassImpl for MyClass {
const IS_GC: bool = false;
const IS_BASETYPE: bool = false;
const IS_SUBCLASS: bool = false;
type Layout = PyCell<MyClass>;
type BaseType = PyAny;
type ThreadChecker = pyo3::class::impl_::ThreadCheckerStub<MyClass>;
fn for_each_method_def(visitor: impl FnMut(&pyo3::class::PyMethodDefType)) {

View file

@ -312,14 +312,14 @@ fn impl_class(
let weakref = if attr.has_weaklist {
quote! { pyo3::pyclass_slots::PyClassWeakRefSlot }
} else if attr.has_extends {
quote! { <Self::BaseType as pyo3::derive_utils::PyBaseTypeUtils>::WeakRef }
quote! { <Self::BaseType as pyo3::class::impl_::PyClassBaseType>::WeakRef }
} else {
quote! { pyo3::pyclass_slots::PyClassDummySlot }
};
let dict = if attr.has_dict {
quote! { pyo3::pyclass_slots::PyClassDictSlot }
} else if attr.has_extends {
quote! { <Self::BaseType as pyo3::derive_utils::PyBaseTypeUtils>::Dict }
quote! { <Self::BaseType as pyo3::class::impl_::PyClassBaseType>::Dict }
} else {
quote! { pyo3::pyclass_slots::PyClassDummySlot }
};
@ -358,13 +358,8 @@ fn impl_class(
};
let base = &attr.base;
let base_layout = if attr.has_extends {
quote! { <Self::BaseType as pyo3::derive_utils::PyBaseTypeUtils>::LayoutAsBase }
} else {
quote! { pyo3::pycell::PyCellBase<pyo3::PyAny> }
};
let base_nativetype = if attr.has_extends {
quote! { <Self::BaseType as pyo3::derive_utils::PyBaseTypeUtils>::BaseNativeType }
quote! { <Self::BaseType as pyo3::class::impl_::PyClassBaseType>::BaseNativeType }
} else {
quote! { pyo3::PyAny }
};
@ -386,7 +381,7 @@ fn impl_class(
quote! { pyo3::class::impl_::ThreadCheckerImpl<#cls> }
} else if attr.has_extends {
quote! {
pyo3::class::impl_::ThreadCheckerInherited<#cls, <#cls as pyo3::type_object::PyTypeInfo>::BaseType>
pyo3::class::impl_::ThreadCheckerInherited<#cls, <#cls as pyo3::class::impl_::PyClassImpl>::BaseType>
}
} else {
quote! { pyo3::class::impl_::ThreadCheckerStub<#cls> }
@ -398,10 +393,6 @@ fn impl_class(
Ok(quote! {
unsafe impl pyo3::type_object::PyTypeInfo for #cls {
type BaseType = #base;
type Layout = pyo3::PyCell<Self>;
type BaseLayout = #base_layout;
type Initializer = pyo3::pyclass_init::PyClassInitializer<Self>;
type AsRefTarget = pyo3::PyCell<Self>;
const NAME: &'static str = #cls_name;
@ -441,6 +432,8 @@ fn impl_class(
const IS_BASETYPE: bool = #is_basetype;
const IS_SUBCLASS: bool = #is_subclass;
type Layout = PyCell<Self>;
type BaseType = #base;
type ThreadChecker = #thread_checker;
fn for_each_method_def(visitor: impl FnMut(&pyo3::class::PyMethodDefType)) {

View file

@ -1,6 +1,12 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
use crate::{derive_utils::PyBaseTypeUtils, ffi, PyMethodDefType, PyNativeType};
use crate::{
ffi,
pycell::PyCellLayout,
pyclass_init::PyObjectInit,
type_object::{PyLayout, PyTypeObject},
PyClass, PyMethodDefType, PyNativeType, PyTypeInfo,
};
use std::{marker::PhantomData, thread};
/// This type is used as a "dummy" type on which dtolnay specializations are
@ -44,6 +50,12 @@ pub trait PyClassImpl: Sized {
/// #[pyclass(extends=...)]
const IS_SUBCLASS: bool = false;
/// Layout
type Layout: PyLayout<Self>;
/// Base class
type BaseType: PyTypeInfo + PyTypeObject + PyClassBaseType;
/// This handles following two situations:
/// 1. In case `T` is `Send`, stub `ThreadChecker` is used and does nothing.
/// This implementation is used by default. Compile fails if `T: !Send`.
@ -241,9 +253,9 @@ impl<T> PyClassThreadChecker<T> for ThreadCheckerImpl<T> {
/// Thread checker for types that have `Send` and `extends=...`.
/// Ensures that `T: Send` and the parent is not accessed by another thread.
#[doc(hidden)]
pub struct ThreadCheckerInherited<T: Send, U: PyBaseTypeUtils>(PhantomData<T>, U::ThreadChecker);
pub struct ThreadCheckerInherited<T: Send, U: PyClassBaseType>(PhantomData<T>, U::ThreadChecker);
impl<T: Send, U: PyBaseTypeUtils> PyClassThreadChecker<T> for ThreadCheckerInherited<T, U> {
impl<T: Send, U: PyClassBaseType> PyClassThreadChecker<T> for ThreadCheckerInherited<T, U> {
fn ensure(&self) {
self.1.ensure();
}
@ -252,3 +264,23 @@ impl<T: Send, U: PyBaseTypeUtils> PyClassThreadChecker<T> for ThreadCheckerInher
}
private_impl! {}
}
/// Trait denoting that this class is suitable to be used as a base type for PyClass.
pub trait PyClassBaseType: Sized {
type Dict;
type WeakRef;
type LayoutAsBase: PyCellLayout<Self>;
type BaseNativeType;
type ThreadChecker: PyClassThreadChecker<Self>;
type Initializer: PyObjectInit<Self>;
}
/// All PyClasses can be used as a base type.
impl<T: PyClass> PyClassBaseType for T {
type Dict = T::Dict;
type WeakRef = T::WeakRef;
type LayoutAsBase = crate::pycell::PyCellInner<T>;
type BaseNativeType = T::BaseNativeType;
type ThreadChecker = T::ThreadChecker;
type Initializer = crate::pyclass_init::PyClassInitializer<Self>;
}

View file

@ -4,7 +4,6 @@
//! Functionality for the code generated by the derive backend
use crate::class::impl_::PyClassThreadChecker;
use crate::err::{PyErr, PyResult};
use crate::exceptions::PyTypeError;
use crate::instance::PyNativeType;
@ -326,24 +325,6 @@ impl ModuleDef {
}
}
/// Utilities for basetype
#[doc(hidden)]
pub trait PyBaseTypeUtils: Sized {
type Dict;
type WeakRef;
type LayoutAsBase;
type BaseNativeType;
type ThreadChecker: PyClassThreadChecker<Self>;
}
impl<T: PyClass> PyBaseTypeUtils for T {
type Dict = T::Dict;
type WeakRef = T::WeakRef;
type LayoutAsBase = crate::pycell::PyCellInner<T>;
type BaseNativeType = T::BaseNativeType;
type ThreadChecker = T::ThreadChecker;
}
/// Utility trait to enable &PyClass as a pymethod/function argument
#[doc(hidden)]
pub trait ExtractExt<'a> {

View file

@ -3,7 +3,6 @@ use crate::conversion::{PyTryFrom, ToBorrowedObject};
use crate::err::{PyDowncastError, PyErr, PyResult};
use crate::gil;
use crate::pycell::{PyBorrowError, PyBorrowMutError, PyCell};
use crate::type_object::PyBorrowFlagLayout;
use crate::types::{PyDict, PyTuple};
use crate::{
ffi, AsPyPointer, FromPyObject, IntoPy, IntoPyPointer, PyAny, PyClass, PyClassInitializer,
@ -59,10 +58,7 @@ where
T: PyClass,
{
/// Create a new instance `Py<T>` of a `#[pyclass]` on the Python heap.
pub fn new(py: Python, value: impl Into<PyClassInitializer<T>>) -> PyResult<Py<T>>
where
T::BaseLayout: PyBorrowFlagLayout<T::BaseType>,
{
pub fn new(py: Python, value: impl Into<PyClassInitializer<T>>) -> PyResult<Py<T>> {
let initializer = value.into();
let obj = initializer.create_cell(py)?;
let ob = unsafe { Py::from_owned_ptr(py, obj as _) };

View file

@ -1,12 +1,12 @@
//! Includes `PyCell` implementation.
use crate::class::impl_::PyClassThreadChecker;
use crate::conversion::{AsPyPointer, FromPyPointer, ToPyObject};
use crate::exceptions::PyRuntimeError;
use crate::pyclass::PyClass;
use crate::pyclass_init::PyClassInitializer;
use crate::pyclass_slots::{PyClassDict, PyClassWeakRef};
use crate::type_object::{PyBorrowFlagLayout, PyLayout, PySizedLayout, PyTypeInfo};
use crate::type_object::{PyLayout, PySizedLayout};
use crate::types::PyAny;
use crate::{class::impl_::PyClassBaseType, class::impl_::PyClassThreadChecker};
use crate::{ffi, IntoPy, PyErr, PyNativeType, PyObject, PyResult, Python};
use std::cell::{Cell, UnsafeCell};
use std::fmt;
@ -17,34 +17,18 @@ use std::ops::{Deref, DerefMut};
/// This is necessary for sharing BorrowFlag between parents and children.
#[doc(hidden)]
#[repr(C)]
pub struct PyCellBase<T: PyTypeInfo> {
ob_base: T::Layout,
pub struct PyCellBase<T> {
ob_base: T,
borrow_flag: Cell<BorrowFlag>,
}
unsafe impl<T> PyLayout<T> for PyCellBase<T>
unsafe impl<T, U> PyLayout<T> for PyCellBase<U>
where
T: PyTypeInfo + PyNativeType,
T::Layout: PySizedLayout<T>,
U: PySizedLayout<T>,
{
const IS_NATIVE_TYPE: bool = true;
}
// Thes impls ensures `PyCellBase` can be a base type.
impl<T> PySizedLayout<T> for PyCellBase<T>
where
T: PyTypeInfo + PyNativeType,
T::Layout: PySizedLayout<T>,
{
}
unsafe impl<T> PyBorrowFlagLayout<T> for PyCellBase<T>
where
T: PyTypeInfo + PyNativeType,
T::Layout: PySizedLayout<T>,
{
}
/// Inner type of `PyCell` without dict slots and reference counter.
/// This struct has two usages:
/// 1. As an inner type of `PyRef` and `PyRefMut`.
@ -52,7 +36,7 @@ where
#[doc(hidden)]
#[repr(C)]
pub struct PyCellInner<T: PyClass> {
ob_base: T::BaseLayout,
ob_base: <T::BaseType as PyClassBaseType>::LayoutAsBase,
value: ManuallyDrop<UnsafeCell<T>>,
}
@ -64,9 +48,6 @@ impl<T: PyClass> AsPyPointer for PyCellInner<T> {
unsafe impl<T: PyClass> PyLayout<T> for PyCellInner<T> {
const IS_NATIVE_TYPE: bool = false;
fn get_super(&mut self) -> Option<&mut T::BaseLayout> {
Some(&mut self.ob_base)
}
fn py_init(&mut self, value: T) {
self.value = ManuallyDrop::new(UnsafeCell::new(value));
}
@ -78,20 +59,11 @@ unsafe impl<T: PyClass> PyLayout<T> for PyCellInner<T> {
// These impls ensures `PyCellInner` can be a base type.
impl<T: PyClass> PySizedLayout<T> for PyCellInner<T> {}
unsafe impl<T: PyClass> PyBorrowFlagLayout<T> for PyCellInner<T> {}
impl<T: PyClass> PyCellInner<T> {
fn get_ptr(&self) -> *mut T {
self.value.get()
}
fn get_borrow_flag(&self) -> BorrowFlag {
let base = (&self.ob_base) as *const _ as *const PyCellBase<T::BaseNativeType>;
unsafe { (*base).borrow_flag.get() }
}
fn set_borrow_flag(&self, flag: BorrowFlag) {
let base = (&self.ob_base) as *const _ as *const PyCellBase<T::BaseNativeType>;
unsafe { (*base).borrow_flag.set(flag) }
}
}
/// `PyCell` is the container type for [`PyClass`](../pyclass/trait.PyClass.html).
@ -203,10 +175,7 @@ impl<T: PyClass> PyCell<T> {
/// In cases where the value in the cell does not need to be accessed immediately after
/// creation, consider [`Py::new`](../instance/struct.Py.html#method.new) as a more efficient
/// alternative.
pub fn new(py: Python, value: impl Into<PyClassInitializer<T>>) -> PyResult<&Self>
where
T::BaseLayout: PyBorrowFlagLayout<T::BaseType>,
{
pub fn new(py: Python, value: impl Into<PyClassInitializer<T>>) -> PyResult<&Self> {
unsafe {
let initializer = value.into();
let self_ = initializer.create_cell(py)?;
@ -370,14 +339,10 @@ impl<T: PyClass> PyCell<T> {
}
/// Allocates a new PyCell given a type object `subtype`. Used by our `tp_new` implementation.
/// Requires `T::BaseLayout: PyBorrowFlagLayout<T::BaseType>` to ensure `self` has a borrow flag.
pub(crate) unsafe fn internal_new(
py: Python,
subtype: *mut ffi::PyTypeObject,
) -> PyResult<*mut Self>
where
T::BaseLayout: PyBorrowFlagLayout<T::BaseType>,
{
) -> PyResult<*mut Self> {
let base = T::new(py, subtype);
if base.is_null() {
return Err(PyErr::fetch(py));
@ -394,9 +359,6 @@ impl<T: PyClass> PyCell<T> {
unsafe impl<T: PyClass> PyLayout<T> for PyCell<T> {
const IS_NATIVE_TYPE: bool = false;
fn get_super(&mut self) -> Option<&mut T::BaseLayout> {
Some(&mut self.inner.ob_base)
}
fn py_init(&mut self, value: T) {
self.inner.value = ManuallyDrop::new(UnsafeCell::new(value));
}
@ -504,7 +466,7 @@ impl<'p, T: PyClass> PyRef<'p, T> {
impl<'p, T, U> AsRef<U> for PyRef<'p, T>
where
T: PyClass + PyTypeInfo<BaseType = U, BaseLayout = PyCellInner<U>>,
T: PyClass<BaseType = U>,
U: PyClass,
{
fn as_ref(&self) -> &T::BaseType {
@ -514,7 +476,7 @@ where
impl<'p, T, U> PyRef<'p, T>
where
T: PyClass + PyTypeInfo<BaseType = U, BaseLayout = PyCellInner<U>>,
T: PyClass<BaseType = U>,
U: PyClass,
{
/// Get `PyRef<T::BaseType>`.
@ -621,7 +583,7 @@ impl<'p, T: PyClass> PyRefMut<'p, T> {
impl<'p, T, U> AsRef<U> for PyRefMut<'p, T>
where
T: PyClass + PyTypeInfo<BaseType = U, BaseLayout = PyCellInner<U>>,
T: PyClass<BaseType = U>,
U: PyClass,
{
fn as_ref(&self) -> &T::BaseType {
@ -631,7 +593,7 @@ where
impl<'p, T, U> AsMut<U> for PyRefMut<'p, T>
where
T: PyClass + PyTypeInfo<BaseType = U, BaseLayout = PyCellInner<U>>,
T: PyClass<BaseType = U>,
U: PyClass,
{
fn as_mut(&mut self) -> &mut T::BaseType {
@ -641,7 +603,7 @@ where
impl<'p, T, U> PyRefMut<'p, T>
where
T: PyClass + PyTypeInfo<BaseType = U, BaseLayout = PyCellInner<U>>,
T: PyClass<BaseType = U>,
U: PyClass,
{
/// Get `PyRef<T::BaseType>`.
@ -702,8 +664,9 @@ impl<T: PyClass + fmt::Debug> fmt::Debug for PyRefMut<'_, T> {
}
}
#[doc(hidden)]
#[derive(Copy, Clone, Eq, PartialEq)]
struct BorrowFlag(usize);
pub struct BorrowFlag(usize);
impl BorrowFlag {
const UNUSED: BorrowFlag = BorrowFlag(0);
@ -765,3 +728,33 @@ impl From<PyBorrowMutError> for PyErr {
PyRuntimeError::new_err(other.to_string())
}
}
#[doc(hidden)]
pub trait PyCellLayout<T>: PyLayout<T> {
fn get_borrow_flag(&self) -> BorrowFlag;
fn set_borrow_flag(&self, flag: BorrowFlag);
}
impl<T, U> PyCellLayout<T> for PyCellBase<U>
where
U: PySizedLayout<T>,
{
fn get_borrow_flag(&self) -> BorrowFlag {
self.borrow_flag.get()
}
fn set_borrow_flag(&self, flag: BorrowFlag) {
self.borrow_flag.set(flag)
}
}
impl<T: PyClass> PyCellLayout<T> for PyCellInner<T>
where
<T::BaseType as PyClassBaseType>::LayoutAsBase: PyCellLayout<T::BaseType>,
{
fn get_borrow_flag(&self) -> BorrowFlag {
self.ob_base.get_borrow_flag()
}
fn set_borrow_flag(&self, flag: BorrowFlag) {
self.ob_base.set_borrow_flag(flag)
}
}

View file

@ -1,8 +1,8 @@
//! `PyClass` and related traits.
use crate::class::impl_::PyClassImpl;
use crate::class::methods::PyMethodDefType;
use crate::pyclass_slots::{PyClassDict, PyClassWeakRef};
use crate::type_object::PyLayout;
use crate::{class::impl_::PyClassBaseType, class::impl_::PyClassImpl};
use crate::{ffi, PyCell, PyErr, PyNativeType, PyResult, PyTypeInfo, Python};
use std::convert::TryInto;
use std::ffi::CString;
@ -45,7 +45,7 @@ pub(crate) unsafe fn default_new<T: PyTypeInfo + PyClassImpl>(
subtype: *mut ffi::PyTypeObject,
) -> *mut ffi::PyObject {
// if the class derives native types(e.g., PyDict), call special new
if T::IS_SUBCLASS && T::BaseLayout::IS_NATIVE_TYPE {
if T::IS_SUBCLASS && <T::BaseType as PyClassBaseType>::LayoutAsBase::IS_NATIVE_TYPE {
#[cfg(not(Py_LIMITED_API))]
{
let base_tp = T::BaseType::type_object_raw(py);
@ -137,7 +137,7 @@ pub(crate) unsafe fn tp_free_fallback(ty: *mut ffi::PyTypeObject) -> ffi::freefu
/// The `#[pyclass]` attribute automatically implements this trait for your Rust struct,
/// so you don't have to use this trait directly.
pub trait PyClass:
PyTypeInfo<Layout = PyCell<Self>, AsRefTarget = PyCell<Self>> + Sized + PyClassAlloc + PyClassImpl
PyTypeInfo<AsRefTarget = PyCell<Self>> + Sized + PyClassAlloc + PyClassImpl<Layout = PyCell<Self>>
{
/// Specify this class has `#[pyclass(dict)]` or not.
type Dict: PyClassDict;

View file

@ -1,6 +1,6 @@
//! Initialization utilities for `#[pyclass]`.
use crate::callback::IntoPyCallbackOutput;
use crate::type_object::{PyBorrowFlagLayout, PyLayout, PySizedLayout, PyTypeInfo};
use crate::type_object::{PyLayout, PyTypeInfo};
use crate::{callback::IntoPyCallbackOutput, class::impl_::PyClassBaseType};
use crate::{PyCell, PyClass, PyResult, Python};
use std::marker::PhantomData;
@ -8,7 +8,7 @@ use std::marker::PhantomData;
///
/// This trait is intended to use internally for distinguishing `#[pyclass]` and
/// Python native types.
pub trait PyObjectInit<T: PyTypeInfo>: Sized {
pub trait PyObjectInit<T>: Sized {
fn init_class<L: PyLayout<T>>(self, layout: &mut L);
private_decl! {}
}
@ -71,14 +71,14 @@ impl<T: PyTypeInfo> PyObjectInit<T> for PyNativeTypeInitializer<T> {
/// ```
pub struct PyClassInitializer<T: PyClass> {
init: T,
super_init: <T::BaseType as PyTypeInfo>::Initializer,
super_init: <T::BaseType as PyClassBaseType>::Initializer,
}
impl<T: PyClass> PyClassInitializer<T> {
/// Construct new initializer from value `T` and base class' initializer.
///
/// We recommend to mainly use `add_subclass`, instead of directly call `new`.
pub fn new(init: T, super_init: <T::BaseType as PyTypeInfo>::Initializer) -> Self {
pub fn new(init: T, super_init: <T::BaseType as PyClassBaseType>::Initializer) -> Self {
Self { init, super_init }
}
@ -113,9 +113,8 @@ impl<T: PyClass> PyClassInitializer<T> {
/// ```
pub fn add_subclass<S>(self, subclass_value: S) -> PyClassInitializer<S>
where
S: PyClass + PyTypeInfo<BaseType = T>,
S::BaseLayout: PySizedLayout<T>,
S::BaseType: PyTypeInfo<Initializer = Self>,
S: PyClass<BaseType = T>,
S::BaseType: PyClassBaseType<Initializer = Self>,
{
PyClassInitializer::new(subclass_value, self)
}
@ -125,7 +124,6 @@ impl<T: PyClass> PyClassInitializer<T> {
pub fn create_cell(self, py: Python) -> PyResult<*mut PyCell<T>>
where
T: PyClass,
T::BaseLayout: PyBorrowFlagLayout<T::BaseType>,
{
unsafe { self.create_cell_from_subtype(py, T::type_object_raw(py)) }
}
@ -143,7 +141,6 @@ impl<T: PyClass> PyClassInitializer<T> {
) -> PyResult<*mut PyCell<T>>
where
T: PyClass,
T::BaseLayout: PyBorrowFlagLayout<T::BaseType>,
{
let cell = PyCell::internal_new(py, subtype)?;
self.init_class(&mut *cell);
@ -154,10 +151,12 @@ impl<T: PyClass> PyClassInitializer<T> {
impl<T: PyClass> PyObjectInit<T> for PyClassInitializer<T> {
fn init_class<L: PyLayout<T>>(self, layout: &mut L) {
let Self { init, super_init } = self;
// Safety: A valid PyLayout must contain the base layout as the first entry, so casting L to
// T::BaseType::LayoutAsBase is ok.
super_init.init_class(unsafe {
&mut *(layout as *mut _ as *mut <T::BaseType as PyClassBaseType>::LayoutAsBase)
});
layout.py_init(init);
if let Some(super_obj) = layout.get_super() {
super_init.init_class(super_obj);
}
}
private_impl! {}
}
@ -165,7 +164,7 @@ impl<T: PyClass> PyObjectInit<T> for PyClassInitializer<T> {
impl<T> From<T> for PyClassInitializer<T>
where
T: PyClass,
T::BaseType: PyTypeInfo<Initializer = PyNativeTypeInitializer<T::BaseType>>,
T::BaseType: PyClassBaseType<Initializer = PyNativeTypeInitializer<T::BaseType>>,
{
fn from(value: T) -> PyClassInitializer<T> {
Self::new(value, PyNativeTypeInitializer(PhantomData))
@ -174,10 +173,9 @@ where
impl<S, B> From<(S, B)> for PyClassInitializer<S>
where
S: PyClass + PyTypeInfo<BaseType = B>,
S::BaseLayout: PySizedLayout<B>,
B: PyClass + PyTypeInfo<Initializer = PyClassInitializer<B>>,
B::BaseType: PyTypeInfo<Initializer = PyNativeTypeInitializer<B::BaseType>>,
S: PyClass<BaseType = B>,
B: PyClass,
B::BaseType: PyClassBaseType<Initializer = PyNativeTypeInitializer<B::BaseType>>,
{
fn from(sub_and_base: (S, B)) -> PyClassInitializer<S> {
let (sub, base) = sub_and_base;

View file

@ -1,5 +1,4 @@
use crate::type_object::PyBorrowFlagLayout;
use crate::{Py, PyClass, PyClassInitializer, PyTypeInfo, Python};
use crate::{Py, PyAny, PyClass, Python};
use serde::{de, ser, Deserialize, Deserializer, Serialize, Serializer};
impl<T> Serialize for Py<T>
@ -20,8 +19,7 @@ where
impl<'de, T> Deserialize<'de> for Py<T>
where
T: Into<PyClassInitializer<T>> + PyClass + Deserialize<'de>,
<T as PyTypeInfo>::BaseLayout: PyBorrowFlagLayout<<T as PyTypeInfo>::BaseType>,
T: PyClass<BaseType = PyAny> + Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Py<T>, D::Error>
where

View file

@ -4,7 +4,6 @@
use crate::internal_tricks::extract_cstr_or_leak_cstring;
use crate::once_cell::GILOnceCell;
use crate::pyclass::{create_type_object, PyClass};
use crate::pyclass_init::PyObjectInit;
use crate::types::{PyAny, PyType};
use crate::{conversion::IntoPyPointer, PyMethodDefType};
use crate::{ffi, AsPyPointer, PyErr, PyNativeType, PyObject, PyResult, Python};
@ -16,11 +15,8 @@ use std::thread::{self, ThreadId};
/// is of `PyAny`.
///
/// This trait is intended to be used internally.
pub unsafe trait PyLayout<T: PyTypeInfo> {
pub unsafe trait PyLayout<T> {
const IS_NATIVE_TYPE: bool = true;
fn get_super(&mut self) -> Option<&mut T::BaseLayout> {
None
}
fn py_init(&mut self, _value: T) {}
unsafe fn py_drop(&mut self, _py: Python) {}
}
@ -28,23 +24,7 @@ pub unsafe trait PyLayout<T: PyTypeInfo> {
/// `T: PySizedLayout<U>` represents `T` is not a instance of
/// [`PyVarObject`](https://docs.python.org/3.8/c-api/structures.html?highlight=pyvarobject#c.PyVarObject).
/// , in addition that `T` is a concrete representaion of `U`.
pub trait PySizedLayout<T: PyTypeInfo>: PyLayout<T> + Sized {}
/// Marker type indicates that `Self` can be a base layout of `PyClass`.
///
/// # Safety
///
/// Self should be laid out as follows:
/// ```ignore
/// #[repr(C)]
/// struct Self {
/// obj: ffi::PyObject,
/// borrow_flag: u64,
/// ...
/// }
/// ```
/// Otherwise, implementing this trait is undefined behavior.
pub unsafe trait PyBorrowFlagLayout<T: PyTypeInfo>: PyLayout<T> + Sized {}
pub trait PySizedLayout<T>: PyLayout<T> + Sized {}
/// Python type information.
/// All Python native types(e.g., `PyDict`) and `#[pyclass]` structs implement this trait.
@ -59,18 +39,6 @@ pub unsafe trait PyTypeInfo: Sized {
/// Module name, if any
const MODULE: Option<&'static str>;
/// Base class
type BaseType: PyTypeInfo + PyTypeObject;
/// Layout
type Layout: PyLayout<Self>;
/// Layout of Basetype.
type BaseLayout: PySizedLayout<Self::BaseType>;
/// Initializer for layout
type Initializer: PyObjectInit<Self>;
/// Utility type to make Py::as_ref work
type AsRefTarget: crate::PyNativeType;

View file

@ -46,9 +46,6 @@ impl crate::AsPyPointer for PyAny {
}
}
unsafe impl crate::type_object::PyLayout<PyAny> for ffi::PyObject {}
impl crate::type_object::PySizedLayout<PyAny> for ffi::PyObject {}
#[allow(non_snake_case)]
// Copied here as the macro does not accept deprecated functions.
// Originally ffi::object::PyObject_Check, but this is not in the Python C API.
@ -56,9 +53,10 @@ fn PyObject_Check(_: *mut ffi::PyObject) -> c_int {
1
}
pyobject_native_type_base!(PyAny);
pyobject_native_type_info!(
PyAny,
ffi::PyObject,
ffi::PyBaseObject_Type,
Some("builtins"),
#checkfunction=PyObject_Check
@ -66,7 +64,7 @@ pyobject_native_type_info!(
pyobject_native_type_extract!(PyAny);
pyobject_native_type_base!(PyAny);
pyobject_native_type_sized!(PyAny, ffi::PyObject);
impl PyAny {
/// Convert this PyAny to a concrete Python type.

View file

@ -128,13 +128,8 @@ macro_rules! pyobject_native_type_named (
#[macro_export]
macro_rules! pyobject_native_type_info(
($name:ty, $layout:path, $typeobject:expr,
$module:expr $(, #checkfunction=$checkfunction:path)? $(;$generics:ident)*) => {
($name:ty, $typeobject:expr, $module:expr $(, #checkfunction=$checkfunction:path)? $(;$generics:ident)*) => {
unsafe impl<$($generics,)*> $crate::type_object::PyTypeInfo for $name {
type BaseType = $crate::PyAny;
type Layout = $layout;
type BaseLayout = $crate::ffi::PyObject;
type Initializer = $crate::pyclass_init::PyNativeTypeInitializer<Self>;
type AsRefTarget = Self;
const NAME: &'static str = stringify!($name);
@ -176,35 +171,27 @@ macro_rules! pyobject_native_type_extract {
#[macro_export]
macro_rules! pyobject_native_type_core {
($name:ty, $typeobject:expr, #module=$module:expr $(, #checkfunction=$checkfunction:path)? $(;$generics:ident)*) => {
$crate::pyobject_native_type_core!(@impl $name, $crate::PyAny, $typeobject, #module=$module $(, #checkfunction=$checkfunction)? $(;$generics)*);
};
($name:ty, $typeobject:expr $(, #checkfunction=$checkfunction:path)? $(;$generics:ident)*) => {
$crate::pyobject_native_type_core!(@impl $name, $crate::PyAny, $typeobject, #module=Some("builtins") $(, #checkfunction=$checkfunction)? $(;$generics)*);
};
(@impl $name:ty, $layout:path, $typeobject:expr, #module=$module:expr $(, #checkfunction=$checkfunction:path)? $(;$generics:ident)*) => {
unsafe impl $crate::type_object::PyLayout<$name> for $layout {}
$crate::pyobject_native_type_named!($name $(;$generics)*);
$crate::pyobject_native_type_info!($name, $layout, $typeobject, $module $(, #checkfunction=$checkfunction)? $(;$generics)*);
$crate::pyobject_native_type_info!($name, $typeobject, $module $(, #checkfunction=$checkfunction)? $(;$generics)*);
$crate::pyobject_native_type_extract!($name $(;$generics)*);
};
(@impl $name:ty, $layout:path, $typeobject:expr $(, #checkfunction=$checkfunction:path)? $(;$generics:ident)*) => {
$crate::pyobject_native_type_core!(@impl $name, $layout, $typeobject, #module=Some("builtins") $(, #checkfunction=$checkfunction)? $(;$generics)*);
($name:ty, $typeobject:expr $(, #checkfunction=$checkfunction:path)? $(;$generics:ident)*) => {
$crate::pyobject_native_type_core!($name, $typeobject, #module=Some("builtins") $(, #checkfunction=$checkfunction)? $(;$generics)*);
};
}
#[macro_export]
macro_rules! pyobject_native_type_sized {
($name:ty, $layout:path $(;$generics:ident)*) => {
// To prevent inheriting native types with ABI3
#[cfg(not(Py_LIMITED_API))]
unsafe impl $crate::type_object::PyLayout<$name> for $layout {}
impl $crate::type_object::PySizedLayout<$name> for $layout {}
impl<'a, $($generics,)*> $crate::derive_utils::PyBaseTypeUtils for $name {
impl<'a, $($generics,)*> $crate::class::impl_::PyClassBaseType for $name {
type Dict = $crate::pyclass_slots::PyClassDummySlot;
type WeakRef = $crate::pyclass_slots::PyClassDummySlot;
type LayoutAsBase = $crate::pycell::PyCellBase<$name>;
type LayoutAsBase = $crate::pycell::PyCellBase<$layout>;
type BaseNativeType = $name;
type ThreadChecker = $crate::class::impl_::ThreadCheckerStub<$crate::PyObject>;
type Initializer = $crate::pyclass_init::PyNativeTypeInitializer<Self>;
}
}
}
@ -214,7 +201,9 @@ macro_rules! pyobject_native_type_sized {
#[macro_export]
macro_rules! pyobject_native_type {
($name:ty, $layout:path, $typeobject:expr $(, #module=$module:expr)? $(, #checkfunction=$checkfunction:path)? $(;$generics:ident)*) => {
$crate::pyobject_native_type_core!(@impl $name, $layout, $typeobject $(, #module=$module)? $(, #checkfunction=$checkfunction)? $(;$generics)*);
$crate::pyobject_native_type_core!($name, $typeobject $(, #module=$module)? $(, #checkfunction=$checkfunction)? $(;$generics)*);
// To prevent inheriting native types with ABI3
#[cfg(not(Py_LIMITED_API))]
$crate::pyobject_native_type_sized!($name, $layout $(;$generics)*);
};
}

View file

@ -1,13 +1,22 @@
error[E0277]: the trait bound `PyDictObject: PySizedLayout<PyDict>` is not satisfied
error[E0277]: the trait bound `PyDict: PyClass` is not satisfied
--> $DIR/abi3_nativetype_inheritance.rs:5:1
|
5 | #[pyclass(extends=PyDict)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `PySizedLayout<PyDict>` is not implemented for `PyDictObject`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `PyClass` is not implemented for `PyDict`
|
::: $WORKSPACE/src/type_object.rs
|
| type BaseLayout: PySizedLayout<Self::BaseType>;
| ----------------------------- required by this bound in `pyo3::PyTypeInfo::BaseLayout`
|
= note: required because of the requirements on the impl of `PySizedLayout<PyDict>` for `PyCellBase<PyDict>`
= note: required because of the requirements on the impl of `PyClassBaseType` for `PyDict`
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `PyDict: PyClass` is not satisfied
--> $DIR/abi3_nativetype_inheritance.rs:5:1
|
5 | #[pyclass(extends=PyDict)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `PyClass` is not implemented for `PyDict`
|
::: $WORKSPACE/src/class/impl_.rs
|
| pub struct ThreadCheckerInherited<T: Send, U: PyClassBaseType>(PhantomData<T>, U::ThreadChecker);
| --------------- required by this bound in `ThreadCheckerInherited`
|
= note: required because of the requirements on the impl of `PyClassBaseType` for `PyDict`
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)

View file

@ -1,8 +1,8 @@
error[E0277]: the trait bound `i32: From<&PyCell<MyClass>>` is not satisfied
error[E0277]: the trait bound `i32: From<&pyo3::PyCell<MyClass>>` is not satisfied
--> $DIR/invalid_pymethod_receiver.rs:8:43
|
8 | fn method_with_invalid_self_type(slf: i32, py: Python, index: u32) {}
| ^^^ the trait `From<&PyCell<MyClass>>` is not implemented for `i32`
| ^^^ the trait `From<&pyo3::PyCell<MyClass>>` is not implemented for `i32`
|
= help: the following implementations were found:
<i32 as From<NonZeroI32>>
@ -10,6 +10,6 @@ error[E0277]: the trait bound `i32: From<&PyCell<MyClass>>` is not satisfied
<i32 as From<i16>>
<i32 as From<i8>>
and 2 others
= note: required because of the requirements on the impl of `Into<i32>` for `&PyCell<MyClass>`
= note: required because of the requirements on the impl of `TryFrom<&PyCell<MyClass>>` for `i32`
= note: required because of the requirements on the impl of `Into<i32>` for `&pyo3::PyCell<MyClass>`
= note: required because of the requirements on the impl of `TryFrom<&pyo3::PyCell<MyClass>>` for `i32`
= note: required by `std::convert::TryFrom::try_from`