annotate rust/hg-cpython/src/conversion.rs @ 52411:c2480ac4c5e2

rust-pyo3: retrieving the InnerRevlog of hg-cpython This allows PyO3-based code to use the InnerRevlog, access its shared data (core InnerRevlog), which will then allow, e.g., to retrieve references on the core Index. On the `hg-cpython` (`rusthg` crate, `rustext` Python extension module), we had to also build as a Rust library, and open up some accesses (see notably the public accessor for `inner`, the core `InnerRevlog`). Retrieving the Rust struct underlying a Python object defined by another extension module written in Rust is tricky because the Python type objects are duplicated in the extension modules, leading to failure of the normal type checking. See the doc-comment of `convert_cpython::extract_inner_revlog` for a complete explanation. To solve this, we import the Python type object of `rustext` (defined by `hg-cpython`) and perform a manual check. Checking the Python type is necessary, as PyO3 documentation clearly state that downcasting an object that has not the proper type is Undefined Behaviour. At this point, we do not have conversion facilities for exceptions (`PyErr` on both sides), hence the remaining unwraps).
author Georges Racinet <georges.racinet@cloudcrane.io>
date Sat, 30 Nov 2024 20:57:02 +0100
parents bd8081e9fd62
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
41240
ff333620a4cc rust-cpython: moved generic conversion fn out of ancestors module
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
1 // conversion.rs
ff333620a4cc rust-cpython: moved generic conversion fn out of ancestors module
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
2 //
ff333620a4cc rust-cpython: moved generic conversion fn out of ancestors module
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
3 // Copyright 2019 Georges Racinet <georges.racinet@octobus.net>
ff333620a4cc rust-cpython: moved generic conversion fn out of ancestors module
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
4 //
ff333620a4cc rust-cpython: moved generic conversion fn out of ancestors module
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
5 // This software may be used and distributed according to the terms of the
ff333620a4cc rust-cpython: moved generic conversion fn out of ancestors module
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
6 // GNU General Public License version 2 or any later version.
ff333620a4cc rust-cpython: moved generic conversion fn out of ancestors module
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
7
ff333620a4cc rust-cpython: moved generic conversion fn out of ancestors module
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
8 //! Bindings for the hg::ancestors module provided by the
ff333620a4cc rust-cpython: moved generic conversion fn out of ancestors module
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
9 //! `hg-core` crate. From Python, this will be seen as `rustext.ancestor`
ff333620a4cc rust-cpython: moved generic conversion fn out of ancestors module
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
10
50976
4c5f6e95df84 rust: make `Revision` a newtype
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
11 use cpython::{ObjectProtocol, PyErr, PyObject, PyResult, Python};
52178
bd8081e9fd62 rust: don't star export from the `revlog` module
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51218
diff changeset
12 use hg::{revlog::RevlogIndex, Revision, UncheckedRevision};
50976
4c5f6e95df84 rust: make `Revision` a newtype
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
13
4c5f6e95df84 rust: make `Revision` a newtype
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
14 use crate::{exceptions::GraphError, PyRevision};
41240
ff333620a4cc rust-cpython: moved generic conversion fn out of ancestors module
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
15
ff333620a4cc rust-cpython: moved generic conversion fn out of ancestors module
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
16 /// Utility function to convert a Python iterable into various collections
ff333620a4cc rust-cpython: moved generic conversion fn out of ancestors module
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
17 ///
ff333620a4cc rust-cpython: moved generic conversion fn out of ancestors module
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
18 /// We need this in particular to feed to various methods of inner objects
ff333620a4cc rust-cpython: moved generic conversion fn out of ancestors module
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
19 /// with `impl IntoIterator<Item=Revision>` arguments, because
ff333620a4cc rust-cpython: moved generic conversion fn out of ancestors module
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
20 /// a `PyErr` can arise at each step of iteration, whereas these methods
ff333620a4cc rust-cpython: moved generic conversion fn out of ancestors module
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
21 /// expect iterables over `Revision`, not over some `Result<Revision, PyErr>`
50976
4c5f6e95df84 rust: make `Revision` a newtype
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
22 pub fn rev_pyiter_collect<C, I>(
4c5f6e95df84 rust: make `Revision` a newtype
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
23 py: Python,
4c5f6e95df84 rust: make `Revision` a newtype
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
24 revs: &PyObject,
4c5f6e95df84 rust: make `Revision` a newtype
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
25 index: &I,
4c5f6e95df84 rust: make `Revision` a newtype
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
26 ) -> PyResult<C>
41240
ff333620a4cc rust-cpython: moved generic conversion fn out of ancestors module
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
27 where
ff333620a4cc rust-cpython: moved generic conversion fn out of ancestors module
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
28 C: FromIterator<Revision>,
50976
4c5f6e95df84 rust: make `Revision` a newtype
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
29 I: RevlogIndex,
41240
ff333620a4cc rust-cpython: moved generic conversion fn out of ancestors module
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
30 {
51218
5a7d5fd6808c hg-cpython: rev_pyiter_collect_or_else
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
31 rev_pyiter_collect_or_else(py, revs, index, |r| {
5a7d5fd6808c hg-cpython: rev_pyiter_collect_or_else
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
32 PyErr::new::<GraphError, _>(py, ("InvalidRevision", r.0))
5a7d5fd6808c hg-cpython: rev_pyiter_collect_or_else
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
33 })
5a7d5fd6808c hg-cpython: rev_pyiter_collect_or_else
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
34 }
5a7d5fd6808c hg-cpython: rev_pyiter_collect_or_else
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
35
5a7d5fd6808c hg-cpython: rev_pyiter_collect_or_else
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
36 /// Same as [`rev_pyiter_collect`], giving control on returned errors
5a7d5fd6808c hg-cpython: rev_pyiter_collect_or_else
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
37 pub fn rev_pyiter_collect_or_else<C, I>(
5a7d5fd6808c hg-cpython: rev_pyiter_collect_or_else
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
38 py: Python,
5a7d5fd6808c hg-cpython: rev_pyiter_collect_or_else
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
39 revs: &PyObject,
5a7d5fd6808c hg-cpython: rev_pyiter_collect_or_else
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
40 index: &I,
5a7d5fd6808c hg-cpython: rev_pyiter_collect_or_else
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
41 invalid_rev_error: impl FnOnce(PyRevision) -> PyErr + Copy,
5a7d5fd6808c hg-cpython: rev_pyiter_collect_or_else
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
42 ) -> PyResult<C>
5a7d5fd6808c hg-cpython: rev_pyiter_collect_or_else
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
43 where
5a7d5fd6808c hg-cpython: rev_pyiter_collect_or_else
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
44 C: FromIterator<Revision>,
5a7d5fd6808c hg-cpython: rev_pyiter_collect_or_else
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
45 I: RevlogIndex,
5a7d5fd6808c hg-cpython: rev_pyiter_collect_or_else
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
46 {
41240
ff333620a4cc rust-cpython: moved generic conversion fn out of ancestors module
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
47 revs.iter(py)?
50976
4c5f6e95df84 rust: make `Revision` a newtype
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
48 .map(|r| {
4c5f6e95df84 rust: make `Revision` a newtype
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
49 r.and_then(|o| match o.extract::<PyRevision>(py) {
4c5f6e95df84 rust: make `Revision` a newtype
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
50 Ok(r) => index
4c5f6e95df84 rust: make `Revision` a newtype
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
51 .check_revision(UncheckedRevision(r.0))
51218
5a7d5fd6808c hg-cpython: rev_pyiter_collect_or_else
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
52 .ok_or_else(|| invalid_rev_error(r)),
50976
4c5f6e95df84 rust: make `Revision` a newtype
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
53 Err(e) => Err(e),
4c5f6e95df84 rust: make `Revision` a newtype
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
54 })
4c5f6e95df84 rust: make `Revision` a newtype
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
55 })
41240
ff333620a4cc rust-cpython: moved generic conversion fn out of ancestors module
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
56 .collect()
ff333620a4cc rust-cpython: moved generic conversion fn out of ancestors module
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
57 }