Rename PyClassShell with PyCell

This commit is contained in:
kngwyu 2020-02-03 22:25:16 +09:00
parent 6069ee1239
commit a2408cacbb
19 changed files with 277 additions and 281 deletions

View File

@ -34,7 +34,7 @@ impl pyo3::pyclass::PyClassAlloc for MyClass {}
unsafe impl pyo3::PyTypeInfo for MyClass {
type Type = MyClass;
type BaseType = pyo3::types::PyAny;
type ConcreteLayout = pyo3::PyClassShell<Self>;
type ConcreteLayout = pyo3::PyCell<Self>;
type Initializer = pyo3::PyClassInitializer<Self>;
const NAME: &'static str = "MyClass";
@ -109,19 +109,19 @@ fn mymodule(_py: Python, m: &PyModule) -> PyResult<()> {
You sometimes need to convert your `pyclass` into a Python object in Rust code (e.g., for testing it).
For getting *GIL-bounded* (i.e., with `'py` lifetime) references of `pyclass`,
you can use `PyClassShell<T>`.
you can use `PyCell<T>`.
Or you can use `Py<T>` directly, for *not-GIL-bounded* references.
### `PyClassShell`
`PyClassShell` represents the actual layout of `pyclass` on the Python heap.
### `PyCell`
`PyCell` represents the actual layout of `pyclass` on the Python heap.
If you want to instantiate `pyclass` in Python and get the reference,
you can use `PyClassShell::new_ref` or `PyClassShell::new_mut`.
you can use `PyCell::new_ref` or `PyCell::new_mut`.
```rust
# use pyo3::prelude::*;
# use pyo3::types::PyDict;
# use pyo3::PyClassShell;
# use pyo3::PyCell;
#[pyclass]
struct MyClass {
num: i32,
@ -129,15 +129,15 @@ struct MyClass {
}
let gil = Python::acquire_gil();
let py = gil.python();
let obj = PyClassShell::new_ref(py, MyClass { num: 3, debug: true }).unwrap();
let obj = PyCell::new_ref(py, MyClass { num: 3, debug: true }).unwrap();
// You can use deref
assert_eq!(obj.num, 3);
let dict = PyDict::new(py);
// You can treat a `&PyClassShell` as a normal Python object
// You can treat a `&PyCell` as a normal Python object
dict.set_item("obj", obj).unwrap();
// return &mut PyClassShell<MyClass>
let obj = PyClassShell::new_mut(py, MyClass { num: 3, debug: true }).unwrap();
// return &mut PyCell<MyClass>
let obj = PyCell::new_mut(py, MyClass { num: 3, debug: true }).unwrap();
obj.num = 5;
```
@ -230,7 +230,7 @@ explicitly.
```rust
# use pyo3::prelude::*;
use pyo3::PyClassShell;
use pyo3::PyCell;
#[pyclass]
struct BaseClass {
@ -261,7 +261,7 @@ impl SubClass {
(SubClass{ val2: 15}, BaseClass::new())
}
fn method2(self_: &PyClassShell<Self>) -> PyResult<usize> {
fn method2(self_: &PyCell<Self>) -> PyResult<usize> {
self_.get_super().method().map(|x| x * self_.val2)
}
}
@ -279,7 +279,7 @@ impl SubSubClass {
.add_subclass(SubSubClass{val3: 20})
}
fn method3(self_: &PyClassShell<Self>) -> PyResult<usize> {
fn method3(self_: &PyCell<Self>) -> PyResult<usize> {
let super_ = self_.get_super();
SubClass::method2(super_).map(|x| x * self_.val3)
}
@ -288,20 +288,20 @@ impl SubSubClass {
# let gil = Python::acquire_gil();
# let py = gil.python();
# let subsub = pyo3::PyClassShell::new_ref(py, SubSubClass::new()).unwrap();
# let subsub = pyo3::PyCell::new_ref(py, SubSubClass::new()).unwrap();
# pyo3::py_run!(py, subsub, "assert subsub.method3() == 3000")
```
To access the super class, you can use either of these two ways:
- Use `self_: &PyClassShell<Self>` instead of `self`, and call `get_super()`
- Use `self_: &PyCell<Self>` instead of `self`, and call `get_super()`
- `ObjectProtocol::get_base`
We recommend `PyClassShell` here, since it makes the context much clearer.
We recommend `PyCell` here, since it makes the context much clearer.
If `SubClass` does not provide a baseclass initialization, the compilation fails.
```compile_fail
# use pyo3::prelude::*;
use pyo3::PyClassShell;
use pyo3::PyCell;
#[pyclass]
struct BaseClass {
@ -761,8 +761,8 @@ struct GCTracked {} // Fails because it does not implement PyGCProtocol
Iterators can be defined using the
[`PyIterProtocol`](https://docs.rs/pyo3/latest/pyo3/class/iter/trait.PyIterProtocol.html) trait.
It includes two methods `__iter__` and `__next__`:
* `fn __iter__(slf: &mut PyClassShell<Self>) -> PyResult<impl IntoPy<PyObject>>`
* `fn __next__(slf: &mut PyClassShell<Self>) -> PyResult<Option<impl IntoPy<PyObject>>>`
* `fn __iter__(slf: &mut PyCell<Self>) -> PyResult<impl IntoPy<PyObject>>`
* `fn __next__(slf: &mut PyCell<Self>) -> PyResult<Option<impl IntoPy<PyObject>>>`
Returning `Ok(None)` from `__next__` indicates that that there are no further items.
@ -770,7 +770,7 @@ Example:
```rust
use pyo3::prelude::*;
use pyo3::{PyIterProtocol, PyClassShell};
use pyo3::{PyIterProtocol, PyCell};
#[pyclass]
struct MyIterator {
@ -779,10 +779,10 @@ struct MyIterator {
#[pyproto]
impl PyIterProtocol for MyIterator {
fn __iter__(slf: &mut PyClassShell<Self>) -> PyResult<Py<MyIterator>> {
fn __iter__(slf: &mut PyCell<Self>) -> PyResult<Py<MyIterator>> {
Ok(slf.into())
}
fn __next__(slf: &mut PyClassShell<Self>) -> PyResult<Option<PyObject>> {
fn __next__(slf: &mut PyCell<Self>) -> PyResult<Option<PyObject>> {
Ok(slf.iter.next())
}
}

View File

@ -36,7 +36,7 @@ your Python extensions quickly.
```rust
use pyo3::prelude::*;
use pyo3::{PyClassShell, PyObjectProtocol, py_run};
use pyo3::{PyCell, PyObjectProtocol, py_run};
# fn main() {
#[pyclass]
struct UserData {
@ -61,7 +61,7 @@ let userdata = UserData {
id: 34,
name: "Yu".to_string(),
};
let userdata = PyClassShell::new_ref(py, userdata).unwrap();
let userdata = PyCell::new_ref(py, userdata).unwrap();
let userdata_as_tuple = (34, "Yu");
py_run!(py, userdata userdata_as_tuple, r#"
assert repr(userdata) == "User Yu(id: 34)"

View File

@ -373,7 +373,7 @@ fn impl_class(
unsafe impl pyo3::type_object::PyTypeInfo for #cls {
type Type = #cls;
type BaseType = #base;
type ConcreteLayout = pyo3::pyclass::PyClassShell<Self>;
type ConcreteLayout = pyo3::pyclass::PyCell<Self>;
type Initializer = pyo3::pyclass_init::PyClassInitializer<Self>;
const NAME: &'static str = #cls_name;

View File

@ -175,7 +175,7 @@ pub fn impl_wrap_new(cls: &syn::Type, spec: &FnSpec<'_>) -> TokenStream {
#body
match _result.and_then(|init| pyo3::PyClassInitializer::from(init).create_shell(_py)) {
match _result.and_then(|init| pyo3::PyClassInitializer::from(init).create_cell(_py)) {
Ok(slf) => slf as _,
Err(e) => e.restore_and_null(_py),
}

View File

@ -4,8 +4,7 @@
use crate::callback::{CallbackConverter, PyObjectCallbackConverter};
use crate::err::PyResult;
use crate::{ffi, pyclass::PyClassShell, IntoPy, PyClass, PyObject};
use crate::{IntoPyPointer, Python};
use crate::{ffi, IntoPy, IntoPyPointer, PyCell, PyClass, PyObject, Python};
use std::ptr;
/// Python Iterator Interface.
@ -14,14 +13,14 @@ use std::ptr;
/// `https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_iter`
#[allow(unused_variables)]
pub trait PyIterProtocol<'p>: PyClass {
fn __iter__(slf: &mut PyClassShell<Self>) -> Self::Result
fn __iter__(slf: &mut PyCell<Self>) -> Self::Result
where
Self: PyIterIterProtocol<'p>,
{
unimplemented!()
}
fn __next__(slf: &mut PyClassShell<Self>) -> Self::Result
fn __next__(slf: &mut PyCell<Self>) -> Self::Result
where
Self: PyIterNextProtocol<'p>,
{

View File

@ -35,10 +35,10 @@ macro_rules! py_unary_pyref_func {
where
T: for<'p> $trait<'p>,
{
use $crate::pyclass::PyClassShell;
use $crate::PyCell;
let py = $crate::Python::assume_gil_acquired();
let _pool = $crate::GILPool::new(py);
let slf: &mut PyClassShell<T> = &mut *(slf as *mut PyClassShell<T>);
let slf: &mut PyCell<T> = &mut *(slf as *mut PyCell<T>);
let res = $class::$f(slf).into();
$crate::callback::cb_convert($conv, py, res)
}

View File

@ -3,12 +3,12 @@ use crate::err::{PyErr, PyResult};
use crate::gil;
use crate::object::PyObject;
use crate::objectprotocol::ObjectProtocol;
use crate::pyclass::{PyClass, PyClassShell};
use crate::pyclass_init::PyClassInitializer;
use crate::type_object::{PyObjectLayout, PyTypeInfo};
use crate::types::PyAny;
use crate::{ffi, IntoPy};
use crate::{AsPyPointer, FromPyObject, IntoPyPointer, Python, ToPyObject};
use crate::{
ffi, AsPyPointer, FromPyObject, IntoPy, IntoPyPointer, PyCell, PyClass, PyClassInitializer,
Python, ToPyObject,
};
use std::marker::PhantomData;
use std::mem;
use std::ptr::NonNull;
@ -43,7 +43,7 @@ impl<T> Py<T> {
crate::type_object::PyObjectSizedLayout<T::BaseType>,
{
let initializer = value.into();
let obj = unsafe { initializer.create_shell(py)? };
let obj = unsafe { initializer.create_cell(py)? };
let ob = unsafe { Py::from_owned_ptr(obj as _) };
Ok(ob)
}
@ -174,22 +174,22 @@ where
}
}
// `&PyClassShell<T>` can be converted to `Py<T>`
impl<'a, T> std::convert::From<&PyClassShell<T>> for Py<T>
// `&PyCell<T>` can be converted to `Py<T>`
impl<'a, T> std::convert::From<&PyCell<T>> for Py<T>
where
T: PyClass,
{
fn from(shell: &PyClassShell<T>) -> Self {
unsafe { Py::from_borrowed_ptr(shell.as_ptr()) }
fn from(cell: &PyCell<T>) -> Self {
unsafe { Py::from_borrowed_ptr(cell.as_ptr()) }
}
}
impl<'a, T> std::convert::From<&mut PyClassShell<T>> for Py<T>
impl<'a, T> std::convert::From<&mut PyCell<T>> for Py<T>
where
T: PyClass,
{
fn from(shell: &mut PyClassShell<T>) -> Self {
unsafe { Py::from_borrowed_ptr(shell.as_ptr()) }
fn from(cell: &mut PyCell<T>) -> Self {
unsafe { Py::from_borrowed_ptr(cell.as_ptr()) }
}
}

View File

@ -127,7 +127,8 @@ pub use crate::gil::{init_once, GILGuard, GILPool};
pub use crate::instance::{AsPyRef, ManagedPyRef, Py, PyNativeType};
pub use crate::object::PyObject;
pub use crate::objectprotocol::ObjectProtocol;
pub use crate::pyclass::{PyClass, PyClassShell};
pub use crate::pycell::PyCell;
pub use crate::pyclass::PyClass;
pub use crate::pyclass_init::PyClassInitializer;
pub use crate::python::{prepare_freethreaded_python, Python};
pub use crate::type_object::{type_flags, PyTypeInfo};
@ -170,6 +171,7 @@ pub mod marshal;
mod object;
mod objectprotocol;
pub mod prelude;
mod pycell;
pub mod pyclass;
pub mod pyclass_init;
pub mod pyclass_slots;
@ -221,7 +223,7 @@ macro_rules! wrap_pymodule {
///
/// # Example
/// ```
/// use pyo3::{prelude::*, py_run, PyClassShell};
/// use pyo3::{prelude::*, py_run, PyCell};
/// #[pyclass]
/// #[derive(Debug)]
/// struct Time {
@ -244,7 +246,7 @@ macro_rules! wrap_pymodule {
/// }
/// let gil = Python::acquire_gil();
/// let py = gil.python();
/// let time = PyClassShell::new_ref(py, Time {hour: 8, minute: 43, second: 16}).unwrap();
/// let time = PyCell::new_ref(py, Time {hour: 8, minute: 43, second: 16}).unwrap();
/// let time_as_tuple = (8, 43, 16);
/// py_run!(py, time time_as_tuple, r#"
/// assert time.hour == 8

177
src/pycell.rs Normal file
View File

@ -0,0 +1,177 @@
//! Traits and structs for `#[pyclass]`.
use crate::conversion::{AsPyPointer, FromPyPointer, ToPyObject};
use crate::pyclass::PyClass;
use crate::pyclass_init::PyClassInitializer;
use crate::pyclass_slots::{PyClassDict, PyClassWeakRef};
use crate::type_object::{PyObjectLayout, PyObjectSizedLayout};
use crate::types::PyAny;
use crate::{ffi, gil, PyErr, PyObject, PyResult, PyTypeInfo, Python};
use std::mem::ManuallyDrop;
use std::ptr::NonNull;
/// `PyCell` represents the concrete layout of `T: PyClass` when it is converted
/// to a Python class.
///
/// You can use it to test your `#[pyclass]` correctly works.
///
/// ```
/// # use pyo3::prelude::*;
/// # use pyo3::{py_run, PyCell};
/// #[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",
/// };
/// let book_cell = PyCell::new_ref(py, book).unwrap();
/// py_run!(py, book_cell, "assert book_cell.name[-6:] == 'Castle'");
/// ```
#[repr(C)]
pub struct PyCell<T: PyClass> {
ob_base: <T::BaseType as PyTypeInfo>::ConcreteLayout,
pyclass: ManuallyDrop<T>,
dict: T::Dict,
weakref: T::WeakRef,
}
impl<T: PyClass> PyCell<T> {
/// Make new `PyCell` on the Python heap and returns the reference of it.
pub fn new_ref(py: Python, value: impl Into<PyClassInitializer<T>>) -> PyResult<&Self>
where
<T::BaseType as PyTypeInfo>::ConcreteLayout:
crate::type_object::PyObjectSizedLayout<T::BaseType>,
{
unsafe {
let initializer = value.into();
let self_ = initializer.create_cell(py)?;
FromPyPointer::from_owned_ptr_or_err(py, self_ as _)
}
}
/// Make new `PyCell` on the Python heap and returns the mutable reference of it.
pub fn new_mut(py: Python, value: impl Into<PyClassInitializer<T>>) -> PyResult<&mut Self>
where
<T::BaseType as PyTypeInfo>::ConcreteLayout:
crate::type_object::PyObjectSizedLayout<T::BaseType>,
{
unsafe {
let initializer = value.into();
let self_ = initializer.create_cell(py)?;
FromPyPointer::from_owned_ptr_or_err(py, self_ as _)
}
}
/// Get the reference of base object.
pub fn get_super(&self) -> &<T::BaseType as PyTypeInfo>::ConcreteLayout {
&self.ob_base
}
/// Get the mutable reference of base object.
pub fn get_super_mut(&mut self) -> &mut <T::BaseType as PyTypeInfo>::ConcreteLayout {
&mut self.ob_base
}
pub(crate) unsafe fn internal_new(py: Python) -> PyResult<*mut Self>
where
<T::BaseType as PyTypeInfo>::ConcreteLayout:
crate::type_object::PyObjectSizedLayout<T::BaseType>,
{
let base = T::alloc(py);
if base.is_null() {
return Err(PyErr::fetch(py));
}
let self_ = base as *mut Self;
(*self_).dict = T::Dict::new();
(*self_).weakref = T::WeakRef::new();
Ok(self_)
}
}
impl<T: PyClass> PyObjectLayout<T> for PyCell<T> {
const IS_NATIVE_TYPE: bool = false;
fn get_super_or(&mut self) -> Option<&mut <T::BaseType as PyTypeInfo>::ConcreteLayout> {
Some(&mut self.ob_base)
}
unsafe fn internal_ref_cast(obj: &PyAny) -> &T {
let cell = obj.as_ptr() as *const Self;
&(*cell).pyclass
}
unsafe fn internal_mut_cast(obj: &PyAny) -> &mut T {
let cell = obj.as_ptr() as *const _ as *mut Self;
&mut (*cell).pyclass
}
unsafe fn py_drop(&mut self, py: Python) {
ManuallyDrop::drop(&mut self.pyclass);
self.dict.clear_dict(py);
self.weakref.clear_weakrefs(self.as_ptr(), py);
self.ob_base.py_drop(py);
}
unsafe fn py_init(&mut self, value: T) {
self.pyclass = ManuallyDrop::new(value);
}
}
impl<T: PyClass> PyObjectSizedLayout<T> for PyCell<T> {}
impl<T: PyClass> AsPyPointer for PyCell<T> {
fn as_ptr(&self) -> *mut ffi::PyObject {
(self as *const _) as *mut _
}
}
impl<T: PyClass> std::ops::Deref for PyCell<T> {
type Target = T;
fn deref(&self) -> &T {
self.pyclass.deref()
}
}
impl<T: PyClass> std::ops::DerefMut for PyCell<T> {
fn deref_mut(&mut self) -> &mut T {
self.pyclass.deref_mut()
}
}
impl<T: PyClass> ToPyObject for &PyCell<T> {
fn to_object(&self, py: Python<'_>) -> PyObject {
unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) }
}
}
impl<T: PyClass> ToPyObject for &mut PyCell<T> {
fn to_object(&self, py: Python<'_>) -> PyObject {
unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) }
}
}
unsafe impl<'p, T> FromPyPointer<'p> for &'p PyCell<T>
where
T: PyClass,
{
unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> {
NonNull::new(ptr).map(|p| &*(gil::register_owned(py, p).as_ptr() as *const PyCell<T>))
}
unsafe fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> {
NonNull::new(ptr).map(|p| &*(gil::register_borrowed(py, p).as_ptr() as *const PyCell<T>))
}
}
unsafe impl<'p, T> FromPyPointer<'p> for &'p mut PyCell<T>
where
T: PyClass,
{
unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> {
NonNull::new(ptr)
.map(|p| &mut *(gil::register_owned(py, p).as_ptr() as *const _ as *mut PyCell<T>))
}
unsafe fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> {
NonNull::new(ptr)
.map(|p| &mut *(gil::register_borrowed(py, p).as_ptr() as *const _ as *mut PyCell<T>))
}
}

View File

@ -1,15 +1,11 @@
//! Traits and structs for `#[pyclass]`.
//! `PyClass` trait
use crate::class::methods::{PyMethodDefType, PyMethodsProtocol};
use crate::conversion::{AsPyPointer, FromPyPointer, ToPyObject};
use crate::pyclass_init::PyClassInitializer;
use crate::pyclass_slots::{PyClassDict, PyClassWeakRef};
use crate::type_object::{type_flags, PyObjectLayout, PyObjectSizedLayout};
use crate::types::PyAny;
use crate::{class, ffi, gil, PyErr, PyObject, PyResult, PyTypeInfo, Python};
use crate::type_object::{type_flags, PyObjectLayout};
use crate::{class, ffi, gil, PyCell, PyErr, PyResult, PyTypeInfo, Python};
use std::ffi::CString;
use std::mem::ManuallyDrop;
use std::os::raw::c_void;
use std::ptr::{self, NonNull};
use std::ptr;
#[inline]
pub(crate) unsafe fn default_alloc<T: PyTypeInfo>() -> *mut ffi::PyObject {
@ -71,187 +67,17 @@ pub unsafe fn tp_free_fallback(obj: *mut ffi::PyObject) {
}
/// If `PyClass` is implemented for `T`, then we can use `T` in the Python world,
/// via `PyClassShell`.
/// via `PyCell`.
///
/// 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<ConcreteLayout = PyClassShell<Self>> + Sized + PyClassAlloc + PyMethodsProtocol
PyTypeInfo<ConcreteLayout = PyCell<Self>> + Sized + PyClassAlloc + PyMethodsProtocol
{
type Dict: PyClassDict;
type WeakRef: PyClassWeakRef;
}
/// `PyClassShell` represents the concrete layout of `T: PyClass` when it is converted
/// to a Python class.
///
/// You can use it to test your `#[pyclass]` correctly works.
///
/// ```
/// # use pyo3::prelude::*;
/// # use pyo3::{py_run, PyClassShell};
/// #[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",
/// };
/// let book_shell = PyClassShell::new_ref(py, book).unwrap();
/// py_run!(py, book_shell, "assert book_shell.name[-6:] == 'Castle'");
/// ```
#[repr(C)]
pub struct PyClassShell<T: PyClass> {
ob_base: <T::BaseType as PyTypeInfo>::ConcreteLayout,
pyclass: ManuallyDrop<T>,
dict: T::Dict,
weakref: T::WeakRef,
}
impl<T: PyClass> PyClassShell<T> {
/// Make new `PyClassShell` on the Python heap and returns the reference of it.
pub fn new_ref(py: Python, value: impl Into<PyClassInitializer<T>>) -> PyResult<&Self>
where
<T::BaseType as PyTypeInfo>::ConcreteLayout:
crate::type_object::PyObjectSizedLayout<T::BaseType>,
{
unsafe {
let initializer = value.into();
let self_ = initializer.create_shell(py)?;
FromPyPointer::from_owned_ptr_or_err(py, self_ as _)
}
}
/// Make new `PyClassShell` on the Python heap and returns the mutable reference of it.
pub fn new_mut(py: Python, value: impl Into<PyClassInitializer<T>>) -> PyResult<&mut Self>
where
<T::BaseType as PyTypeInfo>::ConcreteLayout:
crate::type_object::PyObjectSizedLayout<T::BaseType>,
{
unsafe {
let initializer = value.into();
let self_ = initializer.create_shell(py)?;
FromPyPointer::from_owned_ptr_or_err(py, self_ as _)
}
}
/// Get the reference of base object.
pub fn get_super(&self) -> &<T::BaseType as PyTypeInfo>::ConcreteLayout {
&self.ob_base
}
/// Get the mutable reference of base object.
pub fn get_super_mut(&mut self) -> &mut <T::BaseType as PyTypeInfo>::ConcreteLayout {
&mut self.ob_base
}
pub(crate) unsafe fn new(py: Python) -> PyResult<*mut Self>
where
<T::BaseType as PyTypeInfo>::ConcreteLayout:
crate::type_object::PyObjectSizedLayout<T::BaseType>,
{
let base = T::alloc(py);
if base.is_null() {
return Err(PyErr::fetch(py));
}
let self_ = base as *mut Self;
(*self_).dict = T::Dict::new();
(*self_).weakref = T::WeakRef::new();
Ok(self_)
}
}
impl<T: PyClass> PyObjectLayout<T> for PyClassShell<T> {
const IS_NATIVE_TYPE: bool = false;
fn get_super_or(&mut self) -> Option<&mut <T::BaseType as PyTypeInfo>::ConcreteLayout> {
Some(&mut self.ob_base)
}
unsafe fn internal_ref_cast(obj: &PyAny) -> &T {
let shell = obj.as_ptr() as *const Self;
&(*shell).pyclass
}
unsafe fn internal_mut_cast(obj: &PyAny) -> &mut T {
let shell = obj.as_ptr() as *const _ as *mut Self;
&mut (*shell).pyclass
}
unsafe fn py_drop(&mut self, py: Python) {
ManuallyDrop::drop(&mut self.pyclass);
self.dict.clear_dict(py);
self.weakref.clear_weakrefs(self.as_ptr(), py);
self.ob_base.py_drop(py);
}
unsafe fn py_init(&mut self, value: T) {
self.pyclass = ManuallyDrop::new(value);
}
}
impl<T: PyClass> PyObjectSizedLayout<T> for PyClassShell<T> {}
impl<T: PyClass> AsPyPointer for PyClassShell<T> {
fn as_ptr(&self) -> *mut ffi::PyObject {
(self as *const _) as *mut _
}
}
impl<T: PyClass> std::ops::Deref for PyClassShell<T> {
type Target = T;
fn deref(&self) -> &T {
self.pyclass.deref()
}
}
impl<T: PyClass> std::ops::DerefMut for PyClassShell<T> {
fn deref_mut(&mut self) -> &mut T {
self.pyclass.deref_mut()
}
}
impl<T: PyClass> ToPyObject for &PyClassShell<T> {
fn to_object(&self, py: Python<'_>) -> PyObject {
unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) }
}
}
impl<T: PyClass> ToPyObject for &mut PyClassShell<T> {
fn to_object(&self, py: Python<'_>) -> PyObject {
unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) }
}
}
unsafe impl<'p, T> FromPyPointer<'p> for &'p PyClassShell<T>
where
T: PyClass,
{
unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> {
NonNull::new(ptr).map(|p| &*(gil::register_owned(py, p).as_ptr() as *const PyClassShell<T>))
}
unsafe fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> {
NonNull::new(ptr)
.map(|p| &*(gil::register_borrowed(py, p).as_ptr() as *const PyClassShell<T>))
}
}
unsafe impl<'p, T> FromPyPointer<'p> for &'p mut PyClassShell<T>
where
T: PyClass,
{
unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> {
NonNull::new(ptr).map(|p| {
&mut *(gil::register_owned(py, p).as_ptr() as *const _ as *mut PyClassShell<T>)
})
}
unsafe fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> {
NonNull::new(ptr).map(|p| {
&mut *(gil::register_borrowed(py, p).as_ptr() as *const _ as *mut PyClassShell<T>)
})
}
}
#[cfg(not(Py_LIMITED_API))]
pub(crate) fn initialize_type_object<T>(
py: Python,

View File

@ -1,7 +1,6 @@
//! Initialization utilities for `#[pyclass]`.
use crate::pyclass::{PyClass, PyClassShell};
use crate::type_object::{PyObjectLayout, PyObjectSizedLayout, PyTypeInfo};
use crate::{PyResult, Python};
use crate::{PyCell, PyClass, PyResult, Python};
use std::marker::PhantomData;
/// Initializer for Python types.
@ -9,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 {
fn init_class(self, shell: &mut T::ConcreteLayout);
fn init_class(self, layout: &mut T::ConcreteLayout);
private_decl! {}
}
@ -17,7 +16,7 @@ pub trait PyObjectInit<T: PyTypeInfo>: Sized {
pub struct PyNativeTypeInitializer<T: PyTypeInfo>(PhantomData<T>);
impl<T: PyTypeInfo> PyObjectInit<T> for PyNativeTypeInitializer<T> {
fn init_class(self, _shell: &mut T::ConcreteLayout) {}
fn init_class(self, _layout: &mut T::ConcreteLayout) {}
private_impl! {}
}
@ -115,14 +114,14 @@ impl<T: PyClass> PyClassInitializer<T> {
}
#[doc(hidden)]
pub unsafe fn create_shell(self, py: Python) -> PyResult<*mut PyClassShell<T>>
pub unsafe fn create_cell(self, py: Python) -> PyResult<*mut PyCell<T>>
where
T: PyClass,
<T::BaseType as PyTypeInfo>::ConcreteLayout: PyObjectSizedLayout<T::BaseType>,
{
let shell = PyClassShell::new(py)?;
self.init_class(&mut *shell);
Ok(shell)
let cell = PyCell::internal_new(py)?;
self.init_class(&mut *cell);
Ok(cell)
}
}

View File

@ -11,7 +11,7 @@ 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.
/// E.g., `PyClassShell` is a concrete representaion of all `pyclass`es, and `ffi::PyObject`
/// 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.

View File

@ -6,7 +6,7 @@ use pyo3::class::{
use pyo3::exceptions::{IndexError, ValueError};
use pyo3::prelude::*;
use pyo3::types::{IntoPyDict, PyAny, PyBytes, PySlice, PyType};
use pyo3::{ffi, py_run, AsPyPointer, PyClassShell};
use pyo3::{ffi, py_run, AsPyPointer, PyCell};
use std::convert::TryFrom;
use std::{isize, iter};
@ -53,11 +53,11 @@ struct Iterator {
#[pyproto]
impl<'p> PyIterProtocol for Iterator {
fn __iter__(slf: &mut PyClassShell<Self>) -> PyResult<Py<Iterator>> {
fn __iter__(slf: &mut PyCell<Self>) -> PyResult<Py<Iterator>> {
Ok(slf.into())
}
fn __next__(slf: &mut PyClassShell<Self>) -> PyResult<Option<i32>> {
fn __next__(slf: &mut PyCell<Self>) -> PyResult<Option<i32>> {
Ok(slf.iter.next())
}
}
@ -250,7 +250,7 @@ fn setitem() {
let gil = Python::acquire_gil();
let py = gil.python();
let c = PyClassShell::new_ref(py, SetItem { key: 0, val: 0 }).unwrap();
let c = PyCell::new_ref(py, SetItem { key: 0, val: 0 }).unwrap();
py_run!(py, c, "c[1] = 2");
assert_eq!(c.key, 1);
assert_eq!(c.val, 2);
@ -275,7 +275,7 @@ fn delitem() {
let gil = Python::acquire_gil();
let py = gil.python();
let c = PyClassShell::new_ref(py, DelItem { key: 0 }).unwrap();
let c = PyCell::new_ref(py, DelItem { key: 0 }).unwrap();
py_run!(py, c, "del c[1]");
assert_eq!(c.key, 1);
py_expect_exception!(py, c, "c[1] = 2", NotImplementedError);
@ -304,7 +304,7 @@ fn setdelitem() {
let gil = Python::acquire_gil();
let py = gil.python();
let c = PyClassShell::new_ref(py, SetDelItem { val: None }).unwrap();
let c = PyCell::new_ref(py, SetDelItem { val: None }).unwrap();
py_run!(py, c, "c[1] = 2");
assert_eq!(c.val, Some(2));
py_run!(py, c, "del c[1]");
@ -383,7 +383,7 @@ fn context_manager() {
let gil = Python::acquire_gil();
let py = gil.python();
let c = PyClassShell::new_mut(py, ContextManager { exit_called: false }).unwrap();
let c = PyCell::new_mut(py, ContextManager { exit_called: false }).unwrap();
py_run!(py, c, "with c as x: assert x == 42");
assert!(c.exit_called);
@ -455,7 +455,7 @@ struct DunderDictSupport {}
fn dunder_dict_support() {
let gil = Python::acquire_gil();
let py = gil.python();
let inst = PyClassShell::new_ref(py, DunderDictSupport {}).unwrap();
let inst = PyCell::new_ref(py, DunderDictSupport {}).unwrap();
py_run!(
py,
inst,
@ -470,7 +470,7 @@ fn dunder_dict_support() {
fn access_dunder_dict() {
let gil = Python::acquire_gil();
let py = gil.python();
let inst = PyClassShell::new_ref(py, DunderDictSupport {}).unwrap();
let inst = PyCell::new_ref(py, DunderDictSupport {}).unwrap();
py_run!(
py,
inst,
@ -488,7 +488,7 @@ struct WeakRefDunderDictSupport {}
fn weakref_dunder_dict_support() {
let gil = Python::acquire_gil();
let py = gil.python();
let inst = PyClassShell::new_ref(py, WeakRefDunderDictSupport {}).unwrap();
let inst = PyCell::new_ref(py, WeakRefDunderDictSupport {}).unwrap();
py_run!(
py,
inst,
@ -513,7 +513,7 @@ impl PyObjectProtocol for ClassWithGetAttr {
fn getattr_doesnt_override_member() {
let gil = Python::acquire_gil();
let py = gil.python();
let inst = PyClassShell::new_ref(py, ClassWithGetAttr { data: 4 }).unwrap();
let inst = PyCell::new_ref(py, ClassWithGetAttr { data: 4 }).unwrap();
py_assert!(py, inst, "inst.data == 4");
py_assert!(py, inst, "inst.a == 8");
}

View File

@ -3,7 +3,7 @@ use pyo3::class::PyTraverseError;
use pyo3::class::PyVisit;
use pyo3::prelude::*;
use pyo3::types::{PyAny, PyTuple};
use pyo3::{ffi, py_run, AsPyPointer, PyClassShell};
use pyo3::{ffi, py_run, AsPyPointer, PyCell};
use std::cell::RefCell;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
@ -153,7 +153,7 @@ fn gc_integration() {
{
let gil = Python::acquire_gil();
let py = gil.python();
let inst = PyClassShell::new_mut(
let inst = PyCell::new_mut(
py,
GCIntegration {
self_ref: RefCell::new(py.None()),
@ -188,7 +188,7 @@ impl PyGCProtocol for GCIntegration2 {
fn gc_integration2() {
let gil = Python::acquire_gil();
let py = gil.python();
let inst = PyClassShell::new_ref(py, GCIntegration2 {}).unwrap();
let inst = PyCell::new_ref(py, GCIntegration2 {}).unwrap();
py_run!(py, inst, "import gc; assert inst in gc.get_objects()");
}
@ -199,7 +199,7 @@ struct WeakRefSupport {}
fn weakref_support() {
let gil = Python::acquire_gil();
let py = gil.python();
let inst = PyClassShell::new_ref(py, WeakRefSupport {}).unwrap();
let inst = PyCell::new_ref(py, WeakRefSupport {}).unwrap();
py_run!(
py,
inst,

View File

@ -126,7 +126,7 @@ impl SetWithName {
fn inherit_set() {
let gil = Python::acquire_gil();
let py = gil.python();
let set_sub = pyo3::pyclass::PyClassShell::new_ref(py, SetWithName::new()).unwrap();
let set_sub = pyo3::pyclass::PyCell::new_ref(py, SetWithName::new()).unwrap();
py_run!(
py,
set_sub,
@ -152,7 +152,7 @@ impl DictWithName {
fn inherit_dict() {
let gil = Python::acquire_gil();
let py = gil.python();
let dict_sub = pyo3::pyclass::PyClassShell::new_ref(py, DictWithName::new()).unwrap();
let dict_sub = pyo3::pyclass::PyCell::new_ref(py, DictWithName::new()).unwrap();
py_run!(
py,
dict_sub,

View File

@ -1,7 +1,7 @@
use pyo3::prelude::*;
use pyo3::py_run;
use pyo3::types::{IntoPyDict, PyDict, PyList, PySet, PyString, PyTuple, PyType};
use pyo3::PyClassShell;
use pyo3::PyCell;
mod common;
@ -23,7 +23,7 @@ fn instance_method() {
let gil = Python::acquire_gil();
let py = gil.python();
let obj = PyClassShell::new_mut(py, InstanceMethod { member: 42 }).unwrap();
let obj = PyCell::new_mut(py, InstanceMethod { member: 42 }).unwrap();
assert_eq!(obj.method().unwrap(), 42);
let d = [("obj", obj)].into_py_dict(py);
py.run("assert obj.method() == 42", None, Some(d)).unwrap();
@ -49,7 +49,7 @@ fn instance_method_with_args() {
let gil = Python::acquire_gil();
let py = gil.python();
let obj = PyClassShell::new_mut(py, InstanceMethodWithArgs { member: 7 }).unwrap();
let obj = PyCell::new_mut(py, InstanceMethodWithArgs { member: 7 }).unwrap();
assert_eq!(obj.method(6).unwrap(), 42);
let d = [("obj", obj)].into_py_dict(py);
py.run("assert obj.method(3) == 21", None, Some(d)).unwrap();
@ -395,7 +395,7 @@ impl MethodWithLifeTime {
fn method_with_lifetime() {
let gil = Python::acquire_gil();
let py = gil.python();
let obj = PyClassShell::new_ref(py, MethodWithLifeTime {}).unwrap();
let obj = PyCell::new_ref(py, MethodWithLifeTime {}).unwrap();
py_run!(
py,
obj,

View File

@ -2,7 +2,7 @@
use pyo3;
use pyo3::prelude::*;
use pyo3::types::{PyBytes, PyString};
use pyo3::{AsPyRef, PyClassShell, PyIterProtocol};
use pyo3::{AsPyRef, PyCell, PyIterProtocol};
use std::collections::HashMap;
mod common;
@ -17,27 +17,20 @@ struct Reader {
#[pymethods]
impl Reader {
fn clone_ref(slf: &PyClassShell<Self>) -> &PyClassShell<Self> {
fn clone_ref(slf: &PyCell<Self>) -> &PyCell<Self> {
slf
}
fn clone_ref_with_py<'py>(
slf: &'py PyClassShell<Self>,
_py: Python<'py>,
) -> &'py PyClassShell<Self> {
fn clone_ref_with_py<'py>(slf: &'py PyCell<Self>, _py: Python<'py>) -> &'py PyCell<Self> {
slf
}
fn get_iter(slf: &PyClassShell<Self>, keys: Py<PyBytes>) -> PyResult<Iter> {
fn get_iter(slf: &PyCell<Self>, keys: Py<PyBytes>) -> PyResult<Iter> {
Ok(Iter {
reader: slf.into(),
keys,
idx: 0,
})
}
fn get_iter_and_reset(
slf: &mut PyClassShell<Self>,
keys: Py<PyBytes>,
py: Python,
) -> PyResult<Iter> {
fn get_iter_and_reset(slf: &mut PyCell<Self>, keys: Py<PyBytes>, py: Python) -> PyResult<Iter> {
let reader = Py::new(py, slf.clone())?;
slf.inner.clear();
Ok(Iter {
@ -57,12 +50,12 @@ struct Iter {
#[pyproto]
impl PyIterProtocol for Iter {
fn __iter__(slf: &mut PyClassShell<Self>) -> PyResult<PyObject> {
fn __iter__(slf: &mut PyCell<Self>) -> PyResult<PyObject> {
let py = unsafe { Python::assume_gil_acquired() };
Ok(slf.to_object(py))
}
fn __next__(slf: &mut PyClassShell<Self>) -> PyResult<Option<PyObject>> {
fn __next__(slf: &mut PyCell<Self>) -> PyResult<Option<PyObject>> {
let py = unsafe { Python::assume_gil_acquired() };
let bytes = slf.keys.as_ref(py).as_bytes();
match bytes.get(slf.idx) {
@ -113,7 +106,7 @@ fn test_clone_ref() {
fn test_nested_iter_reset() {
let gil = Python::acquire_gil();
let py = gil.python();
let reader = PyClassShell::new_ref(py, reader()).unwrap();
let reader = PyCell::new_ref(py, reader()).unwrap();
py_assert!(
py,
reader,

View File

@ -1,5 +1,5 @@
use pyo3::prelude::*;
use pyo3::{types::PyType, wrap_pyfunction, wrap_pymodule, PyClassShell};
use pyo3::{types::PyType, wrap_pyfunction, wrap_pymodule, PyCell};
mod common;
@ -144,7 +144,7 @@ fn test_methods() {
let _ = a;
}
#[text_signature = "($self, b)"]
fn pyself_method(_this: &PyClassShell<Self>, b: i32) {
fn pyself_method(_this: &PyCell<Self>, b: i32) {
let _ = b;
}
#[classmethod]

View File

@ -1,7 +1,7 @@
use pyo3::prelude::*;
use pyo3::types::IntoPyDict;
use pyo3::types::{PyDict, PyTuple};
use pyo3::{py_run, wrap_pyfunction, AsPyRef, PyClassShell};
use pyo3::{py_run, wrap_pyfunction, AsPyRef, PyCell};
mod common;
@ -81,8 +81,8 @@ fn intopytuple_pyclass() {
let py = gil.python();
let tup = (
PyClassShell::new_ref(py, SimplePyClass {}).unwrap(),
PyClassShell::new_ref(py, SimplePyClass {}).unwrap(),
PyCell::new_ref(py, SimplePyClass {}).unwrap(),
PyCell::new_ref(py, SimplePyClass {}).unwrap(),
);
py_assert!(py, tup, "type(tup[0]).__name__ == 'SimplePyClass'");
py_assert!(py, tup, "type(tup[0]).__name__ == type(tup[1]).__name__");
@ -106,8 +106,8 @@ fn pytuple_pyclass_iter() {
let tup = PyTuple::new(
py,
[
PyClassShell::new_ref(py, SimplePyClass {}).unwrap(),
PyClassShell::new_ref(py, SimplePyClass {}).unwrap(),
PyCell::new_ref(py, SimplePyClass {}).unwrap(),
PyCell::new_ref(py, SimplePyClass {}).unwrap(),
]
.iter(),
);
@ -127,7 +127,7 @@ impl PickleSupport {
}
pub fn __reduce__<'py>(
slf: &'py PyClassShell<Self>,
slf: &'py PyCell<Self>,
py: Python<'py>,
) -> PyResult<(PyObject, &'py PyTuple, PyObject)> {
let cls = slf.to_object(py).getattr(py, "__class__")?;
@ -152,7 +152,7 @@ fn test_pickle() {
let module = PyModule::new(py, "test_module").unwrap();
module.add_class::<PickleSupport>().unwrap();
add_module(py, module).unwrap();
let inst = PyClassShell::new_ref(py, PickleSupport {}).unwrap();
let inst = PyCell::new_ref(py, PickleSupport {}).unwrap();
py_run!(
py,
inst,