Mercurial > public > mercurial-scm > hg
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 |
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 } |