-
Notifications
You must be signed in to change notification settings - Fork 760
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a map
method to PyRef
& PyRefMut
#2300
Comments
Yes absolutely agree this API makes sense. I think in combination with the (poorly-worded) idea in #1089 it would hopefully become possible to create Python objects which don't have their own data, instead just borrowing from sub-fields of other objects. Experimentation in this area is very welcome 👍 |
I imagine we would want these as associated methods like std's guards. It would be called like #[pymethods]
impl Example {
pub fn inner(mut slf: PyRefMut<'_, Self>) -> PyRefMut<'_, ExampleInner> {
PyRefMut::map(slf, |val| val.inner)
}
} 👍 from me |
Small correction, needs to be |
I tried to play with this. Passing the let python_obj: Py<...> = ...;
let pyref1 = python_obj.as_ref(py).borrow();
let pyref2 = PyRef::map(pyref2, |pyref| pyref.field.as_ref(py)); The problem is that for accessing I was able to make it work by passing the pub fn map<'s, F, Target>(&'s self, f: F) -> PyRef<'p, Target>
where F: FnOnce(&'s Self) -> &'p PyCell<Target>,
Target: PyClass,
{
PyRef {
inner: f(self)
}
} The problem is that with this API, I'm able to return some completely unrelated |
I think I know what you mean, but let me know if I'm wrong: It's that the In that case, I've had a look at whether that is possible via use std::cell::{RefCell, Ref};
static UNRELATED: usize = 4;
fn main() {
let c = RefCell::new(5);
let b1 = c.borrow();
Ref::map(b1, |_| &UNRELATED);
} I don't know if that is something that needs to be restricted, since it's possible in std, unless there are some unsafe or other considerations. |
Good point. I tried to make something like this work: fn map_ref<'a>(py: Python<'a>, pyref: PyRef<'a, S1>) -> PyRef<'a, S2> {
let inner: &'a PyCell<S2> = pyref.s2.as_ref(py);
PyRef {
inner: inner
}
} but this won't work, because pub fn as_ref<'py>(&'py self, _py: Python<'py>) -> &'py T::AsRefTarget It takes the shortest of the two lifetimes of This is done on purpose, there's To sum up, I'm not sure if it's even possible to write the function |
I have tried a bit and the only thing I managed to do is the following: impl<'p, T: PyClass> PyRef<'p, T> {
pub fn map<U: PyClass + AsRef<PyAny>, F>(orig: PyRef<'p, T>, f: F) -> PyResult<PyRef<'p, U>>
where
F: FnOnce(&T) -> &U,
{
unsafe {
let inner: &'p T = &*orig.inner.get_ptr();
// Or:
// let inner: &'p T = orig.inner.try_borrow_unguarded()?;
let value: &'p U = f(inner);
PyRef::extract(value.as_ref())
}
}
} Which works but requires the output type to implement |
"good first issue" seems optimistic |
@dimbleby reasonable suggestion. Originally I tagged it because I thought it was an API design problem and relatively orthogonal to the rest of PyO3, but I think now this is relatively coupled to the internal representation of PyO3 types. |
As a related question, does the macro backend generates different output for a pyclass field and a non-pyclass field? Or in the example provided by the OP, it is possible to obtain a |
At the moment that's not possible, but I'd definitely want it to be. At the moment a A possible first step would be to allow this for With the introduction of the new |
I've read through the documentation & haven't seen an easy way to do this, although it might be possible.
Sometimes you want to provide a mutable reference to a field contained within a struct. If you are using std's
RefCell
and it's equivalentRef
orRefMut
, what you can do is callmap
to provide mutable access to fields within structs.It would be great if the same thing could happen with
PyRefMut
&PyRef
.Here's an example of what I am trying to accomplish:
The text was updated successfully, but these errors were encountered: