Skip to content

Commit

Permalink
split PyCell and PyClassObject concepts
Browse files Browse the repository at this point in the history
  • Loading branch information
davidhewitt committed Mar 1, 2024
1 parent 53312c1 commit e9c4553
Show file tree
Hide file tree
Showing 8 changed files with 220 additions and 205 deletions.
30 changes: 17 additions & 13 deletions src/impl_/coroutine.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use std::{
future::Future,
mem,
ops::{Deref, DerefMut},
};

use crate::{
coroutine::{cancel::ThrowCallback, Coroutine},
instance::Bound,
pycell::impl_::PyClassBorrowChecker,
pyclass::boolean_struct::False,
types::PyString,
IntoPy, Py, PyAny, PyCell, PyClass, PyErr, PyObject, PyResult, Python,
Expand Down Expand Up @@ -40,9 +40,9 @@ pub struct RefGuard<T: PyClass>(Py<T>);

impl<T: PyClass> RefGuard<T> {
pub fn new(obj: &PyAny) -> PyResult<Self> {
let owned: Py<T> = obj.extract()?;
mem::forget(owned.try_borrow(obj.py())?);
Ok(RefGuard(owned))
let owned: Bound<'_, T> = obj.extract()?;
owned.get_class_object().borrow_checker().try_borrow()?;
Ok(RefGuard(owned.unbind()))
}
}

Expand All @@ -57,9 +57,11 @@ impl<T: PyClass> Deref for RefGuard<T> {
impl<T: PyClass> Drop for RefGuard<T> {
fn drop(&mut self) {
Python::with_gil(|gil| {
#[allow(deprecated)]
let self_ref = self.0.bind(gil);
self_ref.release_ref()
self.0
.bind(gil)
.get_class_object()
.borrow_checker()
.release_borrow()
})
}
}
Expand All @@ -68,9 +70,9 @@ pub struct RefMutGuard<T: PyClass<Frozen = False>>(Py<T>);

impl<T: PyClass<Frozen = False>> RefMutGuard<T> {
pub fn new(obj: &PyAny) -> PyResult<Self> {
let owned: Py<T> = obj.extract()?;
mem::forget(owned.try_borrow_mut(obj.py())?);
Ok(RefMutGuard(owned))
let owned: Bound<'_, T> = obj.extract()?;
owned.get_class_object().borrow_checker().try_borrow_mut()?;
Ok(RefMutGuard(owned.unbind()))
}
}

Expand All @@ -92,9 +94,11 @@ impl<T: PyClass<Frozen = False>> DerefMut for RefMutGuard<T> {
impl<T: PyClass<Frozen = False>> Drop for RefMutGuard<T> {
fn drop(&mut self) {
Python::with_gil(|gil| {
#[allow(deprecated)]
let self_ref = self.0.bind(gil);
self_ref.release_mut()
self.0
.bind(gil)
.get_class_object()
.borrow_checker()
.release_borrow_mut()
})
}
}
4 changes: 3 additions & 1 deletion src/impl_/pycell.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
//! Externally-accessible implementation of pycell
pub use crate::pycell::impl_::{GetBorrowChecker, PyClassMutability};
pub use crate::pycell::impl_::{
GetBorrowChecker, PyClassMutability, PyClassObject, PyClassObjectBase, PyClassObjectLayout,
};
13 changes: 7 additions & 6 deletions src/impl_/pyclass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ use crate::{
exceptions::{PyAttributeError, PyNotImplementedError, PyRuntimeError, PyValueError},
ffi,
impl_::freelist::FreeList,
impl_::pycell::{GetBorrowChecker, PyClassMutability},
impl_::pycell::{GetBorrowChecker, PyClassMutability, PyClassObjectLayout},
internal_tricks::extract_c_string,
pycell::PyCellLayout,
pyclass_init::PyObjectInit,
types::any::PyAnyMethods,
types::PyBool,
Expand Down Expand Up @@ -883,6 +882,8 @@ macro_rules! generate_pyclass_richcompare_slot {
}
pub use generate_pyclass_richcompare_slot;

use super::pycell::PyClassObject;

/// Implements a freelist.
///
/// Do not implement this trait manually. Instead, use `#[pyclass(freelist = N)]`
Expand Down Expand Up @@ -1095,7 +1096,7 @@ impl<T> PyClassThreadChecker<T> for ThreadCheckerImpl {

/// Trait denoting that this class is suitable to be used as a base type for PyClass.
pub trait PyClassBaseType: Sized {
type LayoutAsBase: PyCellLayout<Self>;
type LayoutAsBase: PyClassObjectLayout<Self>;
type BaseNativeType;
type Initializer: PyObjectInit<Self>;
type PyClassMutability: PyClassMutability;
Expand All @@ -1105,15 +1106,15 @@ pub trait PyClassBaseType: Sized {
///
/// In the future this will be extended to immutable PyClasses too.
impl<T: PyClass> PyClassBaseType for T {
type LayoutAsBase = crate::pycell::PyCell<T>;
type LayoutAsBase = crate::impl_::pycell::PyClassObject<T>;
type BaseNativeType = T::BaseNativeType;
type Initializer = crate::pyclass_init::PyClassInitializer<Self>;
type PyClassMutability = T::PyClassMutability;
}

/// Implementation of tp_dealloc for pyclasses without gc
pub(crate) unsafe extern "C" fn tp_dealloc<T: PyClass>(obj: *mut ffi::PyObject) {
crate::impl_::trampoline::dealloc(obj, PyCell::<T>::tp_dealloc)
crate::impl_::trampoline::dealloc(obj, PyClassObject::<T>::tp_dealloc)
}

/// Implementation of tp_dealloc for pyclasses with gc
Expand All @@ -1122,7 +1123,7 @@ pub(crate) unsafe extern "C" fn tp_dealloc_with_gc<T: PyClass>(obj: *mut ffi::Py
{
ffi::PyObject_GC_UnTrack(obj.cast());
}
crate::impl_::trampoline::dealloc(obj, PyCell::<T>::tp_dealloc)
crate::impl_::trampoline::dealloc(obj, PyClassObject::<T>::tp_dealloc)
}

pub(crate) unsafe extern "C" fn get_sequence_item_from_mapping(
Expand Down
15 changes: 6 additions & 9 deletions src/instance.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::err::{self, PyDowncastError, PyErr, PyResult};
use crate::ffi_ptr_ext::FfiPtrExt;
use crate::impl_::pycell::PyClassObject;
use crate::pycell::{PyBorrowError, PyBorrowMutError, PyCell};
use crate::pyclass::boolean_struct::{False, True};
use crate::type_object::HasPyGilRef;
Expand Down Expand Up @@ -332,18 +333,14 @@ where
where
T: PyClass<Frozen = True> + Sync,
{
let cell = self.get_cell();
// SAFETY: The class itself is frozen and `Sync` and we do not access anything but `cell.contents.value`.
unsafe { &*cell.get_ptr() }
// SAFETY: The class itself is frozen and `Sync`.
unsafe { &*self.get_class_object().get_ptr() }
}

pub(crate) fn get_cell(&'py self) -> &'py PyCell<T> {
let cell = self.as_ptr().cast::<PyCell<T>>();
pub(crate) fn get_class_object(&self) -> &PyClassObject<T> {
let cell = self.as_ptr().cast::<PyClassObject<T>>();
// SAFETY: Bound<T> is known to contain an object which is laid out in memory as a
// PyCell<T>.
//
// Strictly speaking for now `&'py PyCell<T>` is part of the "GIL Ref" API, so this
// could use some further refactoring later to avoid going through this reference.
// PyClassObject<T>.
unsafe { &*cell }
}
}
Expand Down
Loading

0 comments on commit e9c4553

Please sign in to comment.