Skip to content
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

Allow passing non-mutable references to self in PyIterProtocol #856

Merged
merged 7 commits into from
Apr 19, 2020
Merged

Allow passing non-mutable references to self in PyIterProtocol #856

merged 7 commits into from
Apr 19, 2020

Conversation

althonos
Copy link
Member

@althonos althonos commented Apr 8, 2020

Current implementation of PyIterProtocol methods requires a mutable borrow, but it's not needed for all implementations (exemple in #854).

This PR adds the code to make PyIterProtocol accept either PyRef or PyRefMut as its referential argument, by doing the following:

  • Add a UnarySlf method to the derive backend, which serves to extract the right Self type from the method signature
  • Add a Slf associated type to PyIterIterProtocol and PyIterNextProtocol
  • Make the UnarySlf method wrapper use TryFrom<&PyCell> to be generic about the self-reference type ➡️ this has the shitty side-effect of preventing unwrapping the error, since TryFrom::Error are not constrained to implement Debug, and I couldn't get the type checker to accept a constraing for Debug on <T::Slf as TryFrom<&PyCell>>::Error because of lifetime issues

I also think this should be ported to other protocol: for instance PyMappingProtocol.__getitem__ may need a mutable reference (imagine a mapping maintaining a LRU cache) while PyContextProtocol may not need mutable references in __exit__.

Maintenance

  • Run cargo fmt
  • Run cargo clippy and check there are no hard errors (There are a bunch of existing warnings; This is also checked by travis)
  • If applicable, add an entry in the changelog.
  • If applicable, add documentation to all new items and extend the guide.
  • If applicable, add tests for all new or fixed functions
  • If you changed any python code, run black .. You can install black with pip install black)

@kngwyu
Copy link
Member

kngwyu commented Apr 8, 2020

Thank you!

Add a Slf associated type to PyIterIterProtocol and PyIterNextProtocol

Sounds nice to me 💯
Once I tried to solve this problem, I didn't come up with this solution.

this has the shitty side-effect of preventing unwrapping the error, since TryFrom::Error are not constrained to implement Debug, and I couldn't get the type checker to accept a constraing for Debug on <T::Slf as TryFrom<&PyCell>>::Error because of lifetime issues

I'll check this tomorrow.

@birkenfeld
Copy link
Member

Can we use Receiver instead of Slf? The latter is quite cryptic...

@davidhewitt
Copy link
Member

+1 for Receiver instead of Slf.

For the unwrap error difficulty - I have been working on some changes in #797 to make error handling easier in these callback functions. Maybe this can help you.

@kngwyu
Copy link
Member

kngwyu commented Apr 9, 2020

For the unwrap error difficulty - I have been working on some changes in #797 to make error handling easier in these callback functions. Maybe this can help you.

👍
Now I merged #858, which is a subset of #797 including callback refactoring.
So rebasing on the master can help to resolve the lifetime issue. Sorry for troubling you, though.

@althonos
Copy link
Member Author

Update: I rebased against latest master and renamed the associated types to Receiver as suggested.

I added a trait TryFromPyCell that basically only PyRef and PyRefMut implement, which is an extension to TryFrom<&'a PyCell<T>>: the standard library TryFrom is limited (we can't know that the associated error is Into<PyErr>. Ideally this is something that could be constrained in types requiring it, but it's not possible to do so without defining a new trait.

Also, not related to the PR so I didn't include that, but I think PyBorrowError and PyBorrowMutError should implement std::error::Error

@davidhewitt
Copy link
Member

Ideally this is something that could be constrained in types requiring it, but it's not possible to do so without defining a new trait.

Hmm yes I was thinking if we could achieve this with generic associated types; but they're unstable anyway. TryFromPyCell is probably fine for now.

It would be interesting to revisit this problem once we've removed specialization from the protocol implementations.

Also, not related to the PR so I didn't include that, but I think PyBorrowError and PyBorrowMutError should implement std::error::Error

+1 for this. There's a number of improvements I think needs to come to error handling in pyo3.

@althonos althonos marked this pull request as ready for review April 18, 2020 12:01
@althonos althonos requested a review from kngwyu April 18, 2020 12:01
Copy link
Member

@kngwyu kngwyu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank, almost LGTM 👍
Could you please add a test for mutable iterator (fn __iter__(slf: mut PyRefMut<Self>)) ?
Then this PR would be perfect.

@@ -38,7 +38,9 @@ macro_rules! py_unary_refmut_func {
let py = pool.python();
$crate::run_callback(py, || {
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
let res = $class::$f(slf.borrow_mut()).into();
let borrow = <T::Receiver>::try_from_pycell(slf)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess just try_from_pycell(slf)? work?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without the associated <T::Receiver>, the compiler complains about the next line and can't guess the type of e in the map_err method, so I prefer to leave it like that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, OK 👍

src/pycell.rs Outdated Show resolved Hide resolved
pyo3-derive-backend/src/func.rs Outdated Show resolved Hide resolved
@althonos althonos requested a review from kngwyu April 19, 2020 14:00
@kngwyu
Copy link
Member

kngwyu commented Apr 19, 2020

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants