feat: add #[pyo3(get, set)] for Cell

This commit is contained in:
Antoine Romero-Romero 2023-03-05 18:44:45 +00:00
parent 59bbb40a35
commit a629e8267a
4 changed files with 49 additions and 0 deletions

View file

@ -437,6 +437,8 @@ To use these annotations, your field type must implement some conversion traits:
- For `get` the field type must implement both `IntoPy<PyObject>` and `Clone`.
- For `set` the field type must implement `FromPyObject`.
For example, implementations of those traits are provided for the `Cell` type, if the inner type also implements the trait. This means you can use `#[pyo3(get, set)]` on fields wrapped in a `Cell`.
### Object properties using `#[getter]` and `#[setter]`
For cases which don't satisfy the `#[pyo3(get, set)]` trait requirements, or need side effects, descriptor methods can be defined in a `#[pymethods]` `impl` block.

View file

@ -0,0 +1 @@
Add an `IntoPy<PyObject>`, `ToPyObject` and `FromPyObject` impl for `Cell`.

View file

@ -10,6 +10,7 @@ use crate::types::PyTuple;
use crate::{
ffi, gil, Py, PyAny, PyCell, PyClass, PyNativeType, PyObject, PyRef, PyRefMut, Python,
};
use std::cell::Cell;
use std::ptr::NonNull;
/// Returns a borrowed pointer to a Python object.
@ -370,6 +371,24 @@ where
}
}
impl<T: Copy + ToPyObject> ToPyObject for Cell<T> {
fn to_object(&self, py: Python<'_>) -> PyObject {
self.get().to_object(py)
}
}
impl<T: Copy + IntoPy<PyObject>> IntoPy<PyObject> for Cell<T> {
fn into_py(self, py: Python<'_>) -> PyObject {
self.get().into_py(py)
}
}
impl<'a, T: FromPyObject<'a>> FromPyObject<'a> for Cell<T> {
fn extract(ob: &'a PyAny) -> PyResult<Self> {
T::extract(ob).map(Cell::new)
}
}
impl<'a, T> FromPyObject<'a> for &'a PyCell<T>
where
T: PyClass,

View file

@ -1,5 +1,7 @@
#![cfg(feature = "macros")]
use std::cell::Cell;
use pyo3::prelude::*;
use pyo3::py_run;
use pyo3::types::{IntoPyDict, PyList};
@ -189,3 +191,28 @@ fn get_all_and_set() {
py_run!(py, inst, "inst.num = 20; assert inst.num == 20");
});
}
#[pyclass]
struct CellGetterSetter {
#[pyo3(get, set)]
cell_inner: Cell<i32>,
}
#[test]
fn cell_getter_setter() {
let c = CellGetterSetter {
cell_inner: Cell::new(10),
};
Python::with_gil(|py| {
let inst = Py::new(py, c).unwrap().to_object(py);
let cell = Cell::new(20).to_object(py);
py_run!(py, cell, "assert cell == 20");
py_run!(py, inst, "assert inst.cell_inner == 10");
py_run!(
py,
inst,
"inst.cell_inner = 20; assert inst.cell_inner == 20"
);
});
}