Show More
@@ -0,0 +1,78 | |||||
|
1 | use pyo3::prelude::*; | |||
|
2 | ||||
|
3 | use hg::revlog::RevlogIndex; | |||
|
4 | use hg::{BaseRevision, Revision, UncheckedRevision}; | |||
|
5 | ||||
|
6 | use crate::exceptions::GraphError; | |||
|
7 | ||||
|
8 | /// Revision as exposed to/from the Python layer. | |||
|
9 | /// | |||
|
10 | /// We need this indirection because of the orphan rule, meaning we can't | |||
|
11 | /// implement a foreign trait (like [`cpython::ToPyObject`]) | |||
|
12 | /// for a foreign type (like [`hg::UncheckedRevision`]). | |||
|
13 | /// | |||
|
14 | /// This also acts as a deterrent against blindly trusting Python to send | |||
|
15 | /// us valid revision numbers. | |||
|
16 | #[derive( | |||
|
17 | Debug, | |||
|
18 | Copy, | |||
|
19 | Clone, | |||
|
20 | PartialEq, | |||
|
21 | Eq, | |||
|
22 | PartialOrd, | |||
|
23 | Ord, | |||
|
24 | Hash, | |||
|
25 | derive_more::From, | |||
|
26 | IntoPyObject, | |||
|
27 | FromPyObject, | |||
|
28 | )] | |||
|
29 | pub struct PyRevision(pub BaseRevision); | |||
|
30 | ||||
|
31 | impl From<Revision> for PyRevision { | |||
|
32 | fn from(r: Revision) -> Self { | |||
|
33 | PyRevision(r.0) | |||
|
34 | } | |||
|
35 | } | |||
|
36 | ||||
|
37 | /// Utility function to convert a Python iterable into various collections | |||
|
38 | /// | |||
|
39 | /// We need this in particular | |||
|
40 | /// - because of the checked upgrade from [`PyRevision`] to [`Revision`]. | |||
|
41 | /// - to feed to various methods of inner objects with `impl | |||
|
42 | /// IntoIterator<Item=Revision>` arguments, because a `PyErr` can arise at | |||
|
43 | /// each step of iteration, whereas these methods expect iterables over | |||
|
44 | /// `Revision`, not over some `Result<Revision, PyErr>` | |||
|
45 | pub fn rev_pyiter_collect<C, I>( | |||
|
46 | revs: &Bound<'_, PyAny>, | |||
|
47 | index: &I, | |||
|
48 | ) -> PyResult<C> | |||
|
49 | where | |||
|
50 | C: FromIterator<Revision>, | |||
|
51 | I: RevlogIndex, | |||
|
52 | { | |||
|
53 | rev_pyiter_collect_or_else(revs, index, |r| { | |||
|
54 | PyErr::new::<GraphError, _>(("InvalidRevision", r.0)) | |||
|
55 | }) | |||
|
56 | } | |||
|
57 | ||||
|
58 | /// Same as [`rev_pyiter_collect`], giving control on returned errors | |||
|
59 | pub fn rev_pyiter_collect_or_else<C, I>( | |||
|
60 | revs: &Bound<'_, PyAny>, | |||
|
61 | index: &I, | |||
|
62 | invalid_rev_error: impl FnOnce(PyRevision) -> PyErr + Copy, | |||
|
63 | ) -> PyResult<C> | |||
|
64 | where | |||
|
65 | C: FromIterator<Revision>, | |||
|
66 | I: RevlogIndex, | |||
|
67 | { | |||
|
68 | revs.try_iter()? | |||
|
69 | .map(|r| { | |||
|
70 | r.and_then(|o| match o.extract::<PyRevision>() { | |||
|
71 | Ok(r) => index | |||
|
72 | .check_revision(UncheckedRevision(r.0)) | |||
|
73 | .ok_or_else(|| invalid_rev_error(r)), | |||
|
74 | Err(e) => Err(e), | |||
|
75 | }) | |||
|
76 | }) | |||
|
77 | .collect() | |||
|
78 | } |
@@ -712,6 +712,7 dependencies = [ | |||||
712 | name = "hg-pyo3" |
|
712 | name = "hg-pyo3" | |
713 | version = "0.1.0" |
|
713 | version = "0.1.0" | |
714 | dependencies = [ |
|
714 | dependencies = [ | |
|
715 | "derive_more", | |||
715 | "env_logger 0.9.3", |
|
716 | "env_logger 0.9.3", | |
716 | "hg-core", |
|
717 | "hg-core", | |
717 | "log", |
|
718 | "log", |
@@ -12,4 +12,5 pyo3 = { version = "0.23.1", features = | |||||
12 | hg-core = { path = "../hg-core"} |
|
12 | hg-core = { path = "../hg-core"} | |
13 | stable_deref_trait = "1.2.0" |
|
13 | stable_deref_trait = "1.2.0" | |
14 | log = "0.4.17" |
|
14 | log = "0.4.17" | |
15 | env_logger = "0.9.3" No newline at end of file |
|
15 | env_logger = "0.9.3" | |
|
16 | derive_more = "0.99.17" |
General Comments 0
You need to be logged in to leave comments.
Login now