-
Notifications
You must be signed in to change notification settings - Fork 778
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
use ffi::MemberGef
for #[pyo3(get)]
fields of Py<T>
#4254
Conversation
Uff, this is more painful than I was hoping for. On Rust 1.77+ where we have stable The problem is that on versions predating this, the current design doesn't work. The "backport" in I found a solution by deferring evaluation of |
db66ed2
to
547e18f
Compare
Excluding docs and changelog additions, which I'll push later, I think this is now ready for review. Despite the added complexity, this has reasonably clear benefits to me:
It will be nice to simplify things again in future after MSRV 1.77 :( e.g. consider this snippet inspired by #4247 use pyo3::prelude::*;
#[pymodule]
mod pyo3_scratch {
use pyo3::prelude::*;
#[pyclass]
struct RustClass {
#[pyo3(get)]
value: i32,
#[pyo3(get)]
py_value: Py<PyAny>,
}
#[pymethods]
impl RustClass {
#[new]
fn new(py: Python<'_>) -> Self {
RustClass {
value: 0,
py_value: 0.into_py(py),
}
}
}
} Benchmarks on
Benchmarks on this branch:
With
|
Actually, the problem is that |
I thought this too, but I was running into trouble with |
Especially this one sounds really compelling. That's a big improvement in UX after the |
Haha, yes precisely when I realised this would be the way out of regressing UX with The generics... is indeed some dark magic. I think it's a combination of coffee and a bit of luck. I genuinely think I wouldn't have worked this out without stable Let me know if there's any documentation or explanation I can push to help with review 👀 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I mostly understand this 😅
Can we duplicate the definition of PyClassObject
but without the unsafecell, and use that to compute the offset? That should probably work on Rust 1.65+
Is there some way to test that the correct path is taken for various types? I'd like to be certain that this won't regress.
Thanks for the review!
I think that would indeed work for 1.65+. I guess without it working for MSRV I'm inclined to leave this as-is, because adding yet more complexity doesn't seem like an appealing option. Let's revisit when we get our next MSRV bump, it would be nice to remove the runtime calculation and switch to that mode 👍
Good idea, I was being a bit lazy, added some unit tests to examine the generated items from the macro. With those review adjustments made, I'm going to proceed to merge this so we are one step closer to the release. |
6b16b4e
to
b862d1b
Compare
This is a bit of a mess and needs some more work, so probably best not to review it quite yet.Inspired by what I found in #4247 (comment) this PR reworks the implementation of
#[pyo3(get)]
with a couple of goals in mind:ffi::PyMemberDef
for readonlyPy<T>
fields (on frozen types)ToPyObject
where possible instead ofIntoPy<Py<PyAny>>
IntoPy<Py<PyAny>> + Clone
as a fallback to existing behaviour I guessThis seems like a good thing to land for a couple of reasons:
Clone
means that users are less likely to experience a niggle on upgrade with thepy-clone
featureffi::PyMemberDef
is significantly more performant as per #[pyo3(get)] much slower than python attribute access #4247 (comment)I will continue with tidying this up when I get the chance; I think this is worth landing in 0.22