Implement by default immutable pyclasses
This commit is contained in:
parent
00c84eb0ba
commit
7f31000be2
|
@ -78,7 +78,7 @@ For users who are not very familiar with `RefCell`, here is a reminder of Rust's
|
|||
|
||||
```rust
|
||||
# use pyo3::prelude::*;
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct MyClass {
|
||||
#[pyo3(get)]
|
||||
num: i32,
|
||||
|
@ -299,7 +299,7 @@ use pyo3::types::PyDict;
|
|||
use pyo3::AsPyPointer;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[pyclass(extends=PyDict)]
|
||||
#[pyclass(extends=PyDict, mutable)]
|
||||
#[derive(Default)]
|
||||
struct DictWithCounter {
|
||||
counter: HashMap<String, usize>,
|
||||
|
@ -362,7 +362,7 @@ For simple cases where a member variable is just read and written with no side e
|
|||
|
||||
```rust
|
||||
# use pyo3::prelude::*;
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct MyClass {
|
||||
#[pyo3(get, set)]
|
||||
num: i32
|
||||
|
@ -410,7 +410,7 @@ can be used since Rust 2018).
|
|||
|
||||
```rust
|
||||
# use pyo3::prelude::*;
|
||||
# #[pyclass]
|
||||
# #[pyclass(mutable)]
|
||||
# struct MyClass {
|
||||
# num: i32,
|
||||
# }
|
||||
|
@ -436,7 +436,7 @@ If this parameter is specified, it is used as the property name, i.e.
|
|||
|
||||
```rust
|
||||
# use pyo3::prelude::*;
|
||||
# #[pyclass]
|
||||
# #[pyclass(mutable)]
|
||||
# struct MyClass {
|
||||
# num: i32,
|
||||
# }
|
||||
|
@ -473,7 +473,7 @@ between those accessible to Python (and Rust) and those accessible only to Rust.
|
|||
|
||||
```rust
|
||||
# use pyo3::prelude::*;
|
||||
# #[pyclass]
|
||||
# #[pyclass(mutable)]
|
||||
# struct MyClass {
|
||||
# num: i32,
|
||||
# }
|
||||
|
@ -641,7 +641,7 @@ Example:
|
|||
# use pyo3::prelude::*;
|
||||
use pyo3::types::{PyDict, PyTuple};
|
||||
#
|
||||
# #[pyclass]
|
||||
# #[pyclass(mutable)]
|
||||
# struct MyClass {
|
||||
# num: i32,
|
||||
# }
|
||||
|
@ -731,7 +731,7 @@ unsafe impl pyo3::PyTypeInfo for MyClass {
|
|||
}
|
||||
}
|
||||
|
||||
impl pyo3::pyclass::PyClass for MyClass {
|
||||
unsafe impl pyo3::pyclass::PyClass for MyClass {
|
||||
type Dict = pyo3::pyclass_slots::PyClassDummySlot;
|
||||
type WeakRef = pyo3::pyclass_slots::PyClassDummySlot;
|
||||
type BaseNativeType = PyAny;
|
||||
|
|
|
@ -67,7 +67,7 @@ as argument and calls that object when called.
|
|||
# use pyo3::prelude::*;
|
||||
# use pyo3::types::{PyDict, PyTuple};
|
||||
#
|
||||
#[pyclass(name = "counter")]
|
||||
#[pyclass(name = "counter", mutable)]
|
||||
struct PyCounter {
|
||||
count: u64,
|
||||
wraps: Py<PyAny>,
|
||||
|
@ -453,7 +453,7 @@ use pyo3::prelude::*;
|
|||
use pyo3::PyTraverseError;
|
||||
use pyo3::gc::{PyGCProtocol, PyVisit};
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct ClassWithGCSupport {
|
||||
obj: Option<PyObject>,
|
||||
}
|
||||
|
@ -505,7 +505,7 @@ Example:
|
|||
use pyo3::prelude::*;
|
||||
use pyo3::PyIterProtocol;
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct MyIterator {
|
||||
iter: Box<dyn Iterator<Item = PyObject> + Send>,
|
||||
}
|
||||
|
@ -530,7 +530,7 @@ implementations in `PyIterProtocol` will ensure that the objects behave correctl
|
|||
# use pyo3::prelude::*;
|
||||
# use pyo3::PyIterProtocol;
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct Iter {
|
||||
inner: std::vec::IntoIter<usize>,
|
||||
}
|
||||
|
|
|
@ -436,7 +436,7 @@ Here is an example.
|
|||
```rust
|
||||
# use pyo3::prelude::*;
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct Names {
|
||||
names: Vec<String>
|
||||
}
|
||||
|
@ -514,7 +514,7 @@ After:
|
|||
```rust
|
||||
# use pyo3::prelude::*;
|
||||
# use pyo3::types::IntoPyDict;
|
||||
# #[pyclass] #[derive(Clone)] struct MyClass {}
|
||||
# #[pyclass(mutable)] #[derive(Clone)] struct MyClass {}
|
||||
# #[pymethods] impl MyClass { #[new]fn new() -> Self { MyClass {} }}
|
||||
# Python::with_gil(|py| {
|
||||
# let typeobj = py.get_type::<MyClass>();
|
||||
|
|
|
@ -127,7 +127,7 @@ Let's add the PyO3 annotations and add a constructor:
|
|||
# use pyo3::prelude::*;
|
||||
# use pyo3::types::PyAny;
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct UserModel {
|
||||
model: Py<PyAny>,
|
||||
}
|
||||
|
@ -173,7 +173,7 @@ This wrapper will also perform the type conversions between Python and Rust.
|
|||
# fn get_results(&self) -> Vec<f64>;
|
||||
# }
|
||||
#
|
||||
# #[pyclass]
|
||||
# #[pyclass(mutable)]
|
||||
# struct UserModel {
|
||||
# model: Py<PyAny>,
|
||||
# }
|
||||
|
@ -342,7 +342,7 @@ We used in our `get_results` method the following call that performs the type co
|
|||
# fn get_results(&self) -> Vec<f64>;
|
||||
# }
|
||||
#
|
||||
# #[pyclass]
|
||||
# #[pyclass(mutable)]
|
||||
# struct UserModel {
|
||||
# model: Py<PyAny>,
|
||||
# }
|
||||
|
@ -395,7 +395,7 @@ Let's break it down in order to perform better error handling:
|
|||
# fn get_results(&self) -> Vec<f64>;
|
||||
# }
|
||||
#
|
||||
# #[pyclass]
|
||||
# #[pyclass(mutable)]
|
||||
# struct UserModel {
|
||||
# model: Py<PyAny>,
|
||||
# }
|
||||
|
@ -481,7 +481,7 @@ pub fn solve_wrapper(model: &mut UserModel) {
|
|||
solve(model);
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
pub struct UserModel {
|
||||
model: Py<PyAny>,
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ For a `&PyAny` object reference `any` where the underlying object is a `#[pyclas
|
|||
```rust
|
||||
# use pyo3::prelude::*;
|
||||
# use pyo3::{Py, Python, PyAny, PyResult};
|
||||
# #[pyclass] #[derive(Clone)] struct MyClass { }
|
||||
# #[pyclass(mutable)] #[derive(Clone)] struct MyClass { }
|
||||
# Python::with_gil(|py| -> PyResult<()> {
|
||||
let obj: &PyAny = Py::new(py, MyClass { })?.into_ref(py);
|
||||
|
||||
|
@ -191,7 +191,7 @@ For a `#[pyclass] struct MyClass`, the conversions for `Py<MyClass>` are below:
|
|||
```rust
|
||||
# use pyo3::prelude::*;
|
||||
# Python::with_gil(|py| {
|
||||
# #[pyclass] struct MyClass { }
|
||||
# #[pyclass(mutable)] struct MyClass { }
|
||||
# Python::with_gil(|py| -> PyResult<()> {
|
||||
let my_class: Py<MyClass> = Py::new(py, MyClass { })?;
|
||||
|
||||
|
@ -236,7 +236,7 @@ so it also exposes all of the methods on `PyAny`.
|
|||
|
||||
```rust
|
||||
# use pyo3::prelude::*;
|
||||
# #[pyclass] struct MyClass { }
|
||||
# #[pyclass(mutable)] struct MyClass { }
|
||||
# Python::with_gil(|py| -> PyResult<()> {
|
||||
let cell: &PyCell<MyClass> = PyCell::new(py, MyClass { })?;
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ pub struct PyClassArgs {
|
|||
pub is_basetype: bool,
|
||||
pub has_extends: bool,
|
||||
pub has_unsendable: bool,
|
||||
pub is_mutable: bool,
|
||||
pub module: Option<syn::LitStr>,
|
||||
}
|
||||
|
||||
|
@ -54,6 +55,7 @@ impl Default for PyClassArgs {
|
|||
is_basetype: false,
|
||||
has_extends: false,
|
||||
has_unsendable: false,
|
||||
is_mutable: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -158,6 +160,9 @@ impl PyClassArgs {
|
|||
"unsendable" => {
|
||||
self.has_unsendable = true;
|
||||
}
|
||||
"mutable" => {
|
||||
self.is_mutable = true;
|
||||
}
|
||||
_ => bail_spanned!(
|
||||
exp.path.span() => "expected one of gc/weakref/subclass/dict/unsendable"
|
||||
),
|
||||
|
@ -515,6 +520,52 @@ fn impl_class(
|
|||
let is_basetype = attr.is_basetype;
|
||||
let is_subclass = attr.has_extends;
|
||||
|
||||
// If the pyclass has extends/unsendable, we must opt back into PyCell checking
|
||||
// so that the inner Rust object is not inappropriately shared between threads.
|
||||
let impl_pyclass = if attr.has_unsendable || attr.has_extends || attr.is_mutable {
|
||||
quote! {
|
||||
unsafe impl ::pyo3::pyclass::MutablePyClass for #cls {}
|
||||
|
||||
unsafe impl ::pyo3::PyClass for #cls {
|
||||
type Dict = #dict;
|
||||
type WeakRef = #weakref;
|
||||
type BaseNativeType = #base_nativetype;
|
||||
|
||||
#[inline]
|
||||
fn try_borrow_as_pyref(slf: &::pyo3::PyCell<Self>) -> ::std::result::Result<::pyo3::pycell::PyRef<'_, Self>, ::pyo3::pycell::PyBorrowError> {
|
||||
unsafe { ::pyo3::PyCell::immutable_pyclass_try_borrow(slf) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn borrow_as_pyref(slf: &::pyo3::PyCell<Self>) -> ::pyo3::pycell::PyRef<'_, Self> {
|
||||
unsafe { ::pyo3::PyCell::immutable_pyclass_borrow(slf) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn try_borrow_unguarded(slf: &::pyo3::PyCell<Self>) -> ::std::result::Result<&Self, ::pyo3::pycell::PyBorrowError> {
|
||||
::pyo3::PyCell::immutable_pyclass_try_borrow_unguarded(slf)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn drop_pyref(pyref: &mut ::pyo3::pycell::PyRef<Self>) {
|
||||
::pyo3::pycell::PyRef::decrement_flag(pyref)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ::pyo3::derive_utils::ExtractExt<'a> for &'a mut #cls {
|
||||
type Target = ::pyo3::PyRefMut<'a, #cls>;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
unsafe impl ::pyo3::PyClass for #cls {
|
||||
type Dict = #dict;
|
||||
type WeakRef = #weakref;
|
||||
type BaseNativeType = #base_nativetype;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(quote! {
|
||||
unsafe impl ::pyo3::type_object::PyTypeInfo for #cls {
|
||||
type AsRefTarget = ::pyo3::PyCell<Self>;
|
||||
|
@ -532,21 +583,14 @@ fn impl_class(
|
|||
}
|
||||
}
|
||||
|
||||
impl ::pyo3::PyClass for #cls {
|
||||
type Dict = #dict;
|
||||
type WeakRef = #weakref;
|
||||
type BaseNativeType = #base_nativetype;
|
||||
}
|
||||
#impl_pyclass
|
||||
|
||||
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
|
||||
{
|
||||
type Target = ::pyo3::PyRefMut<'a, #cls>;
|
||||
}
|
||||
|
||||
|
||||
#into_pyobject
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
//! [typeobj docs](https://docs.python.org/3/c-api/typeobj.html)
|
||||
|
||||
use crate::callback::{HashCallbackOutput, IntoPyCallbackOutput};
|
||||
use crate::pyclass::MutablePyClass;
|
||||
use crate::{exceptions, ffi, FromPyObject, PyAny, PyCell, PyClass, PyObject};
|
||||
use std::os::raw::c_int;
|
||||
|
||||
|
@ -128,12 +129,12 @@ pub trait PyObjectGetAttrProtocol<'p>: PyObjectProtocol<'p> {
|
|||
type Name: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
pub trait PyObjectSetAttrProtocol<'p>: PyObjectProtocol<'p> {
|
||||
pub trait PyObjectSetAttrProtocol<'p>: PyObjectProtocol<'p> + MutablePyClass {
|
||||
type Name: FromPyObject<'p>;
|
||||
type Value: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
pub trait PyObjectDelAttrProtocol<'p>: PyObjectProtocol<'p> {
|
||||
pub trait PyObjectDelAttrProtocol<'p>: PyObjectProtocol<'p> + MutablePyClass {
|
||||
type Name: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
//! For more information check [buffer protocol](https://docs.python.org/3/c-api/buffer.html)
|
||||
//! c-api
|
||||
use crate::callback::IntoPyCallbackOutput;
|
||||
use crate::{ffi, PyCell, PyClass, PyRefMut};
|
||||
use crate::pyclass::MutablePyClass;
|
||||
use crate::{ffi, PyCell, PyRefMut};
|
||||
use std::os::raw::c_int;
|
||||
|
||||
/// Buffer protocol interface
|
||||
|
@ -13,7 +14,7 @@ use std::os::raw::c_int;
|
|||
/// For more information check [buffer protocol](https://docs.python.org/3/c-api/buffer.html)
|
||||
/// c-api.
|
||||
#[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.
|
||||
|
||||
fn bf_getbuffer(slf: PyRefMut<Self>, view: *mut ffi::Py_buffer, flags: c_int) -> Self::Result
|
||||
|
@ -51,7 +52,7 @@ where
|
|||
#[doc(hidden)]
|
||||
pub unsafe extern "C" fn releasebuffer<T>(slf: *mut ffi::PyObject, arg1: *mut ffi::Py_buffer)
|
||||
where
|
||||
T: for<'p> PyBufferReleaseBufferProtocol<'p>,
|
||||
T: for<'p> PyBufferReleaseBufferProtocol<'p> + MutablePyClass,
|
||||
{
|
||||
crate::callback_body!(py, {
|
||||
let slf = py.from_borrowed_ptr::<crate::PyCell<T>>(slf);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
//! Python GC support
|
||||
|
||||
use crate::pyclass::MutablePyClass;
|
||||
use crate::{ffi, AsPyPointer, PyCell, PyClass, Python};
|
||||
use std::os::raw::{c_int, c_void};
|
||||
|
||||
|
@ -53,7 +54,7 @@ where
|
|||
#[doc(hidden)]
|
||||
pub unsafe extern "C" fn clear<T>(slf: *mut ffi::PyObject) -> c_int
|
||||
where
|
||||
T: for<'p> PyGCClearProtocol<'p>,
|
||||
T: for<'p> PyGCClearProtocol<'p> + MutablePyClass,
|
||||
{
|
||||
let pool = crate::GILPool::new();
|
||||
let slf = pool.python().from_borrowed_ptr::<PyCell<T>>(slf);
|
||||
|
|
|
@ -21,7 +21,7 @@ use crate::{ffi, IntoPy, IntoPyPointer, PyClass, PyObject, Python};
|
|||
/// use pyo3::prelude::*;
|
||||
/// use pyo3::PyIterProtocol;
|
||||
///
|
||||
/// #[pyclass]
|
||||
/// #[pyclass(mutable)]
|
||||
/// struct Iter {
|
||||
/// count: usize,
|
||||
/// }
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
//! Trait and support implementation for implementing mapping support
|
||||
|
||||
use crate::callback::IntoPyCallbackOutput;
|
||||
use crate::pyclass::MutablePyClass;
|
||||
use crate::{FromPyObject, PyClass, PyObject};
|
||||
|
||||
/// Mapping interface
|
||||
#[allow(unused_variables)]
|
||||
pub trait PyMappingProtocol<'p>: PyClass {
|
||||
|
@ -61,13 +61,13 @@ pub trait PyMappingGetItemProtocol<'p>: PyMappingProtocol<'p> {
|
|||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyMappingSetItemProtocol<'p>: PyMappingProtocol<'p> {
|
||||
pub trait PyMappingSetItemProtocol<'p>: PyMappingProtocol<'p> + MutablePyClass {
|
||||
type Key: FromPyObject<'p>;
|
||||
type Value: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyMappingDelItemProtocol<'p>: PyMappingProtocol<'p> {
|
||||
pub trait PyMappingDelItemProtocol<'p>: PyMappingProtocol<'p> + MutablePyClass {
|
||||
type Key: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
//! Trait and support implementation for implementing number protocol
|
||||
use crate::callback::IntoPyCallbackOutput;
|
||||
use crate::err::PyErr;
|
||||
use crate::pyclass::MutablePyClass;
|
||||
use crate::{ffi, FromPyObject, PyClass, PyObject};
|
||||
|
||||
/// Number interface
|
||||
|
@ -481,74 +482,74 @@ pub trait PyNumberROrProtocol<'p>: PyNumberProtocol<'p> {
|
|||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberIAddProtocol<'p>: PyNumberProtocol<'p> {
|
||||
pub trait PyNumberIAddProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberISubProtocol<'p>: PyNumberProtocol<'p> {
|
||||
pub trait PyNumberISubProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberIMulProtocol<'p>: PyNumberProtocol<'p> {
|
||||
pub trait PyNumberIMulProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberIMatmulProtocol<'p>: PyNumberProtocol<'p> {
|
||||
pub trait PyNumberIMatmulProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberITruedivProtocol<'p>: PyNumberProtocol<'p> {
|
||||
pub trait PyNumberITruedivProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberIFloordivProtocol<'p>: PyNumberProtocol<'p> {
|
||||
pub trait PyNumberIFloordivProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberIModProtocol<'p>: PyNumberProtocol<'p> {
|
||||
pub trait PyNumberIModProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberIDivmodProtocol<'p>: PyNumberProtocol<'p> {
|
||||
pub trait PyNumberIDivmodProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberIPowProtocol<'p>: PyNumberProtocol<'p> {
|
||||
pub trait PyNumberIPowProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
pub trait PyNumberILShiftProtocol<'p>: PyNumberProtocol<'p> {
|
||||
pub trait PyNumberILShiftProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
pub trait PyNumberIRShiftProtocol<'p>: PyNumberProtocol<'p> {
|
||||
pub trait PyNumberIRShiftProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberIAndProtocol<'p>: PyNumberProtocol<'p> {
|
||||
pub trait PyNumberIAndProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberIXorProtocol<'p>: PyNumberProtocol<'p> {
|
||||
pub trait PyNumberIXorProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberIOrProtocol<'p>: PyNumberProtocol<'p> {
|
||||
pub trait PyNumberIOrProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
@ -750,7 +751,7 @@ pub unsafe extern "C" fn ipow<T>(
|
|||
_modulo: *mut ffi::PyObject,
|
||||
) -> *mut ffi::PyObject
|
||||
where
|
||||
T: for<'p> PyNumberIPowProtocol<'p>,
|
||||
T: for<'p> PyNumberIPowProtocol<'p> + MutablePyClass,
|
||||
{
|
||||
// NOTE: Somehow __ipow__ causes SIGSEGV in Python < 3.8 when we extract,
|
||||
// so we ignore it. It's the same as what CPython does.
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
use crate::callback::IntoPyCallbackOutput;
|
||||
use crate::conversion::{FromPyObject, IntoPy};
|
||||
use crate::err::PyErr;
|
||||
use crate::pyclass::MutablePyClass;
|
||||
use crate::{exceptions, ffi, PyAny, PyCell, PyClass, PyObject};
|
||||
use std::os::raw::c_int;
|
||||
|
||||
|
@ -88,13 +89,13 @@ pub trait PySequenceGetItemProtocol<'p>: PySequenceProtocol<'p> {
|
|||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PySequenceSetItemProtocol<'p>: PySequenceProtocol<'p> {
|
||||
pub trait PySequenceSetItemProtocol<'p>: PySequenceProtocol<'p> + MutablePyClass {
|
||||
type Index: FromPyObject<'p> + From<isize>;
|
||||
type Value: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PySequenceDelItemProtocol<'p>: PySequenceProtocol<'p> {
|
||||
pub trait PySequenceDelItemProtocol<'p>: PySequenceProtocol<'p> + MutablePyClass {
|
||||
type Index: FromPyObject<'p> + From<isize>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
@ -115,14 +116,14 @@ pub trait PySequenceRepeatProtocol<'p>: PySequenceProtocol<'p> {
|
|||
}
|
||||
|
||||
pub trait PySequenceInplaceConcatProtocol<'p>:
|
||||
PySequenceProtocol<'p> + IntoPy<PyObject> + 'p
|
||||
PySequenceProtocol<'p> + IntoPy<PyObject> + MutablePyClass + 'p
|
||||
{
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<Self>;
|
||||
}
|
||||
|
||||
pub trait PySequenceInplaceRepeatProtocol<'p>:
|
||||
PySequenceProtocol<'p> + IntoPy<PyObject> + 'p
|
||||
PySequenceProtocol<'p> + IntoPy<PyObject> + MutablePyClass + 'p
|
||||
{
|
||||
type Index: FromPyObject<'p> + From<isize>;
|
||||
type Result: IntoPyCallbackOutput<Self>;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
//! Defines conversions between Rust and Python types.
|
||||
use crate::err::{self, PyDowncastError, PyResult};
|
||||
use crate::pyclass::MutablePyClass;
|
||||
use crate::type_object::PyTypeInfo;
|
||||
use crate::types::PyTuple;
|
||||
use crate::{
|
||||
|
@ -145,7 +146,7 @@ where
|
|||
/// ```rust
|
||||
/// use pyo3::prelude::*;
|
||||
///
|
||||
/// #[pyclass]
|
||||
/// #[pyclass(mutable)]
|
||||
/// struct Number {
|
||||
/// #[pyo3(get, set)]
|
||||
/// value: i32,
|
||||
|
@ -329,7 +330,7 @@ where
|
|||
|
||||
impl<'a, T> FromPyObject<'a> for PyRefMut<'a, T>
|
||||
where
|
||||
T: PyClass,
|
||||
T: MutablePyClass,
|
||||
{
|
||||
fn extract(obj: &'a PyAny) -> PyResult<Self> {
|
||||
let cell: &PyCell<T> = PyTryFrom::try_from(obj)?;
|
||||
|
|
|
@ -3,6 +3,7 @@ use crate::conversion::{PyTryFrom, ToBorrowedObject};
|
|||
use crate::err::{self, PyDowncastError, PyErr, PyResult};
|
||||
use crate::gil;
|
||||
use crate::pycell::{PyBorrowError, PyBorrowMutError, PyCell};
|
||||
use crate::pyclass::MutablePyClass;
|
||||
use crate::types::{PyDict, PyTuple};
|
||||
use crate::{
|
||||
ffi, AsPyPointer, FromPyObject, IntoPy, IntoPyPointer, PyAny, PyClass, PyClassInitializer,
|
||||
|
@ -391,6 +392,23 @@ where
|
|||
self.as_ref(py).borrow()
|
||||
}
|
||||
|
||||
/// Attempts to immutably borrow the value `T`, returning an error if the value is currently mutably borrowed.
|
||||
///
|
||||
/// The borrow lasts while the returned [`PyRef`] exists.
|
||||
///
|
||||
/// This is the non-panicking variant of [`borrow`](#method.borrow).
|
||||
///
|
||||
/// Equivalent to `self.as_ref(py).borrow_mut()` -
|
||||
/// see [`PyCell::try_borrow`](crate::pycell::PyCell::try_borrow).
|
||||
pub fn try_borrow<'py>(&'py self, py: Python<'py>) -> Result<PyRef<'py, T>, PyBorrowError> {
|
||||
self.as_ref(py).try_borrow()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Py<T>
|
||||
where
|
||||
T: MutablePyClass,
|
||||
{
|
||||
/// Mutably borrows the value `T`.
|
||||
///
|
||||
/// This borrow lasts while the returned [`PyRefMut`] exists.
|
||||
|
@ -403,7 +421,7 @@ where
|
|||
/// ```
|
||||
/// # use pyo3::prelude::*;
|
||||
/// #
|
||||
/// #[pyclass]
|
||||
/// #[pyclass(mutable)]
|
||||
/// struct Foo {
|
||||
/// inner: u8,
|
||||
/// }
|
||||
|
@ -427,18 +445,6 @@ where
|
|||
self.as_ref(py).borrow_mut()
|
||||
}
|
||||
|
||||
/// Attempts to immutably borrow the value `T`, returning an error if the value is currently mutably borrowed.
|
||||
///
|
||||
/// The borrow lasts while the returned [`PyRef`] exists.
|
||||
///
|
||||
/// This is the non-panicking variant of [`borrow`](#method.borrow).
|
||||
///
|
||||
/// Equivalent to `self.as_ref(py).borrow_mut()` -
|
||||
/// see [`PyCell::try_borrow`](crate::pycell::PyCell::try_borrow).
|
||||
pub fn try_borrow<'py>(&'py self, py: Python<'py>) -> Result<PyRef<'py, T>, PyBorrowError> {
|
||||
self.as_ref(py).try_borrow()
|
||||
}
|
||||
|
||||
/// Attempts to mutably borrow the value `T`, returning an error if the value is currently borrowed.
|
||||
///
|
||||
/// The borrow lasts while the returned [`PyRefMut`] exists.
|
||||
|
@ -802,7 +808,7 @@ where
|
|||
|
||||
impl<'a, T> std::convert::From<PyRefMut<'a, T>> for Py<T>
|
||||
where
|
||||
T: PyClass,
|
||||
T: MutablePyClass,
|
||||
{
|
||||
fn from(pyref: PyRefMut<'a, T>) -> Self {
|
||||
unsafe { Py::from_borrowed_ptr(pyref.py(), pyref.as_ptr()) }
|
||||
|
|
186
src/pycell.rs
186
src/pycell.rs
|
@ -25,7 +25,7 @@
|
|||
//! ```rust
|
||||
//! use pyo3::prelude::*;
|
||||
//!
|
||||
//! #[pyclass]
|
||||
//! #[pyclass(mutable)]
|
||||
//! struct Number {
|
||||
//! inner: u32,
|
||||
//! }
|
||||
|
@ -60,7 +60,7 @@
|
|||
//! ```rust
|
||||
//! # use pyo3::prelude::*;
|
||||
//! #
|
||||
//! # #[pyclass]
|
||||
//! # #[pyclass(mutable)]
|
||||
//! # struct Number {
|
||||
//! # inner: u32,
|
||||
//! # }
|
||||
|
@ -99,7 +99,7 @@
|
|||
//! Suppose the following function that swaps the values of two `Number`s:
|
||||
//! ```
|
||||
//! # use pyo3::prelude::*;
|
||||
//! # #[pyclass]
|
||||
//! # #[pyclass(mutable)]
|
||||
//! # pub struct Number {
|
||||
//! # inner: u32,
|
||||
//! # }
|
||||
|
@ -131,7 +131,7 @@
|
|||
//! It is better to write that function like this:
|
||||
//! ```rust
|
||||
//! # use pyo3::prelude::*;
|
||||
//! # #[pyclass]
|
||||
//! # #[pyclass(mutable)]
|
||||
//! # pub struct Number {
|
||||
//! # inner: u32,
|
||||
//! # }
|
||||
|
@ -175,7 +175,7 @@
|
|||
//! [Interior Mutability]: https://doc.rust-lang.org/book/ch15-05-interior-mutability.html "RefCell<T> and the Interior Mutability Pattern - The Rust Programming Language"
|
||||
|
||||
use crate::exceptions::PyRuntimeError;
|
||||
use crate::pyclass::PyClass;
|
||||
use crate::pyclass::{MutablePyClass, PyClass};
|
||||
use crate::pyclass_init::PyClassInitializer;
|
||||
use crate::pyclass_slots::{PyClassDict, PyClassWeakRef};
|
||||
use crate::type_object::{PyLayout, PySizedLayout};
|
||||
|
@ -214,7 +214,7 @@ unsafe impl<T, U> PyLayout<T> for PyCellBase<U> where U: PySizedLayout<T> {}
|
|||
/// ```rust
|
||||
/// use pyo3::prelude::*;
|
||||
///
|
||||
/// #[pyclass]
|
||||
/// #[pyclass(mutable)]
|
||||
/// struct Number {
|
||||
/// inner: u32,
|
||||
/// }
|
||||
|
@ -352,18 +352,15 @@ impl<T: PyClass> PyCell<T> {
|
|||
///
|
||||
/// Panics if the value is currently mutably borrowed. For a non-panicking variant, use
|
||||
/// [`try_borrow`](#method.try_borrow).
|
||||
#[inline]
|
||||
pub fn borrow(&self) -> PyRef<'_, T> {
|
||||
self.try_borrow().expect("Already mutably borrowed")
|
||||
PyClass::borrow_as_pyref(self)
|
||||
}
|
||||
|
||||
/// Mutably borrows the value `T`. This borrow lasts as long as the returned `PyRefMut` exists.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the value is currently borrowed. For a non-panicking variant, use
|
||||
/// [`try_borrow_mut`](#method.try_borrow_mut).
|
||||
pub fn borrow_mut(&self) -> PyRefMut<'_, T> {
|
||||
self.try_borrow_mut().expect("Already borrowed")
|
||||
#[inline]
|
||||
#[doc(hidden)]
|
||||
pub unsafe fn immutable_pyclass_borrow(&self) -> PyRef<'_, T> {
|
||||
self.try_borrow().expect("Already mutably borrowed")
|
||||
}
|
||||
|
||||
/// Immutably borrows the value `T`, returning an error if the value is currently
|
||||
|
@ -375,7 +372,7 @@ impl<T: PyClass> PyCell<T> {
|
|||
///
|
||||
/// ```
|
||||
/// # use pyo3::prelude::*;
|
||||
/// #[pyclass]
|
||||
/// #[pyclass(mutable)]
|
||||
/// struct Class {}
|
||||
///
|
||||
/// Python::with_gil(|py| {
|
||||
|
@ -391,7 +388,14 @@ impl<T: PyClass> PyCell<T> {
|
|||
/// }
|
||||
/// });
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn try_borrow(&self) -> Result<PyRef<'_, T>, PyBorrowError> {
|
||||
PyClass::try_borrow_as_pyref(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[doc(hidden)]
|
||||
pub unsafe fn immutable_pyclass_try_borrow(&self) -> Result<PyRef<'_, T>, PyBorrowError> {
|
||||
let flag = self.get_borrow_flag();
|
||||
if flag == BorrowFlag::HAS_MUTABLE_BORROW {
|
||||
Err(PyBorrowError { _private: () })
|
||||
|
@ -401,6 +405,73 @@ impl<T: PyClass> PyCell<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Immutably borrows the value `T`, returning an error if the value is
|
||||
/// currently mutably borrowed.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This method is unsafe because it does not return a `PyRef`,
|
||||
/// thus leaving the borrow flag untouched. Mutably borrowing the `PyCell`
|
||||
/// while the reference returned by this method is alive is undefined behaviour.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use pyo3::prelude::*;
|
||||
/// #[pyclass(mutable)]
|
||||
/// struct Class {}
|
||||
/// Python::with_gil(|py| {
|
||||
/// let c = PyCell::new(py, Class {}).unwrap();
|
||||
///
|
||||
/// {
|
||||
/// let m = c.borrow_mut();
|
||||
/// assert!(unsafe { c.try_borrow_unguarded() }.is_err());
|
||||
/// }
|
||||
///
|
||||
/// {
|
||||
/// let m = c.borrow();
|
||||
/// assert!(unsafe { c.try_borrow_unguarded() }.is_ok());
|
||||
/// }
|
||||
/// });
|
||||
/// ```
|
||||
#[inline]
|
||||
pub unsafe fn try_borrow_unguarded(&self) -> Result<&T, PyBorrowError> {
|
||||
PyClass::try_borrow_unguarded(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[doc(hidden)]
|
||||
pub unsafe fn immutable_pyclass_try_borrow_unguarded(&self) -> Result<&T, PyBorrowError> {
|
||||
if self.get_borrow_flag() == BorrowFlag::HAS_MUTABLE_BORROW {
|
||||
Err(PyBorrowError { _private: () })
|
||||
} else {
|
||||
Ok(&*self.contents.value.get())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn immutable_pyclass_try_borrow_unchecked_unguarded(&self) -> &T {
|
||||
&*self.contents.value.get()
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn borrow_unchecked_unincremented(&self) -> PyRef<'_, T> {
|
||||
PyRef { inner: self }
|
||||
}
|
||||
|
||||
fn get_ptr(&self) -> *mut T {
|
||||
self.contents.value.get()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: MutablePyClass> PyCell<T> {
|
||||
/// Mutably borrows the value `T`. This borrow lasts as long as the returned `PyRefMut` exists.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the value is currently borrowed. For a non-panicking variant, use
|
||||
/// [`try_borrow_mut`](#method.try_borrow_mut).
|
||||
pub fn borrow_mut(&self) -> PyRefMut<'_, T> {
|
||||
self.try_borrow_mut().expect("Already borrowed")
|
||||
}
|
||||
/// Mutably borrows the value `T`, returning an error if the value is currently borrowed.
|
||||
/// This borrow lasts as long as the returned `PyRefMut` exists.
|
||||
///
|
||||
|
@ -410,7 +481,7 @@ impl<T: PyClass> PyCell<T> {
|
|||
///
|
||||
/// ```
|
||||
/// # use pyo3::prelude::*;
|
||||
/// #[pyclass]
|
||||
/// #[pyclass(mutable)]
|
||||
/// struct Class {}
|
||||
/// Python::with_gil(|py| {
|
||||
/// let c = PyCell::new(py, Class {}).unwrap();
|
||||
|
@ -430,44 +501,6 @@ impl<T: PyClass> PyCell<T> {
|
|||
Ok(PyRefMut { inner: self })
|
||||
}
|
||||
}
|
||||
|
||||
/// Immutably borrows the value `T`, returning an error if the value is
|
||||
/// currently mutably borrowed.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This method is unsafe because it does not return a `PyRef`,
|
||||
/// thus leaving the borrow flag untouched. Mutably borrowing the `PyCell`
|
||||
/// while the reference returned by this method is alive is undefined behaviour.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use pyo3::prelude::*;
|
||||
/// #[pyclass]
|
||||
/// struct Class {}
|
||||
/// Python::with_gil(|py| {
|
||||
/// let c = PyCell::new(py, Class {}).unwrap();
|
||||
///
|
||||
/// {
|
||||
/// let m = c.borrow_mut();
|
||||
/// assert!(unsafe { c.try_borrow_unguarded() }.is_err());
|
||||
/// }
|
||||
///
|
||||
/// {
|
||||
/// let m = c.borrow();
|
||||
/// assert!(unsafe { c.try_borrow_unguarded() }.is_ok());
|
||||
/// }
|
||||
/// });
|
||||
/// ```
|
||||
pub unsafe fn try_borrow_unguarded(&self) -> Result<&T, PyBorrowError> {
|
||||
if self.get_borrow_flag() == BorrowFlag::HAS_MUTABLE_BORROW {
|
||||
Err(PyBorrowError { _private: () })
|
||||
} else {
|
||||
Ok(&*self.contents.value.get())
|
||||
}
|
||||
}
|
||||
|
||||
/// Replaces the wrapped value with a new one, returning the old value.
|
||||
///
|
||||
/// # Panics
|
||||
|
@ -498,10 +531,6 @@ impl<T: PyClass> PyCell<T> {
|
|||
pub fn swap(&self, other: &Self) {
|
||||
std::mem::swap(&mut *self.borrow_mut(), &mut *other.borrow_mut())
|
||||
}
|
||||
|
||||
fn get_ptr(&self) -> *mut T {
|
||||
self.contents.value.get()
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: PyClass> PyLayout<T> for PyCell<T> {}
|
||||
|
@ -605,6 +634,12 @@ impl<'p, T: PyClass> PyRef<'p, T> {
|
|||
pub fn py(&self) -> Python {
|
||||
unsafe { Python::assume_gil_acquired() }
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub unsafe fn decrement_flag(&mut self) {
|
||||
let flag = self.inner.get_borrow_flag();
|
||||
self.inner.set_borrow_flag(flag.decrement())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, T, U> AsRef<U> for PyRef<'p, T>
|
||||
|
@ -687,8 +722,7 @@ impl<'p, T: PyClass> Deref for PyRef<'p, T> {
|
|||
|
||||
impl<'p, T: PyClass> Drop for PyRef<'p, T> {
|
||||
fn drop(&mut self) {
|
||||
let flag = self.inner.get_borrow_flag();
|
||||
self.inner.set_borrow_flag(flag.decrement())
|
||||
unsafe { PyClass::drop_pyref(self) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -720,11 +754,11 @@ impl<T: PyClass + fmt::Debug> fmt::Debug for PyRef<'_, T> {
|
|||
/// A wrapper type for a mutably borrowed value from a[`PyCell`]`<T>`.
|
||||
///
|
||||
/// 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>,
|
||||
}
|
||||
|
||||
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`.
|
||||
pub fn py(&self) -> Python {
|
||||
unsafe { Python::assume_gil_acquired() }
|
||||
|
@ -733,8 +767,8 @@ impl<'p, T: PyClass> PyRefMut<'p, T> {
|
|||
|
||||
impl<'p, T, U> AsRef<U> for PyRefMut<'p, T>
|
||||
where
|
||||
T: PyClass<BaseType = U>,
|
||||
U: PyClass,
|
||||
T: PyClass<BaseType = U> + MutablePyClass,
|
||||
U: MutablePyClass,
|
||||
{
|
||||
fn as_ref(&self) -> &T::BaseType {
|
||||
unsafe { &*self.inner.ob_base.get_ptr() }
|
||||
|
@ -743,8 +777,8 @@ where
|
|||
|
||||
impl<'p, T, U> AsMut<U> for PyRefMut<'p, T>
|
||||
where
|
||||
T: PyClass<BaseType = U>,
|
||||
U: PyClass,
|
||||
T: PyClass<BaseType = U> + MutablePyClass,
|
||||
U: MutablePyClass,
|
||||
{
|
||||
fn as_mut(&mut self) -> &mut T::BaseType {
|
||||
unsafe { &mut *self.inner.ob_base.get_ptr() }
|
||||
|
@ -753,8 +787,8 @@ where
|
|||
|
||||
impl<'p, T, U> PyRefMut<'p, T>
|
||||
where
|
||||
T: PyClass<BaseType = U>,
|
||||
U: PyClass,
|
||||
T: PyClass<BaseType = U> + MutablePyClass,
|
||||
U: MutablePyClass,
|
||||
{
|
||||
/// Gets a `PyRef<T::BaseType>`.
|
||||
///
|
||||
|
@ -768,7 +802,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'p, T: PyClass> Deref for PyRefMut<'p, T> {
|
||||
impl<'p, T: MutablePyClass> Deref for PyRefMut<'p, T> {
|
||||
type Target = T;
|
||||
|
||||
#[inline]
|
||||
|
@ -777,39 +811,39 @@ 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]
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
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) {
|
||||
self.inner.set_borrow_flag(BorrowFlag::UNUSED)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PyClass> IntoPy<PyObject> for PyRefMut<'_, T> {
|
||||
impl<T: MutablePyClass> IntoPy<PyObject> for PyRefMut<'_, T> {
|
||||
fn into_py(self, py: Python) -> PyObject {
|
||||
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 {
|
||||
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;
|
||||
fn try_from(cell: &'a crate::PyCell<T>) -> Result<Self, Self::Error> {
|
||||
cell.try_borrow_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PyClass + fmt::Debug> fmt::Debug for PyRefMut<'_, T> {
|
||||
impl<T: MutablePyClass + fmt::Debug> fmt::Debug for PyRefMut<'_, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&*(self.deref()), f)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
//! `PyClass` and related traits.
|
||||
use crate::pycell::{PyBorrowError, PyRef};
|
||||
use crate::{
|
||||
class::impl_::{fallback_new, tp_dealloc, PyClassImpl},
|
||||
ffi,
|
||||
|
@ -17,7 +18,14 @@ use std::{
|
|||
///
|
||||
/// The `#[pyclass]` attribute automatically implements this trait for your Rust struct,
|
||||
/// so you normally don't have to use this trait directly.
|
||||
pub trait PyClass:
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If `T` implements [`MutablePyClass`], then implementations must override the default methods.
|
||||
///
|
||||
/// If `T` does not implement [`MutablePyClass`], then implementations should not override the
|
||||
/// default methods.
|
||||
pub unsafe trait PyClass:
|
||||
PyTypeInfo<AsRefTarget = PyCell<Self>> + PyClassImpl<Layout = PyCell<Self>>
|
||||
{
|
||||
/// Specify this class has `#[pyclass(dict)]` or not.
|
||||
|
@ -27,8 +35,65 @@ pub trait PyClass:
|
|||
/// The closest native ancestor. This is `PyAny` by default, and when you declare
|
||||
/// `#[pyclass(extends=PyDict)]`, it's `PyDict`.
|
||||
type BaseNativeType: PyTypeInfo + PyNativeType;
|
||||
|
||||
/// Default implementation that borrows as a PyRef without checking or incrementing the
|
||||
/// borrowflag.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Implementations that implement [`MutablePyClass`] **must** override this method
|
||||
/// by wrapping `PyCell::immutable_pyclass_try_borrow()`
|
||||
#[inline]
|
||||
fn try_borrow_as_pyref(slf: &PyCell<Self>) -> Result<PyRef<'_, Self>, PyBorrowError> {
|
||||
Ok(Self::borrow_as_pyref(slf))
|
||||
}
|
||||
|
||||
/// Default implementation that borrows as a PyRef without checking or incrementing the
|
||||
/// borrowflag.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Implementations that implement [`MutablePyClass`] **must** override this method
|
||||
/// by wrapping `PyCell::immutable_pyclass_borrow()`
|
||||
#[inline]
|
||||
fn borrow_as_pyref(slf: &PyCell<Self>) -> PyRef<'_, Self> {
|
||||
unsafe { PyCell::borrow_unchecked_unincremented(slf) }
|
||||
}
|
||||
|
||||
/// Default implementation that borrows as a PyRef without checking or incrementing the
|
||||
/// borrowflag.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Please see the safety requirements on [`PyCell::try_borrow_unguarded`].
|
||||
///
|
||||
/// Implementations that implement [`MutablePyClass`] **must** override this method
|
||||
/// by wrapping `PyCell::immutable_pyclass_try_borrow_unguarded()`.
|
||||
#[inline]
|
||||
unsafe fn try_borrow_unguarded(slf: &PyCell<Self>) -> Result<&Self, PyBorrowError> {
|
||||
Ok(PyCell::_try_borrow_unchecked_unguarded(slf))
|
||||
}
|
||||
|
||||
/// Default implementation that does nothing.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is only called inside [`PyRef`]s [`Drop`] implementation.
|
||||
///
|
||||
/// Implementations that also implement [`MutablePyClass`] **must** make this method call
|
||||
/// [`PyRef::decrement_flag()`] so that [`PyRef`]s [`Drop`] implementation correctly decrements
|
||||
/// the borrowflag.
|
||||
#[inline]
|
||||
unsafe fn drop_pyref(_: &mut PyRef<Self>) {}
|
||||
}
|
||||
|
||||
/// Declares that a pyclass can be mutably borrowed.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Implementations must correctly implement [`PyClass`].
|
||||
pub unsafe trait MutablePyClass: PyClass {}
|
||||
|
||||
/// For collecting slot items.
|
||||
#[derive(Default)]
|
||||
struct TypeSlots(Vec<ffi::PyType_Slot>);
|
||||
|
|
|
@ -15,7 +15,8 @@ pub struct Foo2;
|
|||
unsendable,
|
||||
subclass,
|
||||
extends = ::pyo3::types::PyAny,
|
||||
module = "Spam"
|
||||
module = "Spam",
|
||||
mutable
|
||||
)]
|
||||
pub struct Bar {
|
||||
#[pyo3(get, set)]
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#![no_implicit_prelude]
|
||||
#![allow(unused_variables)]
|
||||
|
||||
#[::pyo3::pyclass]
|
||||
#[::pyo3::pyclass(mutable)]
|
||||
pub struct Dummy;
|
||||
|
||||
#[::pyo3::pyclass]
|
||||
#[::pyo3::pyclass(mutable)]
|
||||
pub struct DummyIter;
|
||||
|
||||
#[::pyo3::pymethods]
|
||||
|
|
|
@ -16,7 +16,8 @@ pub struct Foo2;
|
|||
gc,
|
||||
subclass,
|
||||
extends = ::pyo3::types::PyAny,
|
||||
module = "Spam"
|
||||
module = "Spam",
|
||||
mutable
|
||||
)]
|
||||
pub struct Bar {
|
||||
#[pyo3(get, set)]
|
||||
|
|
|
@ -50,7 +50,7 @@ fn unary_arithmetic() {
|
|||
py_run!(py, c, "assert repr(round(c, 1)) == 'UA(3)'");
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct InPlaceOperations {
|
||||
value: u32,
|
||||
}
|
||||
|
@ -500,7 +500,7 @@ fn rich_comparisons_python_3_type_error() {
|
|||
mod return_not_implemented {
|
||||
use super::*;
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct RichComparisonToSelf {}
|
||||
|
||||
#[pymethods]
|
||||
|
|
|
@ -67,7 +67,7 @@ impl PyObjectProtocol for BinaryArithmetic {
|
|||
}
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct InPlaceOperations {
|
||||
value: u32,
|
||||
}
|
||||
|
@ -527,7 +527,7 @@ fn rich_comparisons_python_3_type_error() {
|
|||
mod return_not_implemented {
|
||||
use super::*;
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct RichComparisonToSelf {}
|
||||
|
||||
#[pyproto]
|
||||
|
|
|
@ -21,7 +21,7 @@ enum TestGetBufferError {
|
|||
IncorrectAlignment,
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct TestBufferErrors {
|
||||
buf: Vec<u32>,
|
||||
error: Option<TestGetBufferError>,
|
||||
|
|
|
@ -15,7 +15,7 @@ use std::sync::Arc;
|
|||
|
||||
mod common;
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct TestBufferClass {
|
||||
vec: Vec<u8>,
|
||||
drop_called: Arc<AtomicBool>,
|
||||
|
|
|
@ -36,7 +36,7 @@ fn unit_class() {
|
|||
///Line2
|
||||
/// Line3
|
||||
// this is not doc string
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct ClassWithDocs {
|
||||
/// Property field
|
||||
#[pyo3(get, set)]
|
||||
|
@ -122,7 +122,7 @@ fn custom_names() {
|
|||
py_assert!(py, typeobj, "not hasattr(typeobj, 'foo')");
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct RawIdents {
|
||||
#[pyo3(get, set)]
|
||||
r#type: i64,
|
||||
|
@ -171,7 +171,7 @@ fn empty_class_in_module() {
|
|||
assert_eq!(module, "builtins");
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct ClassWithObjectField {
|
||||
// It used to be that PyObject was not supported with (get, set)
|
||||
// - this test is just ensuring it compiles.
|
||||
|
@ -316,7 +316,7 @@ fn test_pymethods_from_py_with() {
|
|||
})
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct TupleClass(#[pyo3(get, set, name = "value")] i32);
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -4,7 +4,7 @@ use pyo3::ToPyObject;
|
|||
#[macro_use]
|
||||
mod common;
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
struct Cloneable {
|
||||
x: i32,
|
||||
|
@ -30,7 +30,7 @@ fn test_cloneable_pyclass() {
|
|||
assert_eq!(&c, &*mrc);
|
||||
}
|
||||
|
||||
#[pyclass(subclass)]
|
||||
#[pyclass(subclass, mutable)]
|
||||
#[derive(Default)]
|
||||
struct BaseClass {
|
||||
value: i32,
|
||||
|
@ -43,7 +43,7 @@ impl BaseClass {
|
|||
}
|
||||
}
|
||||
|
||||
#[pyclass(extends=BaseClass)]
|
||||
#[pyclass(extends=BaseClass, mutable)]
|
||||
struct SubClass {}
|
||||
|
||||
#[pymethods]
|
||||
|
@ -53,7 +53,7 @@ impl SubClass {
|
|||
}
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct PolymorphicContainer {
|
||||
#[pyo3(get, set)]
|
||||
inner: Py<BaseClass>,
|
||||
|
|
|
@ -81,7 +81,7 @@ fn data_is_dropped() {
|
|||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct GcIntegration {
|
||||
self_ref: PyObject,
|
||||
dropped: TestDropCall,
|
||||
|
@ -127,7 +127,7 @@ fn gc_integration() {
|
|||
assert!(drop_called.load(Ordering::Relaxed));
|
||||
}
|
||||
|
||||
#[pyclass(gc)]
|
||||
#[pyclass(gc, mutable)]
|
||||
struct GcIntegration2 {}
|
||||
|
||||
#[pyproto]
|
||||
|
@ -181,7 +181,7 @@ fn inherited_weakref() {
|
|||
);
|
||||
}
|
||||
|
||||
#[pyclass(subclass)]
|
||||
#[pyclass(subclass, mutable)]
|
||||
struct BaseClassWithDrop {
|
||||
data: Option<Arc<AtomicBool>>,
|
||||
}
|
||||
|
@ -202,7 +202,7 @@ impl Drop for BaseClassWithDrop {
|
|||
}
|
||||
}
|
||||
|
||||
#[pyclass(extends = BaseClassWithDrop)]
|
||||
#[pyclass(extends = BaseClassWithDrop, mutable)]
|
||||
struct SubClassWithDrop {
|
||||
data: Option<Arc<AtomicBool>>,
|
||||
}
|
||||
|
@ -249,7 +249,7 @@ fn inheritance_with_new_methods_with_drop() {
|
|||
assert!(drop_called2.load(Ordering::Relaxed));
|
||||
}
|
||||
|
||||
#[pyclass(gc)]
|
||||
#[pyclass(gc, mutable)]
|
||||
struct TraversableClass {
|
||||
traversed: AtomicBool,
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use pyo3::types::{IntoPyDict, PyList};
|
|||
|
||||
mod common;
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct ClassWithProperties {
|
||||
num: i32,
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ fn class_with_properties() {
|
|||
py_assert!(py, *d, "C.DATA.__doc__ == 'a getter for data'");
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct GetterSetter {
|
||||
#[pyo3(get, set)]
|
||||
num: i32,
|
||||
|
@ -103,7 +103,7 @@ fn getter_setter_autogen() {
|
|||
);
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct RefGetterSetter {
|
||||
num: i32,
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ fn ref_getter_setter() {
|
|||
py_run!(py, inst, "inst.num = 20; assert inst.num == 20");
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct TupleClassGetterSetter(i32);
|
||||
|
||||
#[pymethods]
|
||||
|
|
|
@ -5,7 +5,7 @@ use pyo3::types::IntoPyDict;
|
|||
|
||||
mod common;
|
||||
|
||||
#[pyclass(subclass)]
|
||||
#[pyclass(subclass, mutable)]
|
||||
struct BaseClass {
|
||||
#[pyo3(get)]
|
||||
val1: usize,
|
||||
|
@ -45,7 +45,7 @@ impl BaseClass {
|
|||
}
|
||||
}
|
||||
|
||||
#[pyclass(extends=BaseClass)]
|
||||
#[pyclass(extends=BaseClass, mutable)]
|
||||
struct SubClass {
|
||||
#[pyo3(get)]
|
||||
val2: usize,
|
||||
|
|
|
@ -45,7 +45,7 @@ fn_macro!("(a, b=None, *, c=42)", a, b = "None", c = 42);
|
|||
|
||||
macro_rules! property_rename_via_macro {
|
||||
($prop_name:ident) => {
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct ClassWithProperty {
|
||||
member: u64,
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ use pyo3::PyMappingProtocol;
|
|||
|
||||
mod common;
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct Mapping {
|
||||
index: HashMap<String, usize>,
|
||||
}
|
||||
|
|
|
@ -675,7 +675,7 @@ fn method_with_lifetime() {
|
|||
);
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct MethodWithPyClassArg {
|
||||
#[pyo3(get)]
|
||||
value: i64,
|
||||
|
@ -824,7 +824,7 @@ fn test_from_sequence() {
|
|||
py_assert!(py, typeobj, "typeobj(range(0, 4)).numbers == [0, 1, 2, 3]")
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct r#RawIdents {
|
||||
#[pyo3(get, set)]
|
||||
r#type: PyObject,
|
||||
|
|
|
@ -6,7 +6,7 @@ use std::{isize, iter};
|
|||
|
||||
mod common;
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct ExampleClass {
|
||||
#[pyo3(get, set)]
|
||||
value: i32,
|
||||
|
@ -194,7 +194,7 @@ fn len() {
|
|||
py_expect_exception!(py, inst, "len(inst)", PyOverflowError);
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct Iterator {
|
||||
iter: Box<dyn iter::Iterator<Item = i32> + Send>,
|
||||
}
|
||||
|
@ -278,7 +278,7 @@ mod deprecated {
|
|||
}
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
#[derive(Debug)]
|
||||
struct SetItem {
|
||||
key: i32,
|
||||
|
@ -308,7 +308,7 @@ fn setitem() {
|
|||
py_expect_exception!(py, c, "del c[1]", PyNotImplementedError);
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct DelItem {
|
||||
key: i32,
|
||||
}
|
||||
|
@ -334,7 +334,7 @@ fn delitem() {
|
|||
py_expect_exception!(py, c, "c[1] = 2", PyNotImplementedError);
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct SetDelItem {
|
||||
val: Option<i32>,
|
||||
}
|
||||
|
@ -418,7 +418,7 @@ fn test_getitem() {
|
|||
py_assert!(py, ob, "ob[100:200:1] == 'slice'");
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct ClassWithGetAttr {
|
||||
#[pyo3(get, set)]
|
||||
data: u32,
|
||||
|
@ -441,7 +441,7 @@ fn getattr_doesnt_override_member() {
|
|||
}
|
||||
|
||||
/// Wraps a Python future and yield it once.
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct OnceFuture {
|
||||
future: PyObject,
|
||||
polled: bool,
|
||||
|
@ -505,7 +505,7 @@ loop.close()
|
|||
}
|
||||
|
||||
/// Increment the count when `__get__` is called.
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct DescrCounter {
|
||||
#[pyo3(get)]
|
||||
count: usize,
|
||||
|
|
|
@ -47,7 +47,7 @@ fn len() {
|
|||
py_expect_exception!(py, inst, "len(inst)", PyOverflowError);
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct Iterator {
|
||||
iter: Box<dyn iter::Iterator<Item = i32> + Send>,
|
||||
}
|
||||
|
@ -149,7 +149,7 @@ fn comparisons() {
|
|||
py_assert!(py, zero, "not zero");
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
#[derive(Debug)]
|
||||
struct Sequence {
|
||||
fields: Vec<String>,
|
||||
|
@ -210,7 +210,7 @@ fn sequence() {
|
|||
py_expect_exception!(py, c, "c['abc']", PyTypeError);
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
#[derive(Debug)]
|
||||
struct SetItem {
|
||||
key: i32,
|
||||
|
@ -240,7 +240,7 @@ fn setitem() {
|
|||
py_expect_exception!(py, c, "del c[1]", PyNotImplementedError);
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct DelItem {
|
||||
key: i32,
|
||||
}
|
||||
|
@ -266,7 +266,7 @@ fn delitem() {
|
|||
py_expect_exception!(py, c, "c[1] = 2", PyNotImplementedError);
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct SetDelItem {
|
||||
val: Option<i32>,
|
||||
}
|
||||
|
@ -338,7 +338,7 @@ fn contains() {
|
|||
py_expect_exception!(py, c, "assert 'wrong type' not in c", PyTypeError);
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct ContextManager {
|
||||
exit_called: bool,
|
||||
}
|
||||
|
@ -507,7 +507,7 @@ fn weakref_dunder_dict_support() {
|
|||
);
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct ClassWithGetAttr {
|
||||
#[pyo3(get, set)]
|
||||
data: u32,
|
||||
|
@ -530,7 +530,7 @@ fn getattr_doesnt_override_member() {
|
|||
}
|
||||
|
||||
/// Wraps a Python future and yield it once.
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct OnceFuture {
|
||||
future: PyObject,
|
||||
polled: bool,
|
||||
|
@ -600,7 +600,7 @@ loop.close()
|
|||
}
|
||||
|
||||
/// Increment the count when `__get__` is called.
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct DescrCounter {
|
||||
#[pyo3(get)]
|
||||
count: usize,
|
||||
|
|
|
@ -8,7 +8,7 @@ mod common;
|
|||
|
||||
/// Assumes it's a file reader or so.
|
||||
/// Inspired by https://github.com/jothan/cordoba, thanks.
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
#[derive(Clone, Debug)]
|
||||
struct Reader {
|
||||
inner: HashMap<u8, String>,
|
||||
|
@ -44,7 +44,7 @@ impl Reader {
|
|||
}
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
#[derive(Debug)]
|
||||
struct Iter {
|
||||
reader: Py<Reader>,
|
||||
|
|
|
@ -7,7 +7,7 @@ use pyo3::py_run;
|
|||
|
||||
mod common;
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct ByteSequence {
|
||||
elements: Vec<u8>,
|
||||
}
|
||||
|
@ -232,7 +232,7 @@ fn test_inplace_repeat() {
|
|||
|
||||
// Check that #[pyo3(get, set)] works correctly for Vec<PyObject>
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct GenericList {
|
||||
#[pyo3(get, set)]
|
||||
items: Vec<PyObject>,
|
||||
|
@ -265,7 +265,7 @@ fn test_generic_list_set() {
|
|||
);
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct OptionList {
|
||||
#[pyo3(get, set)]
|
||||
items: Vec<Option<i64>>,
|
||||
|
|
|
@ -6,7 +6,7 @@ use std::fmt;
|
|||
|
||||
mod common;
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(mutable)]
|
||||
struct MutRefArg {
|
||||
n: i32,
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue