diff --git a/guide/src/class.md b/guide/src/class.md index 9215c6a9..97a84179 100644 --- a/guide/src/class.md +++ b/guide/src/class.md @@ -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; + type ConcreteLayout = pyo3::PyCell; type Initializer = pyo3::PyClassInitializer; 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`. +you can use `PyCell`. Or you can use `Py` 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 -let obj = PyClassShell::new_mut(py, MyClass { num: 3, debug: true }).unwrap(); +// return &mut PyCell +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) -> PyResult { + fn method2(self_: &PyCell) -> PyResult { self_.get_super().method().map(|x| x * self_.val2) } } @@ -279,7 +279,7 @@ impl SubSubClass { .add_subclass(SubSubClass{val3: 20}) } - fn method3(self_: &PyClassShell) -> PyResult { + fn method3(self_: &PyCell) -> PyResult { 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` instead of `self`, and call `get_super()` +- Use `self_: &PyCell` 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) -> PyResult>` - * `fn __next__(slf: &mut PyClassShell) -> PyResult>>` + * `fn __iter__(slf: &mut PyCell) -> PyResult>` + * `fn __next__(slf: &mut PyCell) -> PyResult>>` 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) -> PyResult> { + fn __iter__(slf: &mut PyCell) -> PyResult> { Ok(slf.into()) } - fn __next__(slf: &mut PyClassShell) -> PyResult> { + fn __next__(slf: &mut PyCell) -> PyResult> { Ok(slf.iter.next()) } } diff --git a/guide/src/python_from_rust.md b/guide/src/python_from_rust.md index c20a3281..2250ca70 100644 --- a/guide/src/python_from_rust.md +++ b/guide/src/python_from_rust.md @@ -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)" diff --git a/pyo3-derive-backend/src/pyclass.rs b/pyo3-derive-backend/src/pyclass.rs index 19b01b25..bf0f1af3 100644 --- a/pyo3-derive-backend/src/pyclass.rs +++ b/pyo3-derive-backend/src/pyclass.rs @@ -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; + type ConcreteLayout = pyo3::pyclass::PyCell; type Initializer = pyo3::pyclass_init::PyClassInitializer; const NAME: &'static str = #cls_name; diff --git a/pyo3-derive-backend/src/pymethod.rs b/pyo3-derive-backend/src/pymethod.rs index 97bb1f16..7b737057 100644 --- a/pyo3-derive-backend/src/pymethod.rs +++ b/pyo3-derive-backend/src/pymethod.rs @@ -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), } diff --git a/src/class/iter.rs b/src/class/iter.rs index 802bd159..aca9c030 100644 --- a/src/class/iter.rs +++ b/src/class/iter.rs @@ -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::Result + fn __iter__(slf: &mut PyCell) -> Self::Result where Self: PyIterIterProtocol<'p>, { unimplemented!() } - fn __next__(slf: &mut PyClassShell) -> Self::Result + fn __next__(slf: &mut PyCell) -> Self::Result where Self: PyIterNextProtocol<'p>, { diff --git a/src/class/macros.rs b/src/class/macros.rs index 7fbf2499..f67fdd43 100644 --- a/src/class/macros.rs +++ b/src/class/macros.rs @@ -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 = &mut *(slf as *mut PyClassShell); + let slf: &mut PyCell = &mut *(slf as *mut PyCell); let res = $class::$f(slf).into(); $crate::callback::cb_convert($conv, py, res) } diff --git a/src/instance.rs b/src/instance.rs index 34f9e7df..15a74bed 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -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 Py { crate::type_object::PyObjectSizedLayout, { 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` can be converted to `Py` -impl<'a, T> std::convert::From<&PyClassShell> for Py +// `&PyCell` can be converted to `Py` +impl<'a, T> std::convert::From<&PyCell> for Py where T: PyClass, { - fn from(shell: &PyClassShell) -> Self { - unsafe { Py::from_borrowed_ptr(shell.as_ptr()) } + fn from(cell: &PyCell) -> Self { + unsafe { Py::from_borrowed_ptr(cell.as_ptr()) } } } -impl<'a, T> std::convert::From<&mut PyClassShell> for Py +impl<'a, T> std::convert::From<&mut PyCell> for Py where T: PyClass, { - fn from(shell: &mut PyClassShell) -> Self { - unsafe { Py::from_borrowed_ptr(shell.as_ptr()) } + fn from(cell: &mut PyCell) -> Self { + unsafe { Py::from_borrowed_ptr(cell.as_ptr()) } } } diff --git a/src/lib.rs b/src/lib.rs index 14126a5f..ce19c20f 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -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 diff --git a/src/pycell.rs b/src/pycell.rs new file mode 100644 index 00000000..710f4300 --- /dev/null +++ b/src/pycell.rs @@ -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 { + ob_base: ::ConcreteLayout, + pyclass: ManuallyDrop, + dict: T::Dict, + weakref: T::WeakRef, +} + +impl PyCell { + /// Make new `PyCell` on the Python heap and returns the reference of it. + pub fn new_ref(py: Python, value: impl Into>) -> PyResult<&Self> + where + ::ConcreteLayout: + crate::type_object::PyObjectSizedLayout, + { + 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>) -> PyResult<&mut Self> + where + ::ConcreteLayout: + crate::type_object::PyObjectSizedLayout, + { + 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) -> &::ConcreteLayout { + &self.ob_base + } + + /// Get the mutable reference of base object. + pub fn get_super_mut(&mut self) -> &mut ::ConcreteLayout { + &mut self.ob_base + } + + pub(crate) unsafe fn internal_new(py: Python) -> PyResult<*mut Self> + where + ::ConcreteLayout: + crate::type_object::PyObjectSizedLayout, + { + 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 PyObjectLayout for PyCell { + const IS_NATIVE_TYPE: bool = false; + fn get_super_or(&mut self) -> Option<&mut ::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 PyObjectSizedLayout for PyCell {} + +impl AsPyPointer for PyCell { + fn as_ptr(&self) -> *mut ffi::PyObject { + (self as *const _) as *mut _ + } +} + +impl std::ops::Deref for PyCell { + type Target = T; + fn deref(&self) -> &T { + self.pyclass.deref() + } +} + +impl std::ops::DerefMut for PyCell { + fn deref_mut(&mut self) -> &mut T { + self.pyclass.deref_mut() + } +} + +impl ToPyObject for &PyCell { + fn to_object(&self, py: Python<'_>) -> PyObject { + unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) } + } +} + +impl ToPyObject for &mut PyCell { + 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 +where + T: PyClass, +{ + unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option { + NonNull::new(ptr).map(|p| &*(gil::register_owned(py, p).as_ptr() as *const PyCell)) + } + unsafe fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option { + NonNull::new(ptr).map(|p| &*(gil::register_borrowed(py, p).as_ptr() as *const PyCell)) + } +} + +unsafe impl<'p, T> FromPyPointer<'p> for &'p mut PyCell +where + T: PyClass, +{ + unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option { + NonNull::new(ptr) + .map(|p| &mut *(gil::register_owned(py, p).as_ptr() as *const _ as *mut PyCell)) + } + unsafe fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option { + NonNull::new(ptr) + .map(|p| &mut *(gil::register_borrowed(py, p).as_ptr() as *const _ as *mut PyCell)) + } +} diff --git a/src/pyclass.rs b/src/pyclass.rs index 12fb801b..9ca01845 100644 --- a/src/pyclass.rs +++ b/src/pyclass.rs @@ -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() -> *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> + Sized + PyClassAlloc + PyMethodsProtocol + PyTypeInfo> + 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 { - ob_base: ::ConcreteLayout, - pyclass: ManuallyDrop, - dict: T::Dict, - weakref: T::WeakRef, -} - -impl PyClassShell { - /// Make new `PyClassShell` on the Python heap and returns the reference of it. - pub fn new_ref(py: Python, value: impl Into>) -> PyResult<&Self> - where - ::ConcreteLayout: - crate::type_object::PyObjectSizedLayout, - { - 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>) -> PyResult<&mut Self> - where - ::ConcreteLayout: - crate::type_object::PyObjectSizedLayout, - { - 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) -> &::ConcreteLayout { - &self.ob_base - } - - /// Get the mutable reference of base object. - pub fn get_super_mut(&mut self) -> &mut ::ConcreteLayout { - &mut self.ob_base - } - - pub(crate) unsafe fn new(py: Python) -> PyResult<*mut Self> - where - ::ConcreteLayout: - crate::type_object::PyObjectSizedLayout, - { - 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 PyObjectLayout for PyClassShell { - const IS_NATIVE_TYPE: bool = false; - fn get_super_or(&mut self) -> Option<&mut ::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 PyObjectSizedLayout for PyClassShell {} - -impl AsPyPointer for PyClassShell { - fn as_ptr(&self) -> *mut ffi::PyObject { - (self as *const _) as *mut _ - } -} - -impl std::ops::Deref for PyClassShell { - type Target = T; - fn deref(&self) -> &T { - self.pyclass.deref() - } -} - -impl std::ops::DerefMut for PyClassShell { - fn deref_mut(&mut self) -> &mut T { - self.pyclass.deref_mut() - } -} - -impl ToPyObject for &PyClassShell { - fn to_object(&self, py: Python<'_>) -> PyObject { - unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) } - } -} - -impl ToPyObject for &mut PyClassShell { - 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 -where - T: PyClass, -{ - unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option { - NonNull::new(ptr).map(|p| &*(gil::register_owned(py, p).as_ptr() as *const PyClassShell)) - } - unsafe fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option { - NonNull::new(ptr) - .map(|p| &*(gil::register_borrowed(py, p).as_ptr() as *const PyClassShell)) - } -} - -unsafe impl<'p, T> FromPyPointer<'p> for &'p mut PyClassShell -where - T: PyClass, -{ - unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option { - NonNull::new(ptr).map(|p| { - &mut *(gil::register_owned(py, p).as_ptr() as *const _ as *mut PyClassShell) - }) - } - unsafe fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option { - NonNull::new(ptr).map(|p| { - &mut *(gil::register_borrowed(py, p).as_ptr() as *const _ as *mut PyClassShell) - }) - } -} - #[cfg(not(Py_LIMITED_API))] pub(crate) fn initialize_type_object( py: Python, diff --git a/src/pyclass_init.rs b/src/pyclass_init.rs index bc2904da..daf59de3 100644 --- a/src/pyclass_init.rs +++ b/src/pyclass_init.rs @@ -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: 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: Sized { pub struct PyNativeTypeInitializer(PhantomData); impl PyObjectInit for PyNativeTypeInitializer { - fn init_class(self, _shell: &mut T::ConcreteLayout) {} + fn init_class(self, _layout: &mut T::ConcreteLayout) {} private_impl! {} } @@ -115,14 +114,14 @@ impl PyClassInitializer { } #[doc(hidden)] - pub unsafe fn create_shell(self, py: Python) -> PyResult<*mut PyClassShell> + pub unsafe fn create_cell(self, py: Python) -> PyResult<*mut PyCell> where T: PyClass, ::ConcreteLayout: PyObjectSizedLayout, { - 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) } } diff --git a/src/type_object.rs b/src/type_object.rs index 6b12542a..cce36d02 100644 --- a/src/type_object.rs +++ b/src/type_object.rs @@ -11,7 +11,7 @@ use std::ptr::NonNull; use std::sync::atomic::{AtomicBool, Ordering}; /// `T: PyObjectLayout` 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. diff --git a/tests/test_dunder.rs b/tests/test_dunder.rs index 6fecc4c7..3790c73c 100755 --- a/tests/test_dunder.rs +++ b/tests/test_dunder.rs @@ -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) -> PyResult> { + fn __iter__(slf: &mut PyCell) -> PyResult> { Ok(slf.into()) } - fn __next__(slf: &mut PyClassShell) -> PyResult> { + fn __next__(slf: &mut PyCell) -> PyResult> { 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"); } diff --git a/tests/test_gc.rs b/tests/test_gc.rs index 8f2d0923..1f8de776 100644 --- a/tests/test_gc.rs +++ b/tests/test_gc.rs @@ -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, diff --git a/tests/test_inheritance.rs b/tests/test_inheritance.rs index f19d0fd1..49cc5370 100644 --- a/tests/test_inheritance.rs +++ b/tests/test_inheritance.rs @@ -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, diff --git a/tests/test_methods.rs b/tests/test_methods.rs index 153bc2b5..3e93e669 100644 --- a/tests/test_methods.rs +++ b/tests/test_methods.rs @@ -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, diff --git a/tests/test_pyself.rs b/tests/test_pyself.rs index 00eebfb1..25bf1a89 100644 --- a/tests/test_pyself.rs +++ b/tests/test_pyself.rs @@ -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) -> &PyClassShell { + fn clone_ref(slf: &PyCell) -> &PyCell { slf } - fn clone_ref_with_py<'py>( - slf: &'py PyClassShell, - _py: Python<'py>, - ) -> &'py PyClassShell { + fn clone_ref_with_py<'py>(slf: &'py PyCell, _py: Python<'py>) -> &'py PyCell { slf } - fn get_iter(slf: &PyClassShell, keys: Py) -> PyResult { + fn get_iter(slf: &PyCell, keys: Py) -> PyResult { Ok(Iter { reader: slf.into(), keys, idx: 0, }) } - fn get_iter_and_reset( - slf: &mut PyClassShell, - keys: Py, - py: Python, - ) -> PyResult { + fn get_iter_and_reset(slf: &mut PyCell, keys: Py, py: Python) -> PyResult { 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) -> PyResult { + fn __iter__(slf: &mut PyCell) -> PyResult { let py = unsafe { Python::assume_gil_acquired() }; Ok(slf.to_object(py)) } - fn __next__(slf: &mut PyClassShell) -> PyResult> { + fn __next__(slf: &mut PyCell) -> PyResult> { 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, diff --git a/tests/test_text_signature.rs b/tests/test_text_signature.rs index 6406cbf5..85211a34 100644 --- a/tests/test_text_signature.rs +++ b/tests/test_text_signature.rs @@ -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, b: i32) { + fn pyself_method(_this: &PyCell, b: i32) { let _ = b; } #[classmethod] diff --git a/tests/test_various.rs b/tests/test_various.rs index e24db369..d0bbb7bf 100644 --- a/tests/test_various.rs +++ b/tests/test_various.rs @@ -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, + slf: &'py PyCell, 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::().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,