Implement opt-in immutable pyclasses
This commit is contained in:
parent
ada301773e
commit
7520b49ac1
|
@ -932,36 +932,41 @@ The `#[pyclass]` macro expands to roughly the code seen below. The `PyClassImplC
|
||||||
# #[cfg(not(feature = "multiple-pymethods"))] {
|
# #[cfg(not(feature = "multiple-pymethods"))] {
|
||||||
# use pyo3::prelude::*;
|
# use pyo3::prelude::*;
|
||||||
// Note: the implementation differs slightly with the `multiple-pymethods` feature enabled.
|
// Note: the implementation differs slightly with the `multiple-pymethods` feature enabled.
|
||||||
|
|
||||||
/// Class for demonstration
|
|
||||||
struct MyClass {
|
struct MyClass {
|
||||||
# #[allow(dead_code)]
|
# #[allow(dead_code)]
|
||||||
num: i32,
|
num: i32,
|
||||||
}
|
}
|
||||||
|
unsafe impl ::pyo3::type_object::PyTypeInfo for MyClass {
|
||||||
unsafe impl pyo3::PyTypeInfo for MyClass {
|
type AsRefTarget = ::pyo3::PyCell<Self>;
|
||||||
type AsRefTarget = PyCell<Self>;
|
|
||||||
|
|
||||||
const NAME: &'static str = "MyClass";
|
const NAME: &'static str = "MyClass";
|
||||||
const MODULE: Option<&'static str> = None;
|
const MODULE: ::std::option::Option<&'static str> = ::std::option::Option::None;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn type_object_raw(py: pyo3::Python) -> *mut pyo3::ffi::PyTypeObject {
|
fn type_object_raw(py: ::pyo3::Python<'_>) -> *mut ::pyo3::ffi::PyTypeObject {
|
||||||
use pyo3::type_object::LazyStaticType;
|
use ::pyo3::type_object::LazyStaticType;
|
||||||
static TYPE_OBJECT: LazyStaticType = LazyStaticType::new();
|
static TYPE_OBJECT: LazyStaticType = LazyStaticType::new();
|
||||||
TYPE_OBJECT.get_or_init::<Self>(py)
|
TYPE_OBJECT.get_or_init::<Self>(py)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl pyo3::pyclass::PyClass for MyClass {
|
impl ::pyo3::PyClass for MyClass {
|
||||||
type Dict = pyo3::impl_::pyclass::PyClassDummySlot;
|
type Dict = ::pyo3::impl_::pyclass::PyClassDummySlot;
|
||||||
type WeakRef = pyo3::impl_::pyclass::PyClassDummySlot;
|
type WeakRef = ::pyo3::impl_::pyclass::PyClassDummySlot;
|
||||||
type BaseNativeType = PyAny;
|
type BaseNativeType = ::pyo3::PyAny;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl pyo3::IntoPy<PyObject> for MyClass {
|
unsafe impl ::pyo3::pyclass::MutablePyClass for MyClass {}
|
||||||
fn into_py(self, py: pyo3::Python) -> pyo3::PyObject {
|
|
||||||
pyo3::IntoPy::into_py(pyo3::Py::new(py, self).unwrap(), py)
|
impl<'a> ::pyo3::derive_utils::ExtractExt<'a> for &'a mut MyClass {
|
||||||
|
type Target = ::pyo3::PyRefMut<'a, MyClass>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ::pyo3::derive_utils::ExtractExt<'a> for &'a MyClass {
|
||||||
|
type Target = ::pyo3::PyRef<'a, MyClass>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::pyo3::IntoPy<::pyo3::PyObject> for MyClass {
|
||||||
|
fn into_py(self, py: ::pyo3::Python) -> ::pyo3::PyObject {
|
||||||
|
::pyo3::IntoPy::into_py(::pyo3::Py::new(py, self).unwrap(), py)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -973,6 +978,7 @@ impl pyo3::impl_::pyclass::PyClassImpl for MyClass {
|
||||||
type Layout = PyCell<MyClass>;
|
type Layout = PyCell<MyClass>;
|
||||||
type BaseType = PyAny;
|
type BaseType = PyAny;
|
||||||
type ThreadChecker = pyo3::impl_::pyclass::ThreadCheckerStub<MyClass>;
|
type ThreadChecker = pyo3::impl_::pyclass::ThreadCheckerStub<MyClass>;
|
||||||
|
type Mutabilty = pyo3::pyclass::Mutable;
|
||||||
|
|
||||||
fn for_all_items(visitor: &mut dyn FnMut(&pyo3::impl_::pyclass::PyClassItems)) {
|
fn for_all_items(visitor: &mut dyn FnMut(&pyo3::impl_::pyclass::PyClassItems)) {
|
||||||
use pyo3::impl_::pyclass::*;
|
use pyo3::impl_::pyclass::*;
|
||||||
|
@ -997,6 +1003,15 @@ impl pyo3::impl_::pyclass::PyClassImpl for MyClass {
|
||||||
collector.free_impl()
|
collector.free_impl()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ::pyo3::impl_::pyclass::PyClassDescriptors<MyClass>
|
||||||
|
for ::pyo3::impl_::pyclass::PyClassImplCollector<MyClass>
|
||||||
|
{
|
||||||
|
fn py_class_descriptors(self) -> &'static [::pyo3::class::methods::PyMethodDefType] {
|
||||||
|
static METHODS: &[::pyo3::class::methods::PyMethodDefType] = &[];
|
||||||
|
METHODS
|
||||||
|
}
|
||||||
|
}
|
||||||
# Python::with_gil(|py| {
|
# Python::with_gil(|py| {
|
||||||
# let cls = py.get_type::<MyClass>();
|
# let cls = py.get_type::<MyClass>();
|
||||||
# pyo3::py_run!(py, cls, "assert cls.__name__ == 'MyClass'")
|
# pyo3::py_run!(py, cls, "assert cls.__name__ == 'MyClass'")
|
||||||
|
|
|
@ -35,6 +35,7 @@ pub struct PyClassArgs {
|
||||||
pub has_unsendable: bool,
|
pub has_unsendable: bool,
|
||||||
pub module: Option<syn::LitStr>,
|
pub module: Option<syn::LitStr>,
|
||||||
pub class_kind: PyClassKind,
|
pub class_kind: PyClassKind,
|
||||||
|
pub is_immutable: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PyClassArgs {
|
impl PyClassArgs {
|
||||||
|
@ -67,6 +68,7 @@ impl PyClassArgs {
|
||||||
is_basetype: false,
|
is_basetype: false,
|
||||||
has_extends: false,
|
has_extends: false,
|
||||||
has_unsendable: false,
|
has_unsendable: false,
|
||||||
|
is_immutable: false,
|
||||||
class_kind,
|
class_kind,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -176,6 +178,9 @@ impl PyClassArgs {
|
||||||
"unsendable" => {
|
"unsendable" => {
|
||||||
self.has_unsendable = true;
|
self.has_unsendable = true;
|
||||||
}
|
}
|
||||||
|
"immutable" => {
|
||||||
|
self.is_immutable = true;
|
||||||
|
}
|
||||||
_ => bail_spanned!(
|
_ => bail_spanned!(
|
||||||
exp.path.span() => "expected one of gc/weakref/subclass/dict/unsendable"
|
exp.path.span() => "expected one of gc/weakref/subclass/dict/unsendable"
|
||||||
),
|
),
|
||||||
|
@ -587,12 +592,29 @@ fn impl_enum_class(
|
||||||
let default_items =
|
let default_items =
|
||||||
gen_default_items(cls, vec![default_repr_impl, default_richcmp, default_int]);
|
gen_default_items(cls, vec![default_repr_impl, default_richcmp, default_int]);
|
||||||
|
|
||||||
|
let mutability = if args.is_immutable {
|
||||||
|
quote! {
|
||||||
|
unsafe impl _pyo3::pyclass::ImmutablePyClass for #cls {}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {
|
||||||
|
unsafe impl _pyo3::pyclass::MutablePyClass for #cls {}
|
||||||
|
|
||||||
|
impl<'a> _pyo3::derive_utils::ExtractExt<'a> for &'a mut #cls
|
||||||
|
{
|
||||||
|
type Target = _pyo3::PyRefMut<'a, #cls>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Ok(quote! {
|
Ok(quote! {
|
||||||
const _: () = {
|
const _: () = {
|
||||||
use #krate as _pyo3;
|
use #krate as _pyo3;
|
||||||
|
|
||||||
#pytypeinfo
|
#pytypeinfo
|
||||||
|
|
||||||
|
#mutability
|
||||||
|
|
||||||
#pyclass_impls
|
#pyclass_impls
|
||||||
|
|
||||||
#default_items
|
#default_items
|
||||||
|
@ -788,20 +810,30 @@ impl<'a> PyClassImplsBuilder<'a> {
|
||||||
type Dict = #dict;
|
type Dict = #dict;
|
||||||
type WeakRef = #weakref;
|
type WeakRef = #weakref;
|
||||||
type BaseNativeType = #base_nativetype;
|
type BaseNativeType = #base_nativetype;
|
||||||
|
type Mutability = _pyo3::pycell::Immutable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn impl_extractext(&self) -> TokenStream {
|
fn impl_extractext(&self) -> TokenStream {
|
||||||
let cls = self.cls;
|
let cls = self.cls;
|
||||||
quote! {
|
if self.attr.is_immutable {
|
||||||
impl<'a> _pyo3::derive_utils::ExtractExt<'a> for &'a #cls
|
quote! {
|
||||||
{
|
impl<'a> _pyo3::derive_utils::ExtractExt<'a> for &'a #cls
|
||||||
type Target = _pyo3::PyRef<'a, #cls>;
|
{
|
||||||
|
type Target = _pyo3::PyRef<'a, #cls>;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
quote! {
|
||||||
|
impl<'a> _pyo3::derive_utils::ExtractExt<'a> for &'a #cls
|
||||||
|
{
|
||||||
|
type Target = _pyo3::PyRef<'a, #cls>;
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> _pyo3::derive_utils::ExtractExt<'a> for &'a mut #cls
|
impl<'a> _pyo3::derive_utils::ExtractExt<'a> for &'a mut #cls
|
||||||
{
|
{
|
||||||
type Target = _pyo3::PyRefMut<'a, #cls>;
|
type Target = _pyo3::PyRefMut<'a, #cls>;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -901,8 +933,18 @@ impl<'a> PyClassImplsBuilder<'a> {
|
||||||
|
|
||||||
let default_items = &self.default_items;
|
let default_items = &self.default_items;
|
||||||
|
|
||||||
|
let mutability = if self.attr.is_immutable {
|
||||||
|
quote! {
|
||||||
|
_pyo3::pycell::Immutable
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {
|
||||||
|
_pyo3::pycell::Mutable
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
impl _pyo3::impl_::pyclass::PyClassImpl for #cls {
|
impl _pyo3::impl_::pyclass::PyClassImpl<#mutability> for #cls {
|
||||||
const DOC: &'static str = #doc;
|
const DOC: &'static str = #doc;
|
||||||
const IS_GC: bool = #is_gc;
|
const IS_GC: bool = #is_gc;
|
||||||
const IS_BASETYPE: bool = #is_basetype;
|
const IS_BASETYPE: bool = #is_basetype;
|
||||||
|
@ -943,9 +985,9 @@ impl<'a> PyClassImplsBuilder<'a> {
|
||||||
#dict_offset
|
#dict_offset
|
||||||
|
|
||||||
#weaklist_offset
|
#weaklist_offset
|
||||||
}
|
|
||||||
|
|
||||||
#inventory_class
|
#inventory_class
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,9 @@
|
||||||
//! [typeobj docs](https://docs.python.org/3/c-api/typeobj.html)
|
//! [typeobj docs](https://docs.python.org/3/c-api/typeobj.html)
|
||||||
|
|
||||||
use crate::callback::{HashCallbackOutput, IntoPyCallbackOutput};
|
use crate::callback::{HashCallbackOutput, IntoPyCallbackOutput};
|
||||||
use crate::{exceptions, ffi, FromPyObject, PyAny, PyCell, PyClass, PyObject};
|
use crate::{
|
||||||
|
exceptions, ffi, pyclass::MutablePyClass, FromPyObject, PyAny, PyCell, PyClass, PyObject,
|
||||||
|
};
|
||||||
use std::os::raw::c_int;
|
use std::os::raw::c_int;
|
||||||
|
|
||||||
/// Basic Python class customization
|
/// Basic Python class customization
|
||||||
|
@ -24,14 +26,14 @@ pub trait PyObjectProtocol<'p>: PyClass {
|
||||||
|
|
||||||
fn __setattr__(&'p mut self, name: Self::Name, value: Self::Value) -> Self::Result
|
fn __setattr__(&'p mut self, name: Self::Name, value: Self::Value) -> Self::Result
|
||||||
where
|
where
|
||||||
Self: PyObjectSetAttrProtocol<'p>,
|
Self: PyObjectSetAttrProtocol<'p> + MutablePyClass,
|
||||||
{
|
{
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __delattr__(&'p mut self, name: Self::Name) -> Self::Result
|
fn __delattr__(&'p mut self, name: Self::Name) -> Self::Result
|
||||||
where
|
where
|
||||||
Self: PyObjectDelAttrProtocol<'p>,
|
Self: PyObjectDelAttrProtocol<'p> + MutablePyClass,
|
||||||
{
|
{
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
@ -75,12 +77,12 @@ pub trait PyObjectGetAttrProtocol<'p>: PyObjectProtocol<'p> {
|
||||||
type Name: FromPyObject<'p>;
|
type Name: FromPyObject<'p>;
|
||||||
type Result: IntoPyCallbackOutput<PyObject>;
|
type Result: IntoPyCallbackOutput<PyObject>;
|
||||||
}
|
}
|
||||||
pub trait PyObjectSetAttrProtocol<'p>: PyObjectProtocol<'p> {
|
pub trait PyObjectSetAttrProtocol<'p>: PyObjectProtocol<'p> + MutablePyClass {
|
||||||
type Name: FromPyObject<'p>;
|
type Name: FromPyObject<'p>;
|
||||||
type Value: FromPyObject<'p>;
|
type Value: FromPyObject<'p>;
|
||||||
type Result: IntoPyCallbackOutput<()>;
|
type Result: IntoPyCallbackOutput<()>;
|
||||||
}
|
}
|
||||||
pub trait PyObjectDelAttrProtocol<'p>: PyObjectProtocol<'p> {
|
pub trait PyObjectDelAttrProtocol<'p>: PyObjectProtocol<'p> + MutablePyClass {
|
||||||
type Name: FromPyObject<'p>;
|
type Name: FromPyObject<'p>;
|
||||||
type Result: IntoPyCallbackOutput<()>;
|
type Result: IntoPyCallbackOutput<()>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
//! For more information check [buffer protocol](https://docs.python.org/3/c-api/buffer.html)
|
//! For more information check [buffer protocol](https://docs.python.org/3/c-api/buffer.html)
|
||||||
//! c-api
|
//! c-api
|
||||||
use crate::callback::IntoPyCallbackOutput;
|
use crate::callback::IntoPyCallbackOutput;
|
||||||
use crate::{ffi, PyCell, PyClass, PyRefMut};
|
use crate::{ffi, pyclass::MutablePyClass, PyCell, PyRefMut};
|
||||||
use std::os::raw::c_int;
|
use std::os::raw::c_int;
|
||||||
|
|
||||||
/// Buffer protocol interface
|
/// Buffer protocol interface
|
||||||
|
@ -13,7 +13,7 @@ use std::os::raw::c_int;
|
||||||
/// For more information check [buffer protocol](https://docs.python.org/3/c-api/buffer.html)
|
/// For more information check [buffer protocol](https://docs.python.org/3/c-api/buffer.html)
|
||||||
/// c-api.
|
/// c-api.
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub trait PyBufferProtocol<'p>: PyClass {
|
pub trait PyBufferProtocol<'p>: MutablePyClass {
|
||||||
// No default implementations so that implementors of this trait provide both methods.
|
// No default implementations so that implementors of this trait provide both methods.
|
||||||
|
|
||||||
fn bf_getbuffer(slf: PyRefMut<Self>, view: *mut ffi::Py_buffer, flags: c_int) -> Self::Result
|
fn bf_getbuffer(slf: PyRefMut<Self>, view: *mut ffi::Py_buffer, flags: c_int) -> Self::Result
|
||||||
|
|
|
@ -2,14 +2,14 @@
|
||||||
|
|
||||||
//! Python GC support
|
//! Python GC support
|
||||||
|
|
||||||
use crate::{ffi, AsPyPointer, PyCell, PyClass, Python};
|
use crate::{ffi, pyclass::MutablePyClass, AsPyPointer, PyCell, Python};
|
||||||
use std::os::raw::{c_int, c_void};
|
use std::os::raw::{c_int, c_void};
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct PyTraverseError(c_int);
|
pub struct PyTraverseError(c_int);
|
||||||
|
|
||||||
/// GC support
|
/// GC support
|
||||||
pub trait PyGCProtocol<'p>: PyClass {
|
pub trait PyGCProtocol<'p>: MutablePyClass {
|
||||||
fn __traverse__(&'p self, visit: PyVisit) -> Result<(), PyTraverseError>;
|
fn __traverse__(&'p self, visit: PyVisit) -> Result<(), PyTraverseError>;
|
||||||
fn __clear__(&'p mut self);
|
fn __clear__(&'p mut self);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
//! Trait and support implementation for implementing mapping support
|
//! Trait and support implementation for implementing mapping support
|
||||||
|
|
||||||
use crate::callback::IntoPyCallbackOutput;
|
use crate::callback::IntoPyCallbackOutput;
|
||||||
use crate::{FromPyObject, PyClass, PyObject};
|
use crate::{pyclass::MutablePyClass, FromPyObject, PyClass, PyObject};
|
||||||
|
|
||||||
/// Mapping interface
|
/// Mapping interface
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
|
@ -50,13 +50,13 @@ pub trait PyMappingGetItemProtocol<'p>: PyMappingProtocol<'p> {
|
||||||
type Result: IntoPyCallbackOutput<PyObject>;
|
type Result: IntoPyCallbackOutput<PyObject>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PyMappingSetItemProtocol<'p>: PyMappingProtocol<'p> {
|
pub trait PyMappingSetItemProtocol<'p>: PyMappingProtocol<'p> + MutablePyClass {
|
||||||
type Key: FromPyObject<'p>;
|
type Key: FromPyObject<'p>;
|
||||||
type Value: FromPyObject<'p>;
|
type Value: FromPyObject<'p>;
|
||||||
type Result: IntoPyCallbackOutput<()>;
|
type Result: IntoPyCallbackOutput<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PyMappingDelItemProtocol<'p>: PyMappingProtocol<'p> {
|
pub trait PyMappingDelItemProtocol<'p>: PyMappingProtocol<'p> + MutablePyClass {
|
||||||
type Key: FromPyObject<'p>;
|
type Key: FromPyObject<'p>;
|
||||||
type Result: IntoPyCallbackOutput<()>;
|
type Result: IntoPyCallbackOutput<()>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
//! Trait and support implementation for implementing number protocol
|
//! Trait and support implementation for implementing number protocol
|
||||||
use crate::callback::IntoPyCallbackOutput;
|
use crate::callback::IntoPyCallbackOutput;
|
||||||
use crate::err::PyErr;
|
use crate::err::PyErr;
|
||||||
use crate::{ffi, FromPyObject, PyClass, PyObject};
|
use crate::{ffi, pyclass::MutablePyClass, FromPyObject, PyClass, PyObject};
|
||||||
|
|
||||||
/// Number interface
|
/// Number interface
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
|
@ -459,74 +459,74 @@ pub trait PyNumberROrProtocol<'p>: PyNumberProtocol<'p> {
|
||||||
type Result: IntoPyCallbackOutput<PyObject>;
|
type Result: IntoPyCallbackOutput<PyObject>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PyNumberIAddProtocol<'p>: PyNumberProtocol<'p> {
|
pub trait PyNumberIAddProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||||
type Other: FromPyObject<'p>;
|
type Other: FromPyObject<'p>;
|
||||||
type Result: IntoPyCallbackOutput<()>;
|
type Result: IntoPyCallbackOutput<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PyNumberISubProtocol<'p>: PyNumberProtocol<'p> {
|
pub trait PyNumberISubProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||||
type Other: FromPyObject<'p>;
|
type Other: FromPyObject<'p>;
|
||||||
type Result: IntoPyCallbackOutput<()>;
|
type Result: IntoPyCallbackOutput<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PyNumberIMulProtocol<'p>: PyNumberProtocol<'p> {
|
pub trait PyNumberIMulProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||||
type Other: FromPyObject<'p>;
|
type Other: FromPyObject<'p>;
|
||||||
type Result: IntoPyCallbackOutput<()>;
|
type Result: IntoPyCallbackOutput<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PyNumberIMatmulProtocol<'p>: PyNumberProtocol<'p> {
|
pub trait PyNumberIMatmulProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||||
type Other: FromPyObject<'p>;
|
type Other: FromPyObject<'p>;
|
||||||
type Result: IntoPyCallbackOutput<()>;
|
type Result: IntoPyCallbackOutput<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PyNumberITruedivProtocol<'p>: PyNumberProtocol<'p> {
|
pub trait PyNumberITruedivProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||||
type Other: FromPyObject<'p>;
|
type Other: FromPyObject<'p>;
|
||||||
type Result: IntoPyCallbackOutput<()>;
|
type Result: IntoPyCallbackOutput<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PyNumberIFloordivProtocol<'p>: PyNumberProtocol<'p> {
|
pub trait PyNumberIFloordivProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||||
type Other: FromPyObject<'p>;
|
type Other: FromPyObject<'p>;
|
||||||
type Result: IntoPyCallbackOutput<()>;
|
type Result: IntoPyCallbackOutput<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PyNumberIModProtocol<'p>: PyNumberProtocol<'p> {
|
pub trait PyNumberIModProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||||
type Other: FromPyObject<'p>;
|
type Other: FromPyObject<'p>;
|
||||||
type Result: IntoPyCallbackOutput<()>;
|
type Result: IntoPyCallbackOutput<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PyNumberIDivmodProtocol<'p>: PyNumberProtocol<'p> {
|
pub trait PyNumberIDivmodProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||||
type Other: FromPyObject<'p>;
|
type Other: FromPyObject<'p>;
|
||||||
type Result: IntoPyCallbackOutput<()>;
|
type Result: IntoPyCallbackOutput<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PyNumberIPowProtocol<'p>: PyNumberProtocol<'p> {
|
pub trait PyNumberIPowProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||||
type Other: FromPyObject<'p>;
|
type Other: FromPyObject<'p>;
|
||||||
type Result: IntoPyCallbackOutput<()>;
|
type Result: IntoPyCallbackOutput<()>;
|
||||||
// See https://bugs.python.org/issue36379
|
// See https://bugs.python.org/issue36379
|
||||||
type Modulo: FromPyObject<'p>;
|
type Modulo: FromPyObject<'p>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PyNumberILShiftProtocol<'p>: PyNumberProtocol<'p> {
|
pub trait PyNumberILShiftProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||||
type Other: FromPyObject<'p>;
|
type Other: FromPyObject<'p>;
|
||||||
type Result: IntoPyCallbackOutput<()>;
|
type Result: IntoPyCallbackOutput<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PyNumberIRShiftProtocol<'p>: PyNumberProtocol<'p> {
|
pub trait PyNumberIRShiftProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||||
type Other: FromPyObject<'p>;
|
type Other: FromPyObject<'p>;
|
||||||
type Result: IntoPyCallbackOutput<()>;
|
type Result: IntoPyCallbackOutput<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PyNumberIAndProtocol<'p>: PyNumberProtocol<'p> {
|
pub trait PyNumberIAndProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||||
type Other: FromPyObject<'p>;
|
type Other: FromPyObject<'p>;
|
||||||
type Result: IntoPyCallbackOutput<()>;
|
type Result: IntoPyCallbackOutput<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PyNumberIXorProtocol<'p>: PyNumberProtocol<'p> {
|
pub trait PyNumberIXorProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||||
type Other: FromPyObject<'p>;
|
type Other: FromPyObject<'p>;
|
||||||
type Result: IntoPyCallbackOutput<()>;
|
type Result: IntoPyCallbackOutput<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PyNumberIOrProtocol<'p>: PyNumberProtocol<'p> {
|
pub trait PyNumberIOrProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||||
type Other: FromPyObject<'p>;
|
type Other: FromPyObject<'p>;
|
||||||
type Result: IntoPyCallbackOutput<()>;
|
type Result: IntoPyCallbackOutput<()>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
use crate::callback::IntoPyCallbackOutput;
|
use crate::callback::IntoPyCallbackOutput;
|
||||||
use crate::conversion::{FromPyObject, IntoPy};
|
use crate::conversion::{FromPyObject, IntoPy};
|
||||||
use crate::err::PyErr;
|
use crate::err::PyErr;
|
||||||
use crate::{exceptions, ffi, PyAny, PyCell, PyClass, PyObject};
|
use crate::{exceptions, ffi, pyclass::MutablePyClass, PyAny, PyCell, PyClass, PyObject};
|
||||||
use std::os::raw::c_int;
|
use std::os::raw::c_int;
|
||||||
|
|
||||||
/// Sequence interface
|
/// Sequence interface
|
||||||
|
@ -88,13 +88,13 @@ pub trait PySequenceGetItemProtocol<'p>: PySequenceProtocol<'p> {
|
||||||
type Result: IntoPyCallbackOutput<PyObject>;
|
type Result: IntoPyCallbackOutput<PyObject>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PySequenceSetItemProtocol<'p>: PySequenceProtocol<'p> {
|
pub trait PySequenceSetItemProtocol<'p>: PySequenceProtocol<'p> + MutablePyClass {
|
||||||
type Index: FromPyObject<'p> + From<isize>;
|
type Index: FromPyObject<'p> + From<isize>;
|
||||||
type Value: FromPyObject<'p>;
|
type Value: FromPyObject<'p>;
|
||||||
type Result: IntoPyCallbackOutput<()>;
|
type Result: IntoPyCallbackOutput<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PySequenceDelItemProtocol<'p>: PySequenceProtocol<'p> {
|
pub trait PySequenceDelItemProtocol<'p>: PySequenceProtocol<'p> + MutablePyClass {
|
||||||
type Index: FromPyObject<'p> + From<isize>;
|
type Index: FromPyObject<'p> + From<isize>;
|
||||||
type Result: IntoPyCallbackOutput<()>;
|
type Result: IntoPyCallbackOutput<()>;
|
||||||
}
|
}
|
||||||
|
@ -115,14 +115,14 @@ pub trait PySequenceRepeatProtocol<'p>: PySequenceProtocol<'p> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PySequenceInplaceConcatProtocol<'p>:
|
pub trait PySequenceInplaceConcatProtocol<'p>:
|
||||||
PySequenceProtocol<'p> + IntoPy<PyObject> + 'p
|
PySequenceProtocol<'p> + IntoPy<PyObject> + MutablePyClass
|
||||||
{
|
{
|
||||||
type Other: FromPyObject<'p>;
|
type Other: FromPyObject<'p>;
|
||||||
type Result: IntoPyCallbackOutput<Self>;
|
type Result: IntoPyCallbackOutput<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PySequenceInplaceRepeatProtocol<'p>:
|
pub trait PySequenceInplaceRepeatProtocol<'p>:
|
||||||
PySequenceProtocol<'p> + IntoPy<PyObject> + 'p
|
PySequenceProtocol<'p> + IntoPy<PyObject> + MutablePyClass + 'p
|
||||||
{
|
{
|
||||||
type Index: FromPyObject<'p> + From<isize>;
|
type Index: FromPyObject<'p> + From<isize>;
|
||||||
type Result: IntoPyCallbackOutput<Self>;
|
type Result: IntoPyCallbackOutput<Self>;
|
||||||
|
|
|
@ -5,7 +5,8 @@ use crate::err::{self, PyDowncastError, PyResult};
|
||||||
use crate::type_object::PyTypeInfo;
|
use crate::type_object::PyTypeInfo;
|
||||||
use crate::types::PyTuple;
|
use crate::types::PyTuple;
|
||||||
use crate::{
|
use crate::{
|
||||||
ffi, gil, Py, PyAny, PyCell, PyClass, PyNativeType, PyObject, PyRef, PyRefMut, Python,
|
ffi, gil, pyclass::MutablePyClass, Py, PyAny, PyCell, PyClass, PyNativeType, PyObject, PyRef,
|
||||||
|
PyRefMut, Python,
|
||||||
};
|
};
|
||||||
use std::ptr::NonNull;
|
use std::ptr::NonNull;
|
||||||
|
|
||||||
|
@ -329,7 +330,7 @@ where
|
||||||
|
|
||||||
impl<'a, T> FromPyObject<'a> for PyRefMut<'a, T>
|
impl<'a, T> FromPyObject<'a> for PyRefMut<'a, T>
|
||||||
where
|
where
|
||||||
T: PyClass,
|
T: MutablePyClass,
|
||||||
{
|
{
|
||||||
fn extract(obj: &'a PyAny) -> PyResult<Self> {
|
fn extract(obj: &'a PyAny) -> PyResult<Self> {
|
||||||
let cell: &PyCell<T> = PyTryFrom::try_from(obj)?;
|
let cell: &PyCell<T> = PyTryFrom::try_from(obj)?;
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::{
|
||||||
exceptions::{PyAttributeError, PyNotImplementedError},
|
exceptions::{PyAttributeError, PyNotImplementedError},
|
||||||
ffi,
|
ffi,
|
||||||
impl_::freelist::FreeList,
|
impl_::freelist::FreeList,
|
||||||
pycell::PyCellLayout,
|
pycell::{Mutability, PyCellLayout},
|
||||||
pyclass_init::PyObjectInit,
|
pyclass_init::PyObjectInit,
|
||||||
type_object::{PyLayout, PyTypeObject},
|
type_object::{PyLayout, PyTypeObject},
|
||||||
PyCell, PyClass, PyMethodDefType, PyNativeType, PyResult, PyTypeInfo, Python,
|
PyCell, PyClass, PyMethodDefType, PyNativeType, PyResult, PyTypeInfo, Python,
|
||||||
|
@ -145,7 +145,7 @@ unsafe impl Sync for PyClassItems {}
|
||||||
///
|
///
|
||||||
/// Users are discouraged from implementing this trait manually; it is a PyO3 implementation detail
|
/// Users are discouraged from implementing this trait manually; it is a PyO3 implementation detail
|
||||||
/// and may be changed at any time.
|
/// and may be changed at any time.
|
||||||
pub trait PyClassImpl: Sized {
|
pub trait PyClassImpl<M: Mutability>: Sized {
|
||||||
/// Class doc string
|
/// Class doc string
|
||||||
const DOC: &'static str = "\0";
|
const DOC: &'static str = "\0";
|
||||||
|
|
||||||
|
@ -162,7 +162,7 @@ pub trait PyClassImpl: Sized {
|
||||||
type Layout: PyLayout<Self>;
|
type Layout: PyLayout<Self>;
|
||||||
|
|
||||||
/// Base class
|
/// Base class
|
||||||
type BaseType: PyTypeInfo + PyTypeObject + PyClassBaseType;
|
type BaseType: PyTypeInfo + PyTypeObject + PyClassBaseType<M>;
|
||||||
|
|
||||||
/// This handles following two situations:
|
/// This handles following two situations:
|
||||||
/// 1. In case `T` is `Send`, stub `ThreadChecker` is used and does nothing.
|
/// 1. In case `T` is `Send`, stub `ThreadChecker` is used and does nothing.
|
||||||
|
@ -818,9 +818,14 @@ impl<T> PyClassThreadChecker<T> for ThreadCheckerImpl<T> {
|
||||||
/// Thread checker for types that have `Send` and `extends=...`.
|
/// Thread checker for types that have `Send` and `extends=...`.
|
||||||
/// Ensures that `T: Send` and the parent is not accessed by another thread.
|
/// Ensures that `T: Send` and the parent is not accessed by another thread.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub struct ThreadCheckerInherited<T: Send, U: PyClassBaseType>(PhantomData<T>, U::ThreadChecker);
|
pub struct ThreadCheckerInherited<T: Send, U: PyClassBaseType<M>, M: Mutability>(
|
||||||
|
PhantomData<T>,
|
||||||
|
U::ThreadChecker,
|
||||||
|
);
|
||||||
|
|
||||||
impl<T: Send, U: PyClassBaseType> PyClassThreadChecker<T> for ThreadCheckerInherited<T, U> {
|
impl<T: Send, U: PyClassBaseType<M>, M: Mutability> PyClassThreadChecker<T>
|
||||||
|
for ThreadCheckerInherited<T, U, M>
|
||||||
|
{
|
||||||
fn ensure(&self) {
|
fn ensure(&self) {
|
||||||
self.1.ensure();
|
self.1.ensure();
|
||||||
}
|
}
|
||||||
|
@ -831,15 +836,15 @@ impl<T: Send, U: PyClassBaseType> PyClassThreadChecker<T> for ThreadCheckerInher
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait denoting that this class is suitable to be used as a base type for PyClass.
|
/// Trait denoting that this class is suitable to be used as a base type for PyClass.
|
||||||
pub trait PyClassBaseType: Sized {
|
pub trait PyClassBaseType<M: Mutability>: Sized {
|
||||||
type LayoutAsBase: PyCellLayout<Self>;
|
type LayoutAsBase: PyCellLayout<Self, M>;
|
||||||
type BaseNativeType;
|
type BaseNativeType;
|
||||||
type ThreadChecker: PyClassThreadChecker<Self>;
|
type ThreadChecker: PyClassThreadChecker<Self>;
|
||||||
type Initializer: PyObjectInit<Self>;
|
type Initializer: PyObjectInit<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// All PyClasses can be used as a base type.
|
/// All PyClasses can be used as a base type.
|
||||||
impl<T: PyClass> PyClassBaseType for T {
|
impl<T: PyClass> PyClassBaseType<T::Mutability> for T {
|
||||||
type LayoutAsBase = crate::pycell::PyCell<T>;
|
type LayoutAsBase = crate::pycell::PyCell<T>;
|
||||||
type BaseNativeType = T::BaseNativeType;
|
type BaseNativeType = T::BaseNativeType;
|
||||||
type ThreadChecker = T::ThreadChecker;
|
type ThreadChecker = T::ThreadChecker;
|
||||||
|
|
|
@ -5,8 +5,8 @@ use crate::gil;
|
||||||
use crate::pycell::{PyBorrowError, PyBorrowMutError, PyCell};
|
use crate::pycell::{PyBorrowError, PyBorrowMutError, PyCell};
|
||||||
use crate::types::{PyDict, PyTuple};
|
use crate::types::{PyDict, PyTuple};
|
||||||
use crate::{
|
use crate::{
|
||||||
ffi, AsPyPointer, FromPyObject, IntoPy, IntoPyPointer, PyAny, PyClass, PyClassInitializer,
|
ffi, pyclass::MutablePyClass, AsPyPointer, FromPyObject, IntoPy, IntoPyPointer, PyAny, PyClass,
|
||||||
PyRef, PyRefMut, PyTypeInfo, Python, ToPyObject,
|
PyClassInitializer, PyRef, PyRefMut, PyTypeInfo, Python, ToPyObject,
|
||||||
};
|
};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
@ -427,7 +427,10 @@ where
|
||||||
/// # Panics
|
/// # Panics
|
||||||
/// Panics if the value is currently mutably borrowed. For a non-panicking variant, use
|
/// Panics if the value is currently mutably borrowed. For a non-panicking variant, use
|
||||||
/// [`try_borrow_mut`](#method.try_borrow_mut).
|
/// [`try_borrow_mut`](#method.try_borrow_mut).
|
||||||
pub fn borrow_mut<'py>(&'py self, py: Python<'py>) -> PyRefMut<'py, T> {
|
pub fn borrow_mut<'py>(&'py self, py: Python<'py>) -> PyRefMut<'py, T>
|
||||||
|
where
|
||||||
|
T: MutablePyClass,
|
||||||
|
{
|
||||||
self.as_ref(py).borrow_mut()
|
self.as_ref(py).borrow_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -454,7 +457,10 @@ where
|
||||||
pub fn try_borrow_mut<'py>(
|
pub fn try_borrow_mut<'py>(
|
||||||
&'py self,
|
&'py self,
|
||||||
py: Python<'py>,
|
py: Python<'py>,
|
||||||
) -> Result<PyRefMut<'py, T>, PyBorrowMutError> {
|
) -> Result<PyRefMut<'py, T>, PyBorrowMutError>
|
||||||
|
where
|
||||||
|
T: MutablePyClass,
|
||||||
|
{
|
||||||
self.as_ref(py).try_borrow_mut()
|
self.as_ref(py).try_borrow_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -819,7 +825,7 @@ where
|
||||||
|
|
||||||
impl<'a, T> std::convert::From<PyRefMut<'a, T>> for Py<T>
|
impl<'a, T> std::convert::From<PyRefMut<'a, T>> for Py<T>
|
||||||
where
|
where
|
||||||
T: PyClass,
|
T: MutablePyClass,
|
||||||
{
|
{
|
||||||
fn from(pyref: PyRefMut<'a, T>) -> Self {
|
fn from(pyref: PyRefMut<'a, T>) -> Self {
|
||||||
unsafe { Py::from_borrowed_ptr(pyref.py(), pyref.as_ptr()) }
|
unsafe { Py::from_borrowed_ptr(pyref.py(), pyref.as_ptr()) }
|
||||||
|
|
230
src/pycell.rs
230
src/pycell.rs
|
@ -176,7 +176,7 @@
|
||||||
|
|
||||||
use crate::exceptions::PyRuntimeError;
|
use crate::exceptions::PyRuntimeError;
|
||||||
use crate::impl_::pyclass::{PyClassBaseType, PyClassDict, PyClassThreadChecker, PyClassWeakRef};
|
use crate::impl_::pyclass::{PyClassBaseType, PyClassDict, PyClassThreadChecker, PyClassWeakRef};
|
||||||
use crate::pyclass::PyClass;
|
use crate::pyclass::{MutablePyClass, PyClass};
|
||||||
use crate::pyclass_init::PyClassInitializer;
|
use crate::pyclass_init::PyClassInitializer;
|
||||||
use crate::type_object::{PyLayout, PySizedLayout};
|
use crate::type_object::{PyLayout, PySizedLayout};
|
||||||
use crate::types::PyAny;
|
use crate::types::PyAny;
|
||||||
|
@ -189,19 +189,117 @@ use crate::{
|
||||||
use crate::{ffi, IntoPy, PyErr, PyNativeType, PyObject, PyResult, Python};
|
use crate::{ffi, IntoPy, PyErr, PyNativeType, PyObject, PyResult, Python};
|
||||||
use std::cell::{Cell, UnsafeCell};
|
use std::cell::{Cell, UnsafeCell};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::marker::PhantomData;
|
||||||
use std::mem::ManuallyDrop;
|
use std::mem::ManuallyDrop;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
|
pub trait Mutability {
|
||||||
|
/// Creates a new borrow checker
|
||||||
|
fn new() -> Self;
|
||||||
|
/// Increments immutable borrow count, if possible
|
||||||
|
fn try_borrow(&self) -> Result<(), PyBorrowError>;
|
||||||
|
|
||||||
|
fn try_borrow_unguarded(&self) -> Result<(), PyBorrowError>;
|
||||||
|
|
||||||
|
/// Decrements immutable borrow count
|
||||||
|
fn release_borrow(&self);
|
||||||
|
/// Increments mutable borrow count, if possible
|
||||||
|
fn try_borrow_mut(&self) -> Result<(), PyBorrowMutError>;
|
||||||
|
/// Decremements mutable borrow count
|
||||||
|
fn release_borrow_mut(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Mutable {
|
||||||
|
flag: Cell<BorrowFlag>,
|
||||||
|
}
|
||||||
|
impl Mutability for Mutable {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
flag: Cell::new(BorrowFlag::UNUSED),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_borrow(&self) -> Result<(), PyBorrowError> {
|
||||||
|
let flag = self.flag.get();
|
||||||
|
if flag != BorrowFlag::HAS_MUTABLE_BORROW {
|
||||||
|
self.flag.set(flag.increment());
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(PyBorrowError { _private: () })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_borrow_unguarded(&self) -> Result<(), PyBorrowError> {
|
||||||
|
let flag = self.flag.get();
|
||||||
|
if flag != BorrowFlag::HAS_MUTABLE_BORROW {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(PyBorrowError { _private: () })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn release_borrow(&self) {
|
||||||
|
let flag = self.flag.get();
|
||||||
|
self.flag.set(flag.decrement())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_borrow_mut(&self) -> Result<(), PyBorrowMutError> {
|
||||||
|
let flag = self.flag.get();
|
||||||
|
if flag == BorrowFlag::UNUSED {
|
||||||
|
self.flag.set(BorrowFlag::HAS_MUTABLE_BORROW);
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(PyBorrowMutError { _private: () })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn release_borrow_mut(&self) {
|
||||||
|
self.flag.set(BorrowFlag::UNUSED)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Immutable {
|
||||||
|
flag: PhantomData<Cell<BorrowFlag>>,
|
||||||
|
}
|
||||||
|
impl Mutability for Immutable {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self { flag: PhantomData }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_borrow(&self) -> Result<(), PyBorrowError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_borrow_unguarded(&self) -> Result<(), PyBorrowError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn release_borrow(&self) {}
|
||||||
|
|
||||||
|
fn try_borrow_mut(&self) -> Result<(), PyBorrowMutError> {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn release_borrow_mut(&self) {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Base layout of PyCell.
|
/// Base layout of PyCell.
|
||||||
/// This is necessary for sharing BorrowFlag between parents and children.
|
/// This is necessary for sharing BorrowFlag between parents and children.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct PyCellBase<T> {
|
pub struct PyCellBase<T, M: Mutability> {
|
||||||
ob_base: T,
|
ob_base: T,
|
||||||
borrow_flag: Cell<BorrowFlag>,
|
borrow_impl: M,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T, U> PyLayout<T> for PyCellBase<U> where U: PySizedLayout<T> {}
|
unsafe impl<T, U, M> PyLayout<T> for PyCellBase<U, M>
|
||||||
|
where
|
||||||
|
U: PySizedLayout<T>,
|
||||||
|
M: Mutability,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// A container type for (mutably) accessing [`PyClass`] values
|
/// A container type for (mutably) accessing [`PyClass`] values
|
||||||
///
|
///
|
||||||
|
@ -240,7 +338,7 @@ unsafe impl<T, U> PyLayout<T> for PyCellBase<U> where U: PySizedLayout<T> {}
|
||||||
/// [module-level documentation](self).
|
/// [module-level documentation](self).
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct PyCell<T: PyClass> {
|
pub struct PyCell<T: PyClass> {
|
||||||
ob_base: <T::BaseType as PyClassBaseType>::LayoutAsBase,
|
ob_base: <T::BaseType as PyClassBaseType<T::Mutability>>::LayoutAsBase,
|
||||||
contents: PyCellContents<T>,
|
contents: PyCellContents<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,7 +381,10 @@ impl<T: PyClass> PyCell<T> {
|
||||||
///
|
///
|
||||||
/// Panics if the value is currently borrowed. For a non-panicking variant, use
|
/// Panics if the value is currently borrowed. For a non-panicking variant, use
|
||||||
/// [`try_borrow_mut`](#method.try_borrow_mut).
|
/// [`try_borrow_mut`](#method.try_borrow_mut).
|
||||||
pub fn borrow_mut(&self) -> PyRefMut<'_, T> {
|
pub fn borrow_mut(&self) -> PyRefMut<'_, T>
|
||||||
|
where
|
||||||
|
T: MutablePyClass,
|
||||||
|
{
|
||||||
self.try_borrow_mut().expect("Already borrowed")
|
self.try_borrow_mut().expect("Already borrowed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,13 +414,9 @@ impl<T: PyClass> PyCell<T> {
|
||||||
/// });
|
/// });
|
||||||
/// ```
|
/// ```
|
||||||
pub fn try_borrow(&self) -> Result<PyRef<'_, T>, PyBorrowError> {
|
pub fn try_borrow(&self) -> Result<PyRef<'_, T>, PyBorrowError> {
|
||||||
let flag = self.get_borrow_flag();
|
self.borrow_checker()
|
||||||
if flag == BorrowFlag::HAS_MUTABLE_BORROW {
|
.try_borrow()
|
||||||
Err(PyBorrowError { _private: () })
|
.map(|_| PyRef { inner: self })
|
||||||
} else {
|
|
||||||
self.set_borrow_flag(flag.increment());
|
|
||||||
Ok(PyRef { inner: self })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mutably borrows the value `T`, returning an error if the value is currently borrowed.
|
/// Mutably borrows the value `T`, returning an error if the value is currently borrowed.
|
||||||
|
@ -343,13 +440,13 @@ impl<T: PyClass> PyCell<T> {
|
||||||
/// assert!(c.try_borrow_mut().is_ok());
|
/// assert!(c.try_borrow_mut().is_ok());
|
||||||
/// });
|
/// });
|
||||||
/// ```
|
/// ```
|
||||||
pub fn try_borrow_mut(&self) -> Result<PyRefMut<'_, T>, PyBorrowMutError> {
|
pub fn try_borrow_mut(&self) -> Result<PyRefMut<'_, T>, PyBorrowMutError>
|
||||||
if self.get_borrow_flag() != BorrowFlag::UNUSED {
|
where
|
||||||
Err(PyBorrowMutError { _private: () })
|
T: MutablePyClass,
|
||||||
} else {
|
{
|
||||||
self.set_borrow_flag(BorrowFlag::HAS_MUTABLE_BORROW);
|
self.borrow_checker()
|
||||||
Ok(PyRefMut { inner: self })
|
.try_borrow_mut()
|
||||||
}
|
.map(|_| PyRefMut { inner: self })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Immutably borrows the value `T`, returning an error if the value is
|
/// Immutably borrows the value `T`, returning an error if the value is
|
||||||
|
@ -382,11 +479,9 @@ impl<T: PyClass> PyCell<T> {
|
||||||
/// });
|
/// });
|
||||||
/// ```
|
/// ```
|
||||||
pub unsafe fn try_borrow_unguarded(&self) -> Result<&T, PyBorrowError> {
|
pub unsafe fn try_borrow_unguarded(&self) -> Result<&T, PyBorrowError> {
|
||||||
if self.get_borrow_flag() == BorrowFlag::HAS_MUTABLE_BORROW {
|
self.borrow_checker()
|
||||||
Err(PyBorrowError { _private: () })
|
.try_borrow_unguarded()
|
||||||
} else {
|
.map(|_: ()| &*self.contents.value.get())
|
||||||
Ok(&*self.contents.value.get())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Replaces the wrapped value with a new one, returning the old value.
|
/// Replaces the wrapped value with a new one, returning the old value.
|
||||||
|
@ -395,7 +490,10 @@ impl<T: PyClass> PyCell<T> {
|
||||||
///
|
///
|
||||||
/// Panics if the value is currently borrowed.
|
/// Panics if the value is currently borrowed.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn replace(&self, t: T) -> T {
|
pub fn replace(&self, t: T) -> T
|
||||||
|
where
|
||||||
|
T: MutablePyClass,
|
||||||
|
{
|
||||||
std::mem::replace(&mut *self.borrow_mut(), t)
|
std::mem::replace(&mut *self.borrow_mut(), t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -404,7 +502,10 @@ impl<T: PyClass> PyCell<T> {
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if the value is currently borrowed.
|
/// Panics if the value is currently borrowed.
|
||||||
pub fn replace_with<F: FnOnce(&mut T) -> T>(&self, f: F) -> T {
|
pub fn replace_with<F: FnOnce(&mut T) -> T>(&self, f: F) -> T
|
||||||
|
where
|
||||||
|
T: MutablePyClass,
|
||||||
|
{
|
||||||
let mut_borrow = &mut *self.borrow_mut();
|
let mut_borrow = &mut *self.borrow_mut();
|
||||||
let replacement = f(mut_borrow);
|
let replacement = f(mut_borrow);
|
||||||
std::mem::replace(mut_borrow, replacement)
|
std::mem::replace(mut_borrow, replacement)
|
||||||
|
@ -416,7 +517,10 @@ impl<T: PyClass> PyCell<T> {
|
||||||
///
|
///
|
||||||
/// Panics if the value in either `PyCell` is currently borrowed.
|
/// Panics if the value in either `PyCell` is currently borrowed.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn swap(&self, other: &Self) {
|
pub fn swap(&self, other: &Self)
|
||||||
|
where
|
||||||
|
T: MutablePyClass,
|
||||||
|
{
|
||||||
std::mem::swap(&mut *self.borrow_mut(), &mut *other.borrow_mut())
|
std::mem::swap(&mut *self.borrow_mut(), &mut *other.borrow_mut())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -674,8 +778,7 @@ impl<'p, T: PyClass> Deref for PyRef<'p, T> {
|
||||||
|
|
||||||
impl<'p, T: PyClass> Drop for PyRef<'p, T> {
|
impl<'p, T: PyClass> Drop for PyRef<'p, T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let flag = self.inner.get_borrow_flag();
|
self.inner.borrow_checker().release_borrow()
|
||||||
self.inner.set_borrow_flag(flag.decrement())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -707,11 +810,11 @@ impl<T: PyClass + fmt::Debug> fmt::Debug for PyRef<'_, T> {
|
||||||
/// A wrapper type for a mutably borrowed value from a[`PyCell`]`<T>`.
|
/// A wrapper type for a mutably borrowed value from a[`PyCell`]`<T>`.
|
||||||
///
|
///
|
||||||
/// See the [module-level documentation](self) for more information.
|
/// See the [module-level documentation](self) for more information.
|
||||||
pub struct PyRefMut<'p, T: PyClass> {
|
pub struct PyRefMut<'p, T: MutablePyClass> {
|
||||||
inner: &'p PyCell<T>,
|
inner: &'p PyCell<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'p, T: PyClass> PyRefMut<'p, T> {
|
impl<'p, T: MutablePyClass> PyRefMut<'p, T> {
|
||||||
/// Returns a `Python` token that is bound to the lifetime of the `PyRefMut`.
|
/// Returns a `Python` token that is bound to the lifetime of the `PyRefMut`.
|
||||||
pub fn py(&self) -> Python {
|
pub fn py(&self) -> Python {
|
||||||
unsafe { Python::assume_gil_acquired() }
|
unsafe { Python::assume_gil_acquired() }
|
||||||
|
@ -720,8 +823,8 @@ impl<'p, T: PyClass> PyRefMut<'p, T> {
|
||||||
|
|
||||||
impl<'p, T, U> AsRef<U> for PyRefMut<'p, T>
|
impl<'p, T, U> AsRef<U> for PyRefMut<'p, T>
|
||||||
where
|
where
|
||||||
T: PyClass<BaseType = U>,
|
T: PyClass<BaseType = U> + MutablePyClass,
|
||||||
U: PyClass,
|
U: MutablePyClass,
|
||||||
{
|
{
|
||||||
fn as_ref(&self) -> &T::BaseType {
|
fn as_ref(&self) -> &T::BaseType {
|
||||||
unsafe { &*self.inner.ob_base.get_ptr() }
|
unsafe { &*self.inner.ob_base.get_ptr() }
|
||||||
|
@ -730,8 +833,8 @@ where
|
||||||
|
|
||||||
impl<'p, T, U> AsMut<U> for PyRefMut<'p, T>
|
impl<'p, T, U> AsMut<U> for PyRefMut<'p, T>
|
||||||
where
|
where
|
||||||
T: PyClass<BaseType = U>,
|
T: PyClass<BaseType = U> + MutablePyClass,
|
||||||
U: PyClass,
|
U: MutablePyClass,
|
||||||
{
|
{
|
||||||
fn as_mut(&mut self) -> &mut T::BaseType {
|
fn as_mut(&mut self) -> &mut T::BaseType {
|
||||||
unsafe { &mut *self.inner.ob_base.get_ptr() }
|
unsafe { &mut *self.inner.ob_base.get_ptr() }
|
||||||
|
@ -740,8 +843,8 @@ where
|
||||||
|
|
||||||
impl<'p, T, U> PyRefMut<'p, T>
|
impl<'p, T, U> PyRefMut<'p, T>
|
||||||
where
|
where
|
||||||
T: PyClass<BaseType = U>,
|
T: PyClass<BaseType = U> + MutablePyClass,
|
||||||
U: PyClass,
|
U: MutablePyClass,
|
||||||
{
|
{
|
||||||
/// Gets a `PyRef<T::BaseType>`.
|
/// Gets a `PyRef<T::BaseType>`.
|
||||||
///
|
///
|
||||||
|
@ -755,7 +858,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'p, T: PyClass> Deref for PyRefMut<'p, T> {
|
impl<'p, T: MutablePyClass> Deref for PyRefMut<'p, T> {
|
||||||
type Target = T;
|
type Target = T;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -764,46 +867,46 @@ impl<'p, T: PyClass> Deref for PyRefMut<'p, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'p, T: PyClass> DerefMut for PyRefMut<'p, T> {
|
impl<'p, T: MutablePyClass> DerefMut for PyRefMut<'p, T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn deref_mut(&mut self) -> &mut T {
|
fn deref_mut(&mut self) -> &mut T {
|
||||||
unsafe { &mut *self.inner.get_ptr() }
|
unsafe { &mut *self.inner.get_ptr() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'p, T: PyClass> Drop for PyRefMut<'p, T> {
|
impl<'p, T: MutablePyClass> Drop for PyRefMut<'p, T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.inner.set_borrow_flag(BorrowFlag::UNUSED)
|
self.inner.borrow_checker().release_borrow_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: PyClass> IntoPy<PyObject> for PyRefMut<'_, T> {
|
impl<T: MutablePyClass> IntoPy<PyObject> for PyRefMut<'_, T> {
|
||||||
fn into_py(self, py: Python) -> PyObject {
|
fn into_py(self, py: Python) -> PyObject {
|
||||||
unsafe { PyObject::from_borrowed_ptr(py, self.inner.as_ptr()) }
|
unsafe { PyObject::from_borrowed_ptr(py, self.inner.as_ptr()) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: PyClass> AsPyPointer for PyRefMut<'a, T> {
|
impl<'a, T: MutablePyClass> AsPyPointer for PyRefMut<'a, T> {
|
||||||
fn as_ptr(&self) -> *mut ffi::PyObject {
|
fn as_ptr(&self) -> *mut ffi::PyObject {
|
||||||
self.inner.as_ptr()
|
self.inner.as_ptr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: PyClass> std::convert::TryFrom<&'a PyCell<T>> for crate::PyRefMut<'a, T> {
|
impl<'a, T: MutablePyClass> std::convert::TryFrom<&'a PyCell<T>> for crate::PyRefMut<'a, T> {
|
||||||
type Error = PyBorrowMutError;
|
type Error = PyBorrowMutError;
|
||||||
fn try_from(cell: &'a crate::PyCell<T>) -> Result<Self, Self::Error> {
|
fn try_from(cell: &'a crate::PyCell<T>) -> Result<Self, Self::Error> {
|
||||||
cell.try_borrow_mut()
|
cell.try_borrow_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: PyClass + fmt::Debug> fmt::Debug for PyRefMut<'_, T> {
|
impl<T: MutablePyClass + fmt::Debug> fmt::Debug for PyRefMut<'_, T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
fmt::Debug::fmt(&*(self.deref()), f)
|
fmt::Debug::fmt(&*(self.deref()), f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
pub struct BorrowFlag(usize);
|
pub struct BorrowFlag(usize);
|
||||||
|
|
||||||
impl BorrowFlag {
|
impl BorrowFlag {
|
||||||
|
@ -868,9 +971,11 @@ impl From<PyBorrowMutError> for PyErr {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub trait PyCellLayout<T>: PyLayout<T> {
|
pub trait PyCellLayout<T, M>: PyLayout<T>
|
||||||
fn get_borrow_flag(&self) -> BorrowFlag;
|
where
|
||||||
fn set_borrow_flag(&self, flag: BorrowFlag);
|
M: Mutability,
|
||||||
|
{
|
||||||
|
fn borrow_checker(&self) -> &M;
|
||||||
/// Implementation of tp_dealloc.
|
/// Implementation of tp_dealloc.
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// - slf must be a valid pointer to an instance of a T or a subclass.
|
/// - slf must be a valid pointer to an instance of a T or a subclass.
|
||||||
|
@ -878,17 +983,16 @@ pub trait PyCellLayout<T>: PyLayout<T> {
|
||||||
unsafe fn tp_dealloc(slf: *mut ffi::PyObject, py: Python);
|
unsafe fn tp_dealloc(slf: *mut ffi::PyObject, py: Python);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, U> PyCellLayout<T> for PyCellBase<U>
|
impl<T, U, M> PyCellLayout<T, M> for PyCellBase<U, M>
|
||||||
where
|
where
|
||||||
U: PySizedLayout<T>,
|
U: PySizedLayout<T>,
|
||||||
T: PyTypeInfo,
|
T: PyTypeInfo,
|
||||||
|
M: Mutability,
|
||||||
{
|
{
|
||||||
fn get_borrow_flag(&self) -> BorrowFlag {
|
fn borrow_checker(&self) -> &M {
|
||||||
self.borrow_flag.get()
|
&self.borrow_impl
|
||||||
}
|
|
||||||
fn set_borrow_flag(&self, flag: BorrowFlag) {
|
|
||||||
self.borrow_flag.set(flag)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn tp_dealloc(slf: *mut ffi::PyObject, py: Python) {
|
unsafe fn tp_dealloc(slf: *mut ffi::PyObject, py: Python) {
|
||||||
// For `#[pyclass]` types which inherit from PyAny, we can just call tp_free
|
// For `#[pyclass]` types which inherit from PyAny, we can just call tp_free
|
||||||
if T::type_object_raw(py) == &mut PyBaseObject_Type {
|
if T::type_object_raw(py) == &mut PyBaseObject_Type {
|
||||||
|
@ -910,16 +1014,14 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: PyClass> PyCellLayout<T> for PyCell<T>
|
impl<T: PyClass> PyCellLayout<T, T::Mutability> for PyCell<T>
|
||||||
where
|
where
|
||||||
<T::BaseType as PyClassBaseType>::LayoutAsBase: PyCellLayout<T::BaseType>,
|
<T::BaseType as PyClassBaseType<T::Mutability>>::LayoutAsBase:
|
||||||
|
PyCellLayout<T::BaseType, T::Mutability>,
|
||||||
{
|
{
|
||||||
fn get_borrow_flag(&self) -> BorrowFlag {
|
fn borrow_checker(&self) -> &T::Mutability {
|
||||||
self.contents.thread_checker.ensure();
|
self.contents.thread_checker.ensure();
|
||||||
self.ob_base.get_borrow_flag()
|
self.ob_base.borrow_checker()
|
||||||
}
|
|
||||||
fn set_borrow_flag(&self, flag: BorrowFlag) {
|
|
||||||
self.ob_base.set_borrow_flag(flag)
|
|
||||||
}
|
}
|
||||||
unsafe fn tp_dealloc(slf: *mut ffi::PyObject, py: Python) {
|
unsafe fn tp_dealloc(slf: *mut ffi::PyObject, py: Python) {
|
||||||
// Safety: Python only calls tp_dealloc when no references to the object remain.
|
// Safety: Python only calls tp_dealloc when no references to the object remain.
|
||||||
|
@ -927,6 +1029,6 @@ where
|
||||||
ManuallyDrop::drop(&mut cell.contents.value);
|
ManuallyDrop::drop(&mut cell.contents.value);
|
||||||
cell.contents.dict.clear_dict(py);
|
cell.contents.dict.clear_dict(py);
|
||||||
cell.contents.weakref.clear_weakrefs(slf, py);
|
cell.contents.weakref.clear_weakrefs(slf, py);
|
||||||
<T::BaseType as PyClassBaseType>::LayoutAsBase::tp_dealloc(slf, py)
|
<T::BaseType as PyClassBaseType<T::Mutability>>::LayoutAsBase::tp_dealloc(slf, py)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
//! `PyClass` and related traits.
|
//! `PyClass` and related traits.
|
||||||
|
use crate::pycell::Mutability;
|
||||||
use crate::{
|
use crate::{
|
||||||
callback::IntoPyCallbackOutput,
|
callback::IntoPyCallbackOutput,
|
||||||
ffi,
|
ffi,
|
||||||
|
@ -22,7 +23,7 @@ use std::{
|
||||||
/// The `#[pyclass]` attribute automatically implements this trait for your Rust struct,
|
/// The `#[pyclass]` attribute automatically implements this trait for your Rust struct,
|
||||||
/// so you normally don't have to use this trait directly.
|
/// so you normally don't have to use this trait directly.
|
||||||
pub trait PyClass:
|
pub trait PyClass:
|
||||||
PyTypeInfo<AsRefTarget = PyCell<Self>> + PyClassImpl<Layout = PyCell<Self>>
|
PyTypeInfo<AsRefTarget = PyCell<Self>> + PyClassImpl<Self::Mutability, Layout = PyCell<Self>>
|
||||||
{
|
{
|
||||||
/// Specify this class has `#[pyclass(dict)]` or not.
|
/// Specify this class has `#[pyclass(dict)]` or not.
|
||||||
type Dict: PyClassDict;
|
type Dict: PyClassDict;
|
||||||
|
@ -31,8 +32,13 @@ pub trait PyClass:
|
||||||
/// The closest native ancestor. This is `PyAny` by default, and when you declare
|
/// The closest native ancestor. This is `PyAny` by default, and when you declare
|
||||||
/// `#[pyclass(extends=PyDict)]`, it's `PyDict`.
|
/// `#[pyclass(extends=PyDict)]`, it's `PyDict`.
|
||||||
type BaseNativeType: PyTypeInfo + PyNativeType;
|
type BaseNativeType: PyTypeInfo + PyNativeType;
|
||||||
|
|
||||||
|
type Mutability: Mutability;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub unsafe trait MutablePyClass: PyClass {}
|
||||||
|
pub unsafe trait ImmutablePyClass: PyClass {}
|
||||||
|
|
||||||
fn into_raw<T>(vec: Vec<T>) -> *mut c_void {
|
fn into_raw<T>(vec: Vec<T>) -> *mut c_void {
|
||||||
Box::into_raw(vec.into_boxed_slice()) as _
|
Box::into_raw(vec.into_boxed_slice()) as _
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,14 +130,17 @@ impl<T: PyTypeInfo> PyObjectInit<T> for PyNativeTypeInitializer<T> {
|
||||||
/// ```
|
/// ```
|
||||||
pub struct PyClassInitializer<T: PyClass> {
|
pub struct PyClassInitializer<T: PyClass> {
|
||||||
init: T,
|
init: T,
|
||||||
super_init: <T::BaseType as PyClassBaseType>::Initializer,
|
super_init: <T::BaseType as PyClassBaseType<T::Mutability>>::Initializer,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: PyClass> PyClassInitializer<T> {
|
impl<T: PyClass> PyClassInitializer<T> {
|
||||||
/// Constructs a new initializer from value `T` and base class' initializer.
|
/// Constructs a new initializer from value `T` and base class' initializer.
|
||||||
///
|
///
|
||||||
/// It is recommended to use `add_subclass` instead of this method for most usage.
|
/// It is recommended to use `add_subclass` instead of this method for most usage.
|
||||||
pub fn new(init: T, super_init: <T::BaseType as PyClassBaseType>::Initializer) -> Self {
|
pub fn new(
|
||||||
|
init: T,
|
||||||
|
super_init: <T::BaseType as PyClassBaseType<T::Mutability>>::Initializer,
|
||||||
|
) -> Self {
|
||||||
Self { init, super_init }
|
Self { init, super_init }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +193,7 @@ impl<T: PyClass> PyClassInitializer<T> {
|
||||||
pub fn add_subclass<S>(self, subclass_value: S) -> PyClassInitializer<S>
|
pub fn add_subclass<S>(self, subclass_value: S) -> PyClassInitializer<S>
|
||||||
where
|
where
|
||||||
S: PyClass<BaseType = T>,
|
S: PyClass<BaseType = T>,
|
||||||
S::BaseType: PyClassBaseType<Initializer = Self>,
|
S::BaseType: PyClassBaseType<T::Mutability, Initializer = Self>,
|
||||||
{
|
{
|
||||||
PyClassInitializer::new(subclass_value, self)
|
PyClassInitializer::new(subclass_value, self)
|
||||||
}
|
}
|
||||||
|
@ -231,16 +234,16 @@ impl<T: PyClass> PyObjectInit<T> for PyClassInitializer<T> {
|
||||||
/// Layout of a PyCellBase after base new has been called, but the borrow flag has not
|
/// Layout of a PyCellBase after base new has been called, but the borrow flag has not
|
||||||
/// yet been initialized.
|
/// yet been initialized.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct PartiallyInitializedPyCellBase<T> {
|
struct PartiallyInitializedPyCellBase<T: PyClass> {
|
||||||
_ob_base: T,
|
_ob_base: T,
|
||||||
borrow_flag: MaybeUninit<Cell<BorrowFlag>>,
|
borrow_flag: MaybeUninit<T::Mutability>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Layout of a PyCell after base new has been called, but the contents have not yet been
|
/// Layout of a PyCell after base new has been called, but the contents have not yet been
|
||||||
/// written.
|
/// written.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct PartiallyInitializedPyCell<T: PyClass> {
|
struct PartiallyInitializedPyCell<T: PyClass> {
|
||||||
_ob_base: <T::BaseType as PyClassBaseType>::LayoutAsBase,
|
_ob_base: <T::BaseType as PyClassBaseType<T::Mutability>>::LayoutAsBase,
|
||||||
contents: MaybeUninit<PyCellContents<T>>,
|
contents: MaybeUninit<PyCellContents<T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,7 +277,7 @@ impl<T: PyClass> PyObjectInit<T> for PyClassInitializer<T> {
|
||||||
impl<T> From<T> for PyClassInitializer<T>
|
impl<T> From<T> for PyClassInitializer<T>
|
||||||
where
|
where
|
||||||
T: PyClass,
|
T: PyClass,
|
||||||
T::BaseType: PyClassBaseType<Initializer = PyNativeTypeInitializer<T::BaseType>>,
|
T::BaseType: PyClassBaseType<T::Mutability, Initializer = PyNativeTypeInitializer<T::BaseType>>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: T) -> PyClassInitializer<T> {
|
fn from(value: T) -> PyClassInitializer<T> {
|
||||||
|
|
|
@ -196,8 +196,8 @@ macro_rules! pyobject_native_type_sized {
|
||||||
($name:ty, $layout:path $(;$generics:ident)*) => {
|
($name:ty, $layout:path $(;$generics:ident)*) => {
|
||||||
unsafe impl $crate::type_object::PyLayout<$name> for $layout {}
|
unsafe impl $crate::type_object::PyLayout<$name> for $layout {}
|
||||||
impl $crate::type_object::PySizedLayout<$name> for $layout {}
|
impl $crate::type_object::PySizedLayout<$name> for $layout {}
|
||||||
impl<'a, $($generics,)*> $crate::impl_::pyclass::PyClassBaseType for $name {
|
impl<'a, $($generics,)*> $crate::impl_::pyclass::PyClassBaseType<$crate::pycell::Mutable> for $name {
|
||||||
type LayoutAsBase = $crate::pycell::PyCellBase<$layout>;
|
type LayoutAsBase = $crate::pycell::PyCellBase<$layout, $crate::pycell::Mutable>;
|
||||||
type BaseNativeType = $name;
|
type BaseNativeType = $name;
|
||||||
type ThreadChecker = $crate::impl_::pyclass::ThreadCheckerStub<$crate::PyObject>;
|
type ThreadChecker = $crate::impl_::pyclass::ThreadCheckerStub<$crate::PyObject>;
|
||||||
type Initializer = $crate::pyclass_init::PyNativeTypeInitializer<Self>;
|
type Initializer = $crate::pyclass_init::PyNativeTypeInitializer<Self>;
|
||||||
|
|
|
@ -28,8 +28,12 @@ fn _test_compile_errors() {
|
||||||
t.compile_fail("tests/ui/invalid_pymethod_names.rs");
|
t.compile_fail("tests/ui/invalid_pymethod_names.rs");
|
||||||
t.compile_fail("tests/ui/invalid_pymodule_args.rs");
|
t.compile_fail("tests/ui/invalid_pymodule_args.rs");
|
||||||
t.compile_fail("tests/ui/reject_generics.rs");
|
t.compile_fail("tests/ui/reject_generics.rs");
|
||||||
|
<<<<<<< HEAD
|
||||||
t.compile_fail("tests/ui/invalid_pymethod_proto_args.rs");
|
t.compile_fail("tests/ui/invalid_pymethod_proto_args.rs");
|
||||||
t.compile_fail("tests/ui/invalid_pymethod_proto_args_py.rs");
|
t.compile_fail("tests/ui/invalid_pymethod_proto_args_py.rs");
|
||||||
|
=======
|
||||||
|
t.compile_fail("tests/ui/invalid_immutable_pyclass_borrow.rs");
|
||||||
|
>>>>>>> 0fa03a67cd (Implement opt-in immutable pyclasses)
|
||||||
|
|
||||||
tests_rust_1_49(&t);
|
tests_rust_1_49(&t);
|
||||||
tests_rust_1_56(&t);
|
tests_rust_1_56(&t);
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
|
#[pyclass(immutable)]
|
||||||
|
pub struct Foo {
|
||||||
|
#[pyo3(get)]
|
||||||
|
field: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn borrow_mut_fails(foo: Py<Foo>, py: Python){
|
||||||
|
let borrow = foo.as_ref(py).borrow_mut();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main(){}
|
|
@ -0,0 +1,5 @@
|
||||||
|
error[E0277]: the trait bound `Foo: MutablePyClass` is not satisfied
|
||||||
|
--> tests/ui/invalid_immutable_pyclass_borrow.rs:10:33
|
||||||
|
|
|
||||||
|
10 | let borrow = foo.as_ref(py).borrow_mut();
|
||||||
|
| ^^^^^^^^^^ the trait `MutablePyClass` is not implemented for `Foo`
|
|
@ -11,8 +11,20 @@ note: required because it appears within the type `NotThreadSafe`
|
||||||
5 | struct NotThreadSafe {
|
5 | struct NotThreadSafe {
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
note: required by a bound in `ThreadCheckerStub`
|
note: required by a bound in `ThreadCheckerStub`
|
||||||
|
<<<<<<< HEAD
|
||||||
|
<<<<<<< HEAD
|
||||||
--> src/impl_/pyclass.rs
|
--> src/impl_/pyclass.rs
|
||||||
|
|
|
|
||||||
| pub struct ThreadCheckerStub<T: Send>(PhantomData<T>);
|
| pub struct ThreadCheckerStub<T: Send>(PhantomData<T>);
|
||||||
|
=======
|
||||||
|
--> src/class/impl_.rs:731:33
|
||||||
|
|
|
||||||
|
731 | pub struct ThreadCheckerStub<T: Send>(PhantomData<T>);
|
||||||
|
>>>>>>> 0fa03a67cd (Implement opt-in immutable pyclasses)
|
||||||
|
=======
|
||||||
|
--> src/class/impl_.rs:728:33
|
||||||
|
|
|
||||||
|
728 | pub struct ThreadCheckerStub<T: Send>(PhantomData<T>);
|
||||||
|
>>>>>>> 7cded1178d (Fix formatting.)
|
||||||
| ^^^^ required by this bound in `ThreadCheckerStub`
|
| ^^^^ required by this bound in `ThreadCheckerStub`
|
||||||
= note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
Loading…
Reference in New Issue