2020-02-21 12:12:32 +00:00
|
|
|
//! Includes `PyCell` implementation.
|
2020-02-15 15:24:38 +00:00
|
|
|
use crate::conversion::{AsPyPointer, FromPyPointer, ToPyObject};
|
2020-02-03 13:25:16 +00:00
|
|
|
use crate::pyclass_init::PyClassInitializer;
|
|
|
|
use crate::pyclass_slots::{PyClassDict, PyClassWeakRef};
|
2020-02-22 15:56:58 +00:00
|
|
|
use crate::type_object::{PyBorrowFlagLayout, PyDowncastImpl, PyLayout, PySizedLayout, PyTypeInfo};
|
2020-02-03 13:25:16 +00:00
|
|
|
use crate::types::PyAny;
|
2020-02-15 15:24:38 +00:00
|
|
|
use crate::{ffi, FromPy, PyClass, PyErr, PyNativeType, PyObject, PyResult, Python};
|
2020-02-09 07:36:32 +00:00
|
|
|
use std::cell::{Cell, UnsafeCell};
|
|
|
|
use std::fmt;
|
2020-02-03 13:25:16 +00:00
|
|
|
use std::mem::ManuallyDrop;
|
2020-02-09 07:36:32 +00:00
|
|
|
use std::ops::{Deref, DerefMut};
|
2020-02-03 13:25:16 +00:00
|
|
|
|
2020-02-28 07:49:25 +00:00
|
|
|
/// Base layout of PyCell.
|
|
|
|
/// This is necessary for sharing BorrowFlag between parents and children.
|
2020-02-15 04:42:25 +00:00
|
|
|
#[doc(hidden)]
|
|
|
|
#[repr(C)]
|
|
|
|
pub struct PyCellBase<T: PyTypeInfo> {
|
|
|
|
ob_base: T::Layout,
|
|
|
|
borrow_flag: Cell<BorrowFlag>,
|
|
|
|
}
|
|
|
|
|
2020-02-22 15:56:58 +00:00
|
|
|
unsafe impl<T> PyLayout<T> for PyCellBase<T>
|
2020-02-15 04:42:25 +00:00
|
|
|
where
|
|
|
|
T: PyTypeInfo + PyNativeType,
|
2020-02-22 15:56:58 +00:00
|
|
|
T::Layout: PySizedLayout<T>,
|
2020-02-15 04:42:25 +00:00
|
|
|
{
|
2020-02-15 15:24:38 +00:00
|
|
|
const IS_NATIVE_TYPE: bool = true;
|
2020-02-15 04:42:25 +00:00
|
|
|
}
|
|
|
|
|
2020-02-22 15:56:58 +00:00
|
|
|
// Thes impls ensures `PyCellBase` can be a base type.
|
|
|
|
impl<T> PySizedLayout<T> for PyCellBase<T>
|
2020-02-15 04:42:25 +00:00
|
|
|
where
|
|
|
|
T: PyTypeInfo + PyNativeType,
|
2020-02-22 15:56:58 +00:00
|
|
|
T::Layout: PySizedLayout<T>,
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe impl<T> PyBorrowFlagLayout<T> for PyCellBase<T>
|
|
|
|
where
|
|
|
|
T: PyTypeInfo + PyNativeType,
|
|
|
|
T::Layout: PySizedLayout<T>,
|
2020-02-15 04:42:25 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2020-02-09 07:36:32 +00:00
|
|
|
/// Inner type of `PyCell` without dict slots and reference counter.
|
2020-02-10 08:30:48 +00:00
|
|
|
/// This struct has two usages:
|
|
|
|
/// 1. As an inner type of `PyRef` and `PyRefMut`.
|
2020-02-28 07:49:25 +00:00
|
|
|
/// 2. When `#[pyclass(extends=Base)]` is specified, `PyCellInner<Base>` is used as a base layout.
|
2020-02-09 07:36:32 +00:00
|
|
|
#[doc(hidden)]
|
|
|
|
#[repr(C)]
|
2020-02-15 04:42:25 +00:00
|
|
|
pub struct PyCellInner<T: PyClass> {
|
|
|
|
ob_base: T::BaseLayout,
|
2020-02-09 07:36:32 +00:00
|
|
|
value: ManuallyDrop<UnsafeCell<T>>,
|
|
|
|
}
|
|
|
|
|
2020-02-15 04:42:25 +00:00
|
|
|
impl<T: PyClass> AsPyPointer for PyCellInner<T> {
|
2020-02-10 08:30:48 +00:00
|
|
|
fn as_ptr(&self) -> *mut ffi::PyObject {
|
|
|
|
(self as *const _) as *mut _
|
2020-02-09 07:36:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-22 15:56:58 +00:00
|
|
|
unsafe impl<T: PyClass> PyLayout<T> for PyCellInner<T> {
|
2020-02-09 07:36:32 +00:00
|
|
|
const IS_NATIVE_TYPE: bool = false;
|
2020-03-01 03:58:28 +00:00
|
|
|
fn get_super(&mut self) -> Option<&mut T::BaseLayout> {
|
2020-02-09 07:36:32 +00:00
|
|
|
Some(&mut self.ob_base)
|
|
|
|
}
|
|
|
|
unsafe fn py_init(&mut self, value: T) {
|
|
|
|
self.value = ManuallyDrop::new(UnsafeCell::new(value));
|
|
|
|
}
|
|
|
|
unsafe fn py_drop(&mut self, py: Python) {
|
|
|
|
ManuallyDrop::drop(&mut self.value);
|
|
|
|
self.ob_base.py_drop(py);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-28 07:49:25 +00:00
|
|
|
// These impls ensures `PyCellInner` can be a base type.
|
2020-02-22 15:56:58 +00:00
|
|
|
impl<T: PyClass> PySizedLayout<T> for PyCellInner<T> {}
|
|
|
|
unsafe impl<T: PyClass> PyBorrowFlagLayout<T> for PyCellInner<T> {}
|
2020-02-15 04:42:25 +00:00
|
|
|
|
|
|
|
impl<T: PyClass> PyCellInner<T> {
|
2020-03-02 09:42:04 +00:00
|
|
|
unsafe fn get_ptr(&self) -> *mut T {
|
|
|
|
self.value.get()
|
|
|
|
}
|
2020-02-15 04:42:25 +00:00
|
|
|
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) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-21 12:12:32 +00:00
|
|
|
/// `PyCell` is the container type for [`PyClass`](../pyclass/trait.PyClass.html).
|
2020-02-03 13:25:16 +00:00
|
|
|
///
|
2020-02-21 12:12:32 +00:00
|
|
|
/// From Python side, `PyCell<T>` is the concrete layout of `T: PyClass` in the Python heap,
|
|
|
|
/// which means we can convert `*const PyClass<T>` to `*mut ffi::PyObject`.
|
2020-02-03 13:25:16 +00:00
|
|
|
///
|
2020-02-21 12:12:32 +00:00
|
|
|
/// From Rust side, `PyCell<T>` is the mutable container of `T`.
|
|
|
|
/// Since `PyCell<T: PyClass>` is always on the Python heap, we don't have the ownership of it.
|
|
|
|
/// Thus, to mutate the data behind `&PyCell<T>` safely, we employ the
|
|
|
|
/// [Interior Mutability Pattern](https://doc.rust-lang.org/book/ch15-05-interior-mutability.html)
|
|
|
|
/// like [std::cell::RefCell](https://doc.rust-lang.org/std/cell/struct.RefCell.html).
|
|
|
|
///
|
2020-02-22 14:38:01 +00:00
|
|
|
/// # Examples
|
|
|
|
///
|
2020-02-21 12:12:32 +00:00
|
|
|
/// In most cases, `PyCell` is hidden behind `#[pymethods]`.
|
|
|
|
/// However, you can construct `&PyCell` directly to test your pyclass in Rust code.
|
2020-02-22 14:38:01 +00:00
|
|
|
///
|
2020-02-03 13:25:16 +00:00
|
|
|
/// ```
|
|
|
|
/// # use pyo3::prelude::*;
|
|
|
|
/// #[pyclass]
|
|
|
|
/// struct Book {
|
|
|
|
/// #[pyo3(get)]
|
|
|
|
/// name: &'static str,
|
|
|
|
/// author: &'static str,
|
|
|
|
/// }
|
|
|
|
/// let gil = Python::acquire_gil();
|
|
|
|
/// let py = gil.python();
|
|
|
|
/// let book = Book {
|
|
|
|
/// name: "The Man in the High Castle",
|
|
|
|
/// author: "Philip Kindred Dick",
|
|
|
|
/// };
|
2020-02-15 15:24:38 +00:00
|
|
|
/// let book_cell = PyCell::new(py, book).unwrap();
|
2020-02-21 12:12:32 +00:00
|
|
|
/// // you can expose PyCell to Python snippets
|
|
|
|
/// pyo3::py_run!(py, book_cell, "assert book_cell.name[-6:] == 'Castle'");
|
|
|
|
/// ```
|
2020-02-22 14:38:01 +00:00
|
|
|
/// You can use `slf: &PyCell<Self>` as an alternative `self` receiver of `#[pymethod]`,
|
|
|
|
/// though you rarely need it.
|
2020-02-21 12:12:32 +00:00
|
|
|
/// ```
|
|
|
|
/// # use pyo3::prelude::*;
|
|
|
|
/// use std::collections::HashMap;
|
|
|
|
/// #[pyclass]
|
|
|
|
/// #[derive(Default)]
|
|
|
|
/// struct Counter {
|
2020-02-22 14:38:01 +00:00
|
|
|
/// counter: HashMap<String, usize>
|
2020-02-21 12:12:32 +00:00
|
|
|
/// }
|
|
|
|
/// #[pymethods]
|
|
|
|
/// impl Counter {
|
2020-02-22 14:38:01 +00:00
|
|
|
/// // You can use &mut self here, but now we use &PyCell for demonstration
|
2020-02-21 12:12:32 +00:00
|
|
|
/// fn increment(slf: &PyCell<Self>, name: String) -> PyResult<usize> {
|
|
|
|
/// let mut slf_mut = slf.try_borrow_mut()?;
|
2020-02-22 14:38:01 +00:00
|
|
|
/// // Now a mutable reference exists so we cannot get another one
|
2020-02-21 12:12:32 +00:00
|
|
|
/// assert!(slf.try_borrow().is_err());
|
|
|
|
/// assert!(slf.try_borrow_mut().is_err());
|
2020-02-22 14:38:01 +00:00
|
|
|
/// let counter = slf_mut.counter.entry(name).or_insert(0);
|
2020-02-21 12:12:32 +00:00
|
|
|
/// *counter += 1;
|
|
|
|
/// Ok(*counter)
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// # let gil = Python::acquire_gil();
|
|
|
|
/// # let py = gil.python();
|
|
|
|
/// # let counter = PyCell::new(py, Counter::default()).unwrap();
|
|
|
|
/// # pyo3::py_run!(py, counter, "assert counter.increment('cat') == 1");
|
2020-02-03 13:25:16 +00:00
|
|
|
/// ```
|
|
|
|
#[repr(C)]
|
|
|
|
pub struct PyCell<T: PyClass> {
|
2020-02-15 04:42:25 +00:00
|
|
|
inner: PyCellInner<T>,
|
2020-02-03 13:25:16 +00:00
|
|
|
dict: T::Dict,
|
|
|
|
weakref: T::WeakRef,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: PyClass> PyCell<T> {
|
|
|
|
/// Make new `PyCell` on the Python heap and returns the reference of it.
|
2020-02-22 14:38:01 +00:00
|
|
|
///
|
2020-02-09 07:35:52 +00:00
|
|
|
pub fn new(py: Python, value: impl Into<PyClassInitializer<T>>) -> PyResult<&Self>
|
2020-02-03 13:25:16 +00:00
|
|
|
where
|
2020-02-22 15:56:58 +00:00
|
|
|
T::BaseLayout: PyBorrowFlagLayout<T::BaseType>,
|
2020-02-03 13:25:16 +00:00
|
|
|
{
|
|
|
|
unsafe {
|
|
|
|
let initializer = value.into();
|
|
|
|
let self_ = initializer.create_cell(py)?;
|
|
|
|
FromPyPointer::from_owned_ptr_or_err(py, self_ as _)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-22 14:38:01 +00:00
|
|
|
/// Immutably borrows the value `T`. This borrow lasts untill the returned `PyRef` exists.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// Panics if the value is currently mutably borrowed. For a non-panicking variant, use
|
|
|
|
/// [`try_borrow`](#method.try_borrow).
|
2020-02-09 07:36:32 +00:00
|
|
|
pub fn borrow(&self) -> PyRef<'_, T> {
|
2020-02-10 08:30:48 +00:00
|
|
|
self.try_borrow().expect("Already mutably borrowed")
|
2020-02-03 13:25:16 +00:00
|
|
|
}
|
|
|
|
|
2020-02-22 14:38:01 +00:00
|
|
|
/// Mutably borrows the value `T`. This borrow lasts untill the returned `PyRefMut` exists.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// Panics if the value is currently mutably borrowed. For a non-panicking variant, use
|
|
|
|
/// [`try_borrow_mut`](#method.try_borrow_mut).
|
2020-02-09 07:36:32 +00:00
|
|
|
pub fn borrow_mut(&self) -> PyRefMut<'_, T> {
|
2020-02-10 08:30:48 +00:00
|
|
|
self.try_borrow_mut().expect("Already borrowed")
|
|
|
|
}
|
|
|
|
|
2020-02-22 14:38:01 +00:00
|
|
|
/// Immutably borrows the value `T`, returning an error if the value is currently
|
|
|
|
/// mutably borrowed. This borrow lasts untill the returned `PyRef` exists.
|
|
|
|
///
|
|
|
|
/// This is the non-panicking variant of [`borrow`](#method.borrow).
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use pyo3::prelude::*;
|
|
|
|
/// #[pyclass]
|
|
|
|
/// struct Class {}
|
|
|
|
/// let gil = Python::acquire_gil();
|
|
|
|
/// let py = gil.python();
|
|
|
|
/// let c = PyCell::new(py, Class {}).unwrap();
|
|
|
|
/// {
|
|
|
|
/// let m = c.borrow_mut();
|
|
|
|
/// assert!(c.try_borrow().is_err());
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// {
|
|
|
|
/// let m = c.borrow();
|
|
|
|
/// assert!(c.try_borrow().is_ok());
|
|
|
|
/// }
|
|
|
|
/// ```
|
2020-02-10 08:30:48 +00:00
|
|
|
pub fn try_borrow(&self) -> Result<PyRef<'_, T>, PyBorrowError> {
|
2020-02-15 04:42:25 +00:00
|
|
|
let flag = self.inner.get_borrow_flag();
|
2020-02-15 15:24:38 +00:00
|
|
|
if flag == BorrowFlag::HAS_MUTABLE_BORROW {
|
2020-02-10 08:30:48 +00:00
|
|
|
Err(PyBorrowError { _private: () })
|
|
|
|
} else {
|
2020-02-15 04:42:25 +00:00
|
|
|
self.inner.set_borrow_flag(flag.increment());
|
|
|
|
Ok(PyRef { inner: &self.inner })
|
2020-02-10 08:30:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-22 14:38:01 +00:00
|
|
|
/// Mutably borrows the value `T`, returning an error if the value is currently borrowed.
|
|
|
|
/// This borrow lasts untill the returned `PyRefMut` exists.
|
|
|
|
///
|
|
|
|
/// This is the non-panicking variant of [`borrow_mut`](#method.borrow_mut).
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use pyo3::prelude::*;
|
|
|
|
/// #[pyclass]
|
|
|
|
/// struct Class {}
|
|
|
|
/// let gil = Python::acquire_gil();
|
|
|
|
/// let py = gil.python();
|
|
|
|
/// let c = PyCell::new(py, Class {}).unwrap();
|
|
|
|
/// {
|
|
|
|
/// let m = c.borrow();
|
|
|
|
/// assert!(c.try_borrow_mut().is_err());
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// assert!(c.try_borrow_mut().is_ok());
|
|
|
|
/// ```
|
2020-02-10 08:30:48 +00:00
|
|
|
pub fn try_borrow_mut(&self) -> Result<PyRefMut<'_, T>, PyBorrowMutError> {
|
2020-02-15 04:42:25 +00:00
|
|
|
if self.inner.get_borrow_flag() != BorrowFlag::UNUSED {
|
2020-02-10 08:30:48 +00:00
|
|
|
Err(PyBorrowMutError { _private: () })
|
|
|
|
} else {
|
2020-02-15 04:42:25 +00:00
|
|
|
self.inner.set_borrow_flag(BorrowFlag::HAS_MUTABLE_BORROW);
|
|
|
|
Ok(PyRefMut { inner: &self.inner })
|
2020-02-09 07:36:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-22 14:38:01 +00:00
|
|
|
/// Immutably borrows the value `T`, returning an error if the value is
|
|
|
|
/// currently mutably borrowed.
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// This method is unsafe because it does not return a `PyRef`,
|
|
|
|
/// thus leaving the borrow flag untouched. Mutably borrowing the `PyCell`
|
|
|
|
/// while the reference returned by this method is alive is undefined behaviour.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use pyo3::prelude::*;
|
|
|
|
/// #[pyclass]
|
|
|
|
/// struct Class {}
|
|
|
|
/// let gil = Python::acquire_gil();
|
|
|
|
/// let py = gil.python();
|
|
|
|
/// let c = PyCell::new(py, Class {}).unwrap();
|
|
|
|
///
|
|
|
|
/// {
|
|
|
|
/// let m = c.borrow_mut();
|
|
|
|
/// assert!(unsafe { c.try_borrow_unguarded() }.is_err());
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// {
|
|
|
|
/// let m = c.borrow();
|
|
|
|
/// assert!(unsafe { c.try_borrow_unguarded() }.is_ok());
|
|
|
|
/// }
|
|
|
|
/// ```
|
2020-02-09 07:36:32 +00:00
|
|
|
pub unsafe fn try_borrow_unguarded(&self) -> Result<&T, PyBorrowError> {
|
2020-02-15 15:24:38 +00:00
|
|
|
if self.inner.get_borrow_flag() == BorrowFlag::HAS_MUTABLE_BORROW {
|
2020-02-10 08:30:48 +00:00
|
|
|
Err(PyBorrowError { _private: () })
|
|
|
|
} else {
|
2020-02-15 04:42:25 +00:00
|
|
|
Ok(&*self.inner.value.get())
|
2020-02-10 08:30:48 +00:00
|
|
|
}
|
2020-02-09 07:36:32 +00:00
|
|
|
}
|
|
|
|
|
2020-02-22 14:38:01 +00:00
|
|
|
/// Replaces the wrapped value with a new one, returning the old value,
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// Panics if the value is currently borrowed.
|
|
|
|
#[inline]
|
|
|
|
pub fn replace(&self, t: T) -> T {
|
|
|
|
std::mem::replace(&mut *self.borrow_mut(), t)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Replaces the wrapped value with a new one computed from `f`, returning the old value.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// Panics if the value is currently borrowed.
|
|
|
|
pub fn replace_with<F: FnOnce(&mut T) -> T>(&self, f: F) -> T {
|
|
|
|
let mut_borrow = &mut *self.borrow_mut();
|
|
|
|
let replacement = f(mut_borrow);
|
|
|
|
std::mem::replace(mut_borrow, replacement)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Swaps the wrapped value of `self` with the wrapped value of `other`.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// Panics if the value in either `PyCell` is currently borrowed.
|
|
|
|
#[inline]
|
|
|
|
pub fn swap(&self, other: &Self) {
|
|
|
|
std::mem::swap(&mut *self.borrow_mut(), &mut *other.borrow_mut())
|
2020-02-03 13:25:16 +00:00
|
|
|
}
|
|
|
|
|
2020-02-22 15:56:58 +00:00
|
|
|
/// Allocates new PyCell without initilizing value.
|
2020-02-28 07:49:25 +00:00
|
|
|
/// Requires `T::BaseLayout: PyBorrowFlagLayout<T::BaseType>` to ensure `self` has a borrow flag.
|
2020-02-03 13:25:16 +00:00
|
|
|
pub(crate) unsafe fn internal_new(py: Python) -> PyResult<*mut Self>
|
|
|
|
where
|
2020-02-22 15:56:58 +00:00
|
|
|
T::BaseLayout: PyBorrowFlagLayout<T::BaseType>,
|
2020-02-03 13:25:16 +00:00
|
|
|
{
|
|
|
|
let base = T::alloc(py);
|
|
|
|
if base.is_null() {
|
|
|
|
return Err(PyErr::fetch(py));
|
|
|
|
}
|
2020-02-15 04:42:25 +00:00
|
|
|
let base = base as *mut PyCellBase<T::BaseNativeType>;
|
|
|
|
(*base).borrow_flag = Cell::new(BorrowFlag::UNUSED);
|
2020-02-03 13:25:16 +00:00
|
|
|
let self_ = base as *mut Self;
|
|
|
|
(*self_).dict = T::Dict::new();
|
|
|
|
(*self_).weakref = T::WeakRef::new();
|
|
|
|
Ok(self_)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-22 15:56:58 +00:00
|
|
|
unsafe impl<T: PyClass> PyLayout<T> for PyCell<T> {
|
2020-02-03 13:25:16 +00:00
|
|
|
const IS_NATIVE_TYPE: bool = false;
|
2020-03-01 03:58:28 +00:00
|
|
|
fn get_super(&mut self) -> Option<&mut T::BaseLayout> {
|
2020-02-15 04:42:25 +00:00
|
|
|
Some(&mut self.inner.ob_base)
|
2020-02-10 08:30:48 +00:00
|
|
|
}
|
2020-02-09 07:36:32 +00:00
|
|
|
unsafe fn py_init(&mut self, value: T) {
|
2020-02-15 04:42:25 +00:00
|
|
|
self.inner.value = ManuallyDrop::new(UnsafeCell::new(value));
|
2020-02-09 07:36:32 +00:00
|
|
|
}
|
2020-02-03 13:25:16 +00:00
|
|
|
unsafe fn py_drop(&mut self, py: Python) {
|
2020-02-15 04:42:25 +00:00
|
|
|
ManuallyDrop::drop(&mut self.inner.value);
|
2020-02-03 13:25:16 +00:00
|
|
|
self.dict.clear_dict(py);
|
|
|
|
self.weakref.clear_weakrefs(self.as_ptr(), py);
|
2020-02-15 04:42:25 +00:00
|
|
|
self.inner.ob_base.py_drop(py);
|
2020-02-03 13:25:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-15 15:24:38 +00:00
|
|
|
unsafe impl<T: PyClass> PyDowncastImpl for PyCell<T> {
|
|
|
|
unsafe fn unchecked_downcast(obj: &PyAny) -> &Self {
|
2020-02-09 07:35:52 +00:00
|
|
|
&*(obj.as_ptr() as *const Self)
|
|
|
|
}
|
|
|
|
private_impl! {}
|
|
|
|
}
|
|
|
|
|
2020-02-03 13:25:16 +00:00
|
|
|
impl<T: PyClass> AsPyPointer for PyCell<T> {
|
|
|
|
fn as_ptr(&self) -> *mut ffi::PyObject {
|
2020-02-15 15:24:38 +00:00
|
|
|
self.inner.as_ptr()
|
2020-02-03 13:25:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: PyClass> ToPyObject for &PyCell<T> {
|
|
|
|
fn to_object(&self, py: Python<'_>) -> PyObject {
|
|
|
|
unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-15 15:24:38 +00:00
|
|
|
impl<T: PyClass + fmt::Debug> fmt::Debug for PyCell<T> {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
match self.try_borrow() {
|
|
|
|
Ok(borrow) => f.debug_struct("RefCell").field("value", &borrow).finish(),
|
|
|
|
Err(_) => {
|
|
|
|
struct BorrowedPlaceholder;
|
|
|
|
impl fmt::Debug for BorrowedPlaceholder {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
f.write_str("<borrowed>")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
f.debug_struct("RefCell")
|
|
|
|
.field("value", &BorrowedPlaceholder)
|
|
|
|
.finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-21 12:12:32 +00:00
|
|
|
/// Wraps a borrowed reference to a value in a `PyCell<T>`.
|
|
|
|
///
|
|
|
|
/// See the [`PyCell`](struct.PyCell.html) documentation for more.
|
|
|
|
/// # Example
|
|
|
|
/// You can use `PyRef` as an alternative of `&self` receiver when
|
|
|
|
/// - You need to access the pointer of `PyCell`.
|
|
|
|
/// - You want to get super class.
|
|
|
|
/// ```
|
|
|
|
/// # use pyo3::prelude::*;
|
|
|
|
/// #[pyclass]
|
|
|
|
/// struct Parent {
|
|
|
|
/// basename: &'static str,
|
|
|
|
/// }
|
|
|
|
/// #[pyclass(extends=Parent)]
|
|
|
|
/// struct Child {
|
|
|
|
/// name: &'static str,
|
|
|
|
/// }
|
|
|
|
/// #[pymethods]
|
|
|
|
/// impl Child {
|
|
|
|
/// #[new]
|
|
|
|
/// fn new() -> (Self, Parent) {
|
|
|
|
/// (Child { name: "Caterpillar" }, Parent { basename: "Butterfly" })
|
|
|
|
/// }
|
|
|
|
/// fn format(slf: PyRef<Self>) -> String {
|
|
|
|
/// // We can get *mut ffi::PyObject from PyRef
|
|
|
|
/// use pyo3::AsPyPointer;
|
|
|
|
/// let refcnt = unsafe { pyo3::ffi::Py_REFCNT(slf.as_ptr()) };
|
|
|
|
/// // We can get &Self::BaseType by as_ref
|
|
|
|
/// let basename = slf.as_ref().basename;
|
|
|
|
/// format!("{}(base: {}, cnt: {})", slf.name, basename, refcnt)
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// # let gil = Python::acquire_gil();
|
|
|
|
/// # let py = gil.python();
|
|
|
|
/// # let sub = PyCell::new(py, Child::new()).unwrap();
|
|
|
|
/// # pyo3::py_run!(py, sub, "assert sub.format() == 'Caterpillar(base: Butterfly, cnt: 4)'");
|
|
|
|
/// ```
|
2020-02-09 07:36:32 +00:00
|
|
|
pub struct PyRef<'p, T: PyClass> {
|
2020-02-15 04:42:25 +00:00
|
|
|
inner: &'p PyCellInner<T>,
|
2020-02-09 07:36:32 +00:00
|
|
|
}
|
|
|
|
|
2020-03-02 09:42:04 +00:00
|
|
|
impl<'p, T, U> AsRef<U> for PyRef<'p, T>
|
|
|
|
where
|
|
|
|
T: PyClass + PyTypeInfo<BaseType = U, BaseLayout = PyCellInner<U>>,
|
|
|
|
U: PyClass,
|
|
|
|
{
|
2020-02-21 11:37:35 +00:00
|
|
|
fn as_ref(&self) -> &T::BaseType {
|
2020-02-26 08:19:33 +00:00
|
|
|
unsafe { &*self.inner.ob_base.get_ptr() }
|
2020-02-09 07:36:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-17 15:16:11 +00:00
|
|
|
impl<'p, T, U> PyRef<'p, T>
|
|
|
|
where
|
|
|
|
T: PyClass + PyTypeInfo<BaseType = U, BaseLayout = PyCellInner<U>>,
|
|
|
|
U: PyClass,
|
|
|
|
{
|
2020-02-25 10:56:58 +00:00
|
|
|
/// Get `PyRef<T::BaseType>`.
|
|
|
|
/// You can use this method to get super class of super class.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
/// ```
|
|
|
|
/// # use pyo3::prelude::*;
|
|
|
|
/// #[pyclass]
|
|
|
|
/// struct Base1 {
|
|
|
|
/// name1: &'static str,
|
|
|
|
/// }
|
|
|
|
/// #[pyclass(extends=Base1)]
|
|
|
|
/// struct Base2 {
|
|
|
|
/// name2: &'static str,
|
|
|
|
/// }
|
|
|
|
/// #[pyclass(extends=Base2)]
|
|
|
|
/// struct Sub {
|
|
|
|
/// name3: &'static str,
|
|
|
|
/// }
|
|
|
|
/// #[pymethods]
|
|
|
|
/// impl Sub {
|
|
|
|
/// #[new]
|
|
|
|
/// fn new() -> PyClassInitializer<Self> {
|
|
|
|
/// PyClassInitializer::from(Base1{ name1: "base1" })
|
|
|
|
/// .add_subclass(Base2 { name2: "base2" })
|
|
|
|
/// .add_subclass(Self { name3: "sub" })
|
|
|
|
/// }
|
|
|
|
/// fn name(slf: PyRef<Self>) -> String {
|
|
|
|
/// let subname = slf.name3;
|
|
|
|
/// let super_ = slf.into_super();
|
|
|
|
/// format!("{} {} {}", super_.as_ref().name1, super_.name2, subname)
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// # let gil = Python::acquire_gil();
|
|
|
|
/// # let py = gil.python();
|
|
|
|
/// # let sub = PyCell::new(py, Sub::new()).unwrap();
|
|
|
|
/// # pyo3::py_run!(py, sub, "assert sub.name() == 'base1 base2 sub'")
|
|
|
|
/// ```
|
2020-02-17 15:16:11 +00:00
|
|
|
pub fn into_super(self) -> PyRef<'p, U> {
|
2020-02-18 03:52:41 +00:00
|
|
|
let PyRef { inner } = self;
|
|
|
|
std::mem::forget(self);
|
|
|
|
PyRef {
|
|
|
|
inner: &inner.ob_base,
|
|
|
|
}
|
2020-02-17 15:16:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-09 07:36:32 +00:00
|
|
|
impl<'p, T: PyClass> Deref for PyRef<'p, T> {
|
|
|
|
type Target = T;
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn deref(&self) -> &T {
|
2020-02-26 08:19:33 +00:00
|
|
|
unsafe { &*self.inner.get_ptr() }
|
2020-02-09 07:36:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'p, T: PyClass> Drop for PyRef<'p, T> {
|
|
|
|
fn drop(&mut self) {
|
2020-02-15 04:42:25 +00:00
|
|
|
let flag = self.inner.get_borrow_flag();
|
|
|
|
self.inner.set_borrow_flag(flag.decrement())
|
2020-02-09 07:36:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-15 15:24:38 +00:00
|
|
|
impl<'p, T: PyClass> FromPy<PyRef<'p, T>> for PyObject {
|
|
|
|
fn from_py(pyref: PyRef<'p, T>, py: Python<'_>) -> PyObject {
|
|
|
|
unsafe { PyObject::from_borrowed_ptr(py, pyref.inner.as_ptr()) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, T: PyClass> std::convert::TryFrom<&'a PyCell<T>> for crate::PyRef<'a, T> {
|
|
|
|
type Error = PyBorrowError;
|
|
|
|
fn try_from(cell: &'a crate::PyCell<T>) -> Result<Self, Self::Error> {
|
|
|
|
cell.try_borrow()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, T: PyClass> AsPyPointer for PyRef<'a, T> {
|
|
|
|
fn as_ptr(&self) -> *mut ffi::PyObject {
|
|
|
|
self.inner.as_ptr()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: PyClass + fmt::Debug> fmt::Debug for PyRef<'_, T> {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
fmt::Debug::fmt(&**self, f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-21 12:12:32 +00:00
|
|
|
/// Wraps a mutable borrowed reference to a value in a `PyCell<T>`.
|
|
|
|
///
|
|
|
|
/// See the [`PyCell`](struct.PyCell.html) and [`PyRef`](struct.PyRef.html) documentations for more.
|
2020-02-09 07:36:32 +00:00
|
|
|
pub struct PyRefMut<'p, T: PyClass> {
|
2020-02-15 04:42:25 +00:00
|
|
|
inner: &'p PyCellInner<T>,
|
2020-02-09 07:36:32 +00:00
|
|
|
}
|
|
|
|
|
2020-03-02 09:42:04 +00:00
|
|
|
impl<'p, T, U> AsRef<U> for PyRefMut<'p, T>
|
|
|
|
where
|
|
|
|
T: PyClass + PyTypeInfo<BaseType = U, BaseLayout = PyCellInner<U>>,
|
|
|
|
U: PyClass,
|
|
|
|
{
|
2020-02-21 11:37:35 +00:00
|
|
|
fn as_ref(&self) -> &T::BaseType {
|
2020-02-26 08:19:33 +00:00
|
|
|
unsafe { &*self.inner.ob_base.get_ptr() }
|
2020-02-10 08:30:48 +00:00
|
|
|
}
|
2020-02-21 11:37:35 +00:00
|
|
|
}
|
|
|
|
|
2020-03-02 09:42:04 +00:00
|
|
|
impl<'p, T, U> AsMut<U> for PyRefMut<'p, T>
|
|
|
|
where
|
|
|
|
T: PyClass + PyTypeInfo<BaseType = U, BaseLayout = PyCellInner<U>>,
|
|
|
|
U: PyClass,
|
|
|
|
{
|
2020-02-21 11:37:35 +00:00
|
|
|
fn as_mut(&mut self) -> &mut T::BaseType {
|
2020-02-26 08:19:33 +00:00
|
|
|
unsafe { &mut *self.inner.ob_base.get_ptr() }
|
2020-02-10 08:30:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-17 15:16:11 +00:00
|
|
|
impl<'p, T, U> PyRefMut<'p, T>
|
|
|
|
where
|
|
|
|
T: PyClass + PyTypeInfo<BaseType = U, BaseLayout = PyCellInner<U>>,
|
|
|
|
U: PyClass,
|
|
|
|
{
|
2020-02-25 10:56:58 +00:00
|
|
|
/// Get `PyRef<T::BaseType>`.
|
|
|
|
/// See [`PyRef::into_super`](struct.PyRef.html#method.into_super) for more.
|
2020-02-17 15:16:11 +00:00
|
|
|
pub fn into_super(self) -> PyRefMut<'p, U> {
|
2020-02-18 03:52:41 +00:00
|
|
|
let PyRefMut { inner } = self;
|
|
|
|
std::mem::forget(self);
|
|
|
|
PyRefMut {
|
|
|
|
inner: &inner.ob_base,
|
|
|
|
}
|
2020-02-17 15:16:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-09 07:36:32 +00:00
|
|
|
impl<'p, T: PyClass> Deref for PyRefMut<'p, T> {
|
|
|
|
type Target = T;
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn deref(&self) -> &T {
|
2020-02-26 08:19:33 +00:00
|
|
|
unsafe { &*self.inner.get_ptr() }
|
2020-02-09 07:36:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'p, T: PyClass> DerefMut for PyRefMut<'p, T> {
|
|
|
|
#[inline]
|
|
|
|
fn deref_mut(&mut self) -> &mut T {
|
2020-02-26 08:19:33 +00:00
|
|
|
unsafe { &mut *self.inner.get_ptr() }
|
2020-02-09 07:36:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'p, T: PyClass> Drop for PyRefMut<'p, T> {
|
|
|
|
fn drop(&mut self) {
|
2020-02-15 04:42:25 +00:00
|
|
|
self.inner.set_borrow_flag(BorrowFlag::UNUSED)
|
2020-02-09 07:36:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-15 15:24:38 +00:00
|
|
|
impl<'p, T: PyClass> FromPy<PyRefMut<'p, T>> for PyObject {
|
|
|
|
fn from_py(pyref: PyRefMut<'p, T>, py: Python<'_>) -> PyObject {
|
|
|
|
unsafe { PyObject::from_borrowed_ptr(py, pyref.inner.as_ptr()) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, T: PyClass> AsPyPointer for PyRefMut<'a, T> {
|
|
|
|
fn as_ptr(&self) -> *mut ffi::PyObject {
|
|
|
|
self.inner.as_ptr()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, T: PyClass> std::convert::TryFrom<&'a PyCell<T>> for crate::PyRefMut<'a, T> {
|
|
|
|
type Error = PyBorrowMutError;
|
|
|
|
fn try_from(cell: &'a crate::PyCell<T>) -> Result<Self, Self::Error> {
|
|
|
|
cell.try_borrow_mut()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: PyClass + fmt::Debug> fmt::Debug for PyRefMut<'_, T> {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
fmt::Debug::fmt(&*(self.deref()), f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-09 07:36:32 +00:00
|
|
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
|
|
|
struct BorrowFlag(usize);
|
|
|
|
|
|
|
|
impl BorrowFlag {
|
|
|
|
const UNUSED: BorrowFlag = BorrowFlag(0);
|
|
|
|
const HAS_MUTABLE_BORROW: BorrowFlag = BorrowFlag(usize::max_value());
|
2020-02-10 08:30:48 +00:00
|
|
|
const fn increment(self) -> Self {
|
|
|
|
Self(self.0 + 1)
|
|
|
|
}
|
|
|
|
const fn decrement(self) -> Self {
|
2020-02-09 07:36:32 +00:00
|
|
|
Self(self.0 - 1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-22 15:56:58 +00:00
|
|
|
/// An error returned by [`PyCell::try_borrow`](struct.PyCell.html#method.try_borrow).
|
2020-02-09 07:36:32 +00:00
|
|
|
pub struct PyBorrowError {
|
|
|
|
_private: (),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Debug for PyBorrowError {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
f.debug_struct("PyBorrowError").finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for PyBorrowError {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
fmt::Display::fmt("Already mutably borrowed", f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-22 15:56:58 +00:00
|
|
|
/// An error returned by [`PyCell::try_borrow_mut`](struct.PyCell.html#method.try_borrow_mut).
|
2020-02-09 07:36:32 +00:00
|
|
|
pub struct PyBorrowMutError {
|
|
|
|
_private: (),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Debug for PyBorrowMutError {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
f.debug_struct("PyBorrowMutError").finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for PyBorrowMutError {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
fmt::Display::fmt("Already borrowed", f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pyo3_exception!(PyBorrowError, crate::exceptions::Exception);
|
|
|
|
pyo3_exception!(PyBorrowMutError, crate::exceptions::Exception);
|