type_object: remove layout and base type from PyTypeInfo
This commit is contained in:
parent
05db24ce33
commit
7536554ceb
|
@ -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.
|
||||
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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>;
|
||||
}
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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 _) };
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)*);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,13 +1,22 @@
|
|||
error[E0277]: the trait bound `PyDictObject: PySizedLayout<PyDict>` is not satisfied
|
||||
--> $DIR/abi3_nativetype_inheritance.rs:5:1
|
||||
|
|
||||
5 | #[pyclass(extends=PyDict)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `PySizedLayout<PyDict>` is not implemented for `PyDictObject`
|
||||
|
|
||||
::: $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: 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`
|
||||
|
|
||||
= 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)
|
||||
|
|
|
@ -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`
|
||||
|
|
Loading…
Reference in a new issue