Skip to content

Commit

Permalink
Use PyBorrowFlagLayout to ensure the baseclass has a borrow flag
Browse files Browse the repository at this point in the history
  • Loading branch information
kngwyu committed Feb 22, 2020
1 parent 0e3f7cb commit 68a3b15
Show file tree
Hide file tree
Showing 10 changed files with 55 additions and 39 deletions.
2 changes: 1 addition & 1 deletion pyo3-derive-backend/src/pyclass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ fn impl_class(
quote! { 0 }
};
let base_layout = if attr.has_extends {
quote! { <Self::BaseType as pyo3::derive_utils::PyBaseTypeUtils>::Layout }
quote! { <Self::BaseType as pyo3::derive_utils::PyBaseTypeUtils>::LayoutAsBase }
} else {
quote! { pyo3::pycell::PyCellBase<pyo3::types::PyAny> }
};
Expand Down
4 changes: 2 additions & 2 deletions src/derive_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,13 +223,13 @@ impl GetPropertyValue for PyObject {
pub trait PyBaseTypeUtils {
type Dict;
type WeakRef;
type Layout;
type LayoutAsBase;
type BaseNativeType;
}

impl<T: PyClass> PyBaseTypeUtils for T {
type Dict = T::Dict;
type WeakRef = T::WeakRef;
type Layout = crate::pycell::PyCellInner<T>;
type LayoutAsBase = crate::pycell::PyCellInner<T>;
type BaseNativeType = T::BaseNativeType;
}
2 changes: 1 addition & 1 deletion src/freelist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
use crate::ffi;
use crate::pyclass::{tp_free_fallback, PyClassAlloc};
use crate::type_object::{PyObjectLayout, PyTypeInfo};
use crate::type_object::{PyLayout, PyTypeInfo};
use crate::Python;
use std::mem;
use std::os::raw::c_void;
Expand Down
4 changes: 2 additions & 2 deletions src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::err::{PyErr, PyResult};
use crate::gil;
use crate::object::PyObject;
use crate::objectprotocol::ObjectProtocol;
use crate::type_object::PyDowncastImpl;
use crate::type_object::{PyBorrowFlagLayout, PyDowncastImpl};
use crate::types::PyAny;
use crate::{
ffi, AsPyPointer, FromPyObject, IntoPy, IntoPyPointer, PyCell, PyClass, PyClassInitializer,
Expand Down Expand Up @@ -39,7 +39,7 @@ impl<T> Py<T> {
pub fn new(py: Python, value: impl Into<PyClassInitializer<T>>) -> PyResult<Py<T>>
where
T: PyClass,
T::BaseLayout: crate::type_object::PyObjectSizedLayout<T::BaseType>,
T::BaseLayout: PyBorrowFlagLayout<T::BaseType>,
{
let initializer = value.into();
let obj = unsafe { initializer.create_cell(py)? };
Expand Down
37 changes: 25 additions & 12 deletions src/pycell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use crate::conversion::{AsPyPointer, FromPyPointer, ToPyObject};
use crate::pyclass_init::PyClassInitializer;
use crate::pyclass_slots::{PyClassDict, PyClassWeakRef};
use crate::type_object::{PyDowncastImpl, PyObjectLayout, PyObjectSizedLayout, PyTypeInfo};
use crate::type_object::{PyBorrowFlagLayout, PyDowncastImpl, PyLayout, PySizedLayout, PyTypeInfo};
use crate::types::PyAny;
use crate::{ffi, FromPy, PyClass, PyErr, PyNativeType, PyObject, PyResult, Python};
use std::cell::{Cell, UnsafeCell};
Expand All @@ -17,10 +17,10 @@ pub struct PyCellBase<T: PyTypeInfo> {
borrow_flag: Cell<BorrowFlag>,
}

unsafe impl<T> PyObjectLayout<T> for PyCellBase<T>
unsafe impl<T> PyLayout<T> for PyCellBase<T>
where
T: PyTypeInfo + PyNativeType,
T::Layout: PyObjectSizedLayout<T>,
T::Layout: PySizedLayout<T>,
{
const IS_NATIVE_TYPE: bool = true;
unsafe fn unchecked_ref(&self) -> &T {
Expand All @@ -31,11 +31,18 @@ where
}
}

// This impl ensures `PyCellBase` can be a base type.
impl<T> PyObjectSizedLayout<T> for PyCellBase<T>
// Thes impls ensures `PyCellBase` can be a base type.
impl<T> PySizedLayout<T> for PyCellBase<T>
where
T: PyTypeInfo + PyNativeType,
T::Layout: PyObjectSizedLayout<T>,
T::Layout: PySizedLayout<T>,
{
}

unsafe impl<T> PyBorrowFlagLayout<T> for PyCellBase<T>
where
T: PyTypeInfo + PyNativeType,
T::Layout: PySizedLayout<T>,
{
}

Expand All @@ -56,7 +63,7 @@ impl<T: PyClass> AsPyPointer for PyCellInner<T> {
}
}

unsafe impl<T: PyClass> PyObjectLayout<T> for PyCellInner<T> {
unsafe impl<T: PyClass> PyLayout<T> for PyCellInner<T> {
const IS_NATIVE_TYPE: bool = false;
fn get_super_or(&mut self) -> Option<&mut T::BaseLayout> {
Some(&mut self.ob_base)
Expand All @@ -76,8 +83,9 @@ unsafe impl<T: PyClass> PyObjectLayout<T> for PyCellInner<T> {
}
}

// This impl ensures `PyCellInner` can be a base type.
impl<T: PyClass> PyObjectSizedLayout<T> for PyCellInner<T> {}
// Thes 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_borrow_flag(&self) -> BorrowFlag {
Expand Down Expand Up @@ -164,7 +172,7 @@ impl<T: PyClass> PyCell<T> {
///
pub fn new(py: Python, value: impl Into<PyClassInitializer<T>>) -> PyResult<&Self>
where
T::BaseLayout: crate::type_object::PyObjectSizedLayout<T::BaseType>,
T::BaseLayout: PyBorrowFlagLayout<T::BaseType>,
{
unsafe {
let initializer = value.into();
Expand Down Expand Up @@ -325,9 +333,12 @@ impl<T: PyClass> PyCell<T> {
std::mem::swap(&mut *self.borrow_mut(), &mut *other.borrow_mut())
}

/// Allocates new PyCell without initilizing value.
/// Requires `T::BaseLayout: PyBorrowFlagLayout<T::BaseType>` to ensure that
/// this layout has a borrow flag.
pub(crate) unsafe fn internal_new(py: Python) -> PyResult<*mut Self>
where
T::BaseLayout: crate::type_object::PyObjectSizedLayout<T::BaseType>,
T::BaseLayout: PyBorrowFlagLayout<T::BaseType>,
{
let base = T::alloc(py);
if base.is_null() {
Expand All @@ -342,7 +353,7 @@ impl<T: PyClass> PyCell<T> {
}
}

unsafe impl<T: PyClass> PyObjectLayout<T> for PyCell<T> {
unsafe impl<T: PyClass> PyLayout<T> for PyCell<T> {
const IS_NATIVE_TYPE: bool = false;
fn get_super_or(&mut self) -> Option<&mut T::BaseLayout> {
Some(&mut self.inner.ob_base)
Expand Down Expand Up @@ -598,6 +609,7 @@ impl BorrowFlag {
}
}

/// An error returned by [`PyCell::try_borrow`](struct.PyCell.html#method.try_borrow).
pub struct PyBorrowError {
_private: (),
}
Expand All @@ -614,6 +626,7 @@ impl fmt::Display for PyBorrowError {
}
}

/// An error returned by [`PyCell::try_borrow_mut`](struct.PyCell.html#method.try_borrow_mut).
pub struct PyBorrowMutError {
_private: (),
}
Expand Down
2 changes: 1 addition & 1 deletion src/pyclass.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! `PyClass` trait
use crate::class::methods::{PyMethodDefType, PyMethodsProtocol};
use crate::pyclass_slots::{PyClassDict, PyClassWeakRef};
use crate::type_object::{type_flags, PyObjectLayout};
use crate::type_object::{type_flags, PyLayout};
use crate::{class, ffi, gil, PyCell, PyErr, PyNativeType, PyResult, PyTypeInfo, Python};
use std::ffi::CString;
use std::os::raw::c_void;
Expand Down
15 changes: 8 additions & 7 deletions src/pyclass_init.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//! Initialization utilities for `#[pyclass]`.
use crate::type_object::{PyObjectLayout, PyObjectSizedLayout, PyTypeInfo};
use crate::type_object::{PyBorrowFlagLayout, PyLayout, PySizedLayout, PyTypeInfo};
use crate::{PyCell, PyClass, PyResult, Python};
use std::marker::PhantomData;

Expand All @@ -8,15 +8,15 @@ use std::marker::PhantomData;
/// This trait is intended to use internally for distinguishing `#[pyclass]` and
/// Python native types.
pub trait PyObjectInit<T: PyTypeInfo>: Sized {
fn init_class<L: PyObjectLayout<T>>(self, layout: &mut L);
fn init_class<L: PyLayout<T>>(self, layout: &mut L);
private_decl! {}
}

/// Initializer for Python native type, like `PyDict`.
pub struct PyNativeTypeInitializer<T: PyTypeInfo>(PhantomData<T>);

impl<T: PyTypeInfo> PyObjectInit<T> for PyNativeTypeInitializer<T> {
fn init_class<L: PyObjectLayout<T>>(self, _layout: &mut L) {}
fn init_class<L: PyLayout<T>>(self, _layout: &mut L) {}
private_impl! {}
}

Expand Down Expand Up @@ -108,17 +108,18 @@ impl<T: PyClass> PyClassInitializer<T> {
pub fn add_subclass<S>(self, subclass_value: S) -> PyClassInitializer<S>
where
S: PyClass + PyTypeInfo<BaseType = T>,
S::BaseLayout: PyObjectSizedLayout<T>,
S::BaseLayout: PySizedLayout<T>,
S::BaseType: PyTypeInfo<Initializer = Self>,
{
PyClassInitializer::new(subclass_value, self)
}

// Create a new PyCell + initialize it
#[doc(hidden)]
pub unsafe fn create_cell(self, py: Python) -> PyResult<*mut PyCell<T>>
where
T: PyClass,
T::BaseLayout: PyObjectSizedLayout<T::BaseType>,
T::BaseLayout: PyBorrowFlagLayout<T::BaseType>,
{
let cell = PyCell::internal_new(py)?;
self.init_class(&mut *cell);
Expand All @@ -127,7 +128,7 @@ impl<T: PyClass> PyClassInitializer<T> {
}

impl<T: PyClass> PyObjectInit<T> for PyClassInitializer<T> {
fn init_class<L: PyObjectLayout<T>>(self, layout: &mut L) {
fn init_class<L: PyLayout<T>>(self, layout: &mut L) {
let Self { init, super_init } = self;
unsafe {
layout.py_init(init);
Expand All @@ -152,7 +153,7 @@ where
impl<S, B> From<(S, B)> for PyClassInitializer<S>
where
S: PyClass + PyTypeInfo<BaseType = B>,
S::BaseLayout: PyObjectSizedLayout<B>,
S::BaseLayout: PySizedLayout<B>,
B: PyClass + PyTypeInfo<Initializer = PyClassInitializer<B>>,
B::BaseType: PyTypeInfo<Initializer = PyNativeTypeInitializer<B::BaseType>>,
{
Expand Down
18 changes: 10 additions & 8 deletions src/type_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ use std::cell::UnsafeCell;
use std::ptr::NonNull;
use std::sync::atomic::{AtomicBool, Ordering};

/// `T: PyObjectLayout<U>` represents that `T` is a concrete representaion of `U` in Python heap.
/// `T: PyLayout<U>` represents that `T` is a concrete representaion of `U` in Python heap.
/// E.g., `PyCell` is a concrete representaion of all `pyclass`es, and `ffi::PyObject`
/// is of `PyAny`.
///
/// This trait is intended to be used internally.
pub unsafe trait PyObjectLayout<T: PyTypeInfo> {
pub unsafe trait PyLayout<T: PyTypeInfo> {
const IS_NATIVE_TYPE: bool = true;
fn get_super_or(&mut self) -> Option<&mut T::BaseLayout> {
None
Expand All @@ -26,12 +26,14 @@ pub unsafe trait PyObjectLayout<T: PyTypeInfo> {
unsafe fn unchecked_mut(&self) -> &mut T;
}

/// `T: PyObjectSizedLayout<U>` represents `T` is not a instance of
/// `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`.
///
/// `pyclass`es need this trait for their base class.
pub trait PyObjectSizedLayout<T: PyTypeInfo>: PyObjectLayout<T> + Sized {}
pub trait PySizedLayout<T: PyTypeInfo>: PyLayout<T> + Sized {}

/// Marker type indicates that `Self` can be a baselayout of PyClass.
/// This trait assumes a certain layout and thus is unsafe.
pub unsafe trait PyBorrowFlagLayout<T: PyTypeInfo>: PyLayout<T> + Sized {}

/// Our custom type flags
#[doc(hidden)]
Expand Down Expand Up @@ -99,10 +101,10 @@ pub unsafe trait PyTypeInfo: Sized {
type BaseType: PyTypeInfo + PyTypeObject;

/// Layout
type Layout: PyObjectLayout<Self>;
type Layout: PyLayout<Self>;

/// Layout of Basetype.
type BaseLayout: PyObjectLayout<Self::BaseType>;
type BaseLayout: PySizedLayout<Self::BaseType>;

/// Initializer for layout
type Initializer: PyObjectInit<Self>;
Expand Down
4 changes: 2 additions & 2 deletions src/types/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ use crate::{ffi, PyObject};
/// ```
#[repr(transparent)]
pub struct PyAny(PyObject, Unsendable);
unsafe impl crate::type_object::PyObjectLayout<PyAny> for ffi::PyObject {
unsafe impl crate::type_object::PyLayout<PyAny> for ffi::PyObject {
unsafe fn unchecked_ref(&self) -> &PyAny {
&*((&self) as *const &Self as *const _)
}
unsafe fn unchecked_mut(&self) -> &mut PyAny {
&mut *((&self) as *const &Self as *const _ as *mut _)
}
}
impl crate::type_object::PyObjectSizedLayout<PyAny> for ffi::PyObject {}
impl crate::type_object::PySizedLayout<PyAny> for ffi::PyObject {}
pyobject_native_type_named!(PyAny);
pyobject_native_type_convert!(
PyAny,
Expand Down
6 changes: 3 additions & 3 deletions src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ macro_rules! pyobject_native_type_named (

macro_rules! impl_layout {
($name: ty, $layout: path) => {
unsafe impl $crate::type_object::PyObjectLayout<$name> for $layout {
unsafe impl $crate::type_object::PyLayout<$name> for $layout {
unsafe fn unchecked_ref(&self) -> &$name {
&*((&self) as *const &Self as *const _)
}
Expand All @@ -73,11 +73,11 @@ macro_rules! impl_layout {
macro_rules! pyobject_native_type {
($name: ty, $layout: path, $typeobject: expr, $module: expr, $checkfunction: path $(,$type_param: ident)*) => {
impl_layout!($name, $layout);
impl $crate::type_object::PyObjectSizedLayout<$name> for $layout {}
impl $crate::type_object::PySizedLayout<$name> for $layout {}
impl $crate::derive_utils::PyBaseTypeUtils for $name {
type Dict = $crate::pyclass_slots::PyClassDummySlot;
type WeakRef = $crate::pyclass_slots::PyClassDummySlot;
type Layout = $crate::pycell::PyCellBase<$name>;
type LayoutAsBase = $crate::pycell::PyCellBase<$name>;
type BaseNativeType = $name;
}
pyobject_native_type_named!($name $(,$type_param)*);
Expand Down

0 comments on commit 68a3b15

Please sign in to comment.