12 //! - [`PartialDiscovery`] is the Rust implementation of |
12 //! - [`PartialDiscovery`] is the Rust implementation of |
13 //! `mercurial.setdiscovery.partialdiscovery`. |
13 //! `mercurial.setdiscovery.partialdiscovery`. |
14 |
14 |
15 use crate::PyRevision; |
15 use crate::PyRevision; |
16 use crate::{ |
16 use crate::{ |
17 cindex::Index, conversion::rev_pyiter_collect, exceptions::GraphError, |
17 conversion::rev_pyiter_collect, exceptions::GraphError, |
|
18 revlog::PySharedIndex, |
18 }; |
19 }; |
19 use cpython::{ |
20 use cpython::{ |
20 ObjectProtocol, PyClone, PyDict, PyModule, PyObject, PyResult, PyTuple, |
21 ObjectProtocol, PyClone, PyDict, PyModule, PyObject, PyResult, PyTuple, |
21 Python, PythonObject, ToPyObject, |
22 Python, PythonObject, ToPyObject, UnsafePyLeaked, |
22 }; |
23 }; |
23 use hg::discovery::PartialDiscovery as CorePartialDiscovery; |
24 use hg::discovery::PartialDiscovery as CorePartialDiscovery; |
24 use hg::Revision; |
25 use hg::Revision; |
25 use std::collections::HashSet; |
26 use std::collections::HashSet; |
26 |
27 |
27 use std::cell::RefCell; |
28 use std::cell::RefCell; |
28 |
29 |
29 use crate::revlog::pyindex_to_graph; |
30 use crate::revlog::py_rust_index_to_graph; |
30 |
31 |
31 py_class!(pub class PartialDiscovery |py| { |
32 py_class!(pub class PartialDiscovery |py| { |
32 data inner: RefCell<Box<CorePartialDiscovery<Index>>>; |
33 data inner: RefCell<UnsafePyLeaked<CorePartialDiscovery<PySharedIndex>>>; |
33 data index: RefCell<Index>; |
34 data index: RefCell<UnsafePyLeaked<PySharedIndex>>; |
34 |
35 |
35 // `_respectsize` is currently only here to replicate the Python API and |
36 // `_respectsize` is currently only here to replicate the Python API and |
36 // will be used in future patches inside methods that are yet to be |
37 // will be used in future patches inside methods that are yet to be |
37 // implemented. |
38 // implemented. |
38 def __new__( |
39 def __new__( |
56 def addinfo(&self, sample: PyObject) -> PyResult<PyObject> { |
57 def addinfo(&self, sample: PyObject) -> PyResult<PyObject> { |
57 self.inner_addinfo(py, sample) |
58 self.inner_addinfo(py, sample) |
58 } |
59 } |
59 |
60 |
60 def hasinfo(&self) -> PyResult<bool> { |
61 def hasinfo(&self) -> PyResult<bool> { |
61 Ok(self.inner(py).borrow().has_info()) |
62 let leaked = self.inner(py).borrow(); |
|
63 let inner = unsafe { leaked.try_borrow(py)? }; |
|
64 Ok(inner.has_info()) |
62 } |
65 } |
63 |
66 |
64 def iscomplete(&self) -> PyResult<bool> { |
67 def iscomplete(&self) -> PyResult<bool> { |
65 Ok(self.inner(py).borrow().is_complete()) |
68 let leaked = self.inner(py).borrow(); |
|
69 let inner = unsafe { leaked.try_borrow(py)? }; |
|
70 Ok(inner.is_complete()) |
66 } |
71 } |
67 |
72 |
68 def stats(&self) -> PyResult<PyDict> { |
73 def stats(&self) -> PyResult<PyDict> { |
69 let stats = self.inner(py).borrow().stats(); |
74 let leaked = self.inner(py).borrow(); |
|
75 let inner = unsafe { leaked.try_borrow(py)? }; |
|
76 let stats = inner.stats(); |
70 let as_dict: PyDict = PyDict::new(py); |
77 let as_dict: PyDict = PyDict::new(py); |
71 as_dict.set_item(py, "undecided", |
78 as_dict.set_item(py, "undecided", |
72 stats.undecided.map( |
79 stats.undecided.map( |
73 |l| l.to_py_object(py).into_object()) |
80 |l| l.to_py_object(py).into_object()) |
74 .unwrap_or_else(|| py.None()))?; |
81 .unwrap_or_else(|| py.None()))?; |
75 Ok(as_dict) |
82 Ok(as_dict) |
76 } |
83 } |
77 |
84 |
78 def commonheads(&self) -> PyResult<HashSet<PyRevision>> { |
85 def commonheads(&self) -> PyResult<HashSet<PyRevision>> { |
79 let res = self.inner(py).borrow().common_heads() |
86 let leaked = self.inner(py).borrow(); |
|
87 let inner = unsafe { leaked.try_borrow(py)? }; |
|
88 let res = inner.common_heads() |
80 .map_err(|e| GraphError::pynew(py, e))?; |
89 .map_err(|e| GraphError::pynew(py, e))?; |
81 Ok(res.into_iter().map(Into::into).collect()) |
90 Ok(res.into_iter().map(Into::into).collect()) |
82 } |
91 } |
83 |
92 |
84 def takefullsample(&self, headrevs: PyObject, |
93 def takefullsample(&self, headrevs: PyObject, |
100 targetheads: PyObject, |
109 targetheads: PyObject, |
101 respectsize: bool, |
110 respectsize: bool, |
102 randomize: bool, |
111 randomize: bool, |
103 ) -> PyResult<Self> { |
112 ) -> PyResult<Self> { |
104 let index = repo.getattr(py, "changelog")?.getattr(py, "index")?; |
113 let index = repo.getattr(py, "changelog")?.getattr(py, "index")?; |
105 let index = pyindex_to_graph(py, index)?; |
114 let cloned_index = py_rust_index_to_graph(py, index.clone_ref(py))?; |
106 let target_heads = rev_pyiter_collect(py, &targetheads, &index)?; |
115 let index = py_rust_index_to_graph(py, index)?; |
|
116 |
|
117 let target_heads = { |
|
118 let borrowed_idx = unsafe { index.try_borrow(py)? }; |
|
119 rev_pyiter_collect(py, &targetheads, &*borrowed_idx)? |
|
120 }; |
|
121 let lazy_disco = unsafe { |
|
122 index.map(py, |idx| { |
|
123 CorePartialDiscovery::new( |
|
124 idx, |
|
125 target_heads, |
|
126 respectsize, |
|
127 randomize, |
|
128 ) |
|
129 }) |
|
130 }; |
107 Self::create_instance( |
131 Self::create_instance( |
108 py, |
132 py, |
109 RefCell::new(Box::new(CorePartialDiscovery::new( |
133 RefCell::new(lazy_disco), |
110 index.clone_ref(py), |
134 RefCell::new(cloned_index), |
111 target_heads, |
|
112 respectsize, |
|
113 randomize, |
|
114 ))), |
|
115 RefCell::new(index), |
|
116 ) |
135 ) |
117 } |
136 } |
118 |
137 |
119 /// Convert a Python iterator of revisions into a vector |
138 /// Convert a Python iterator of revisions into a vector |
120 fn pyiter_to_vec( |
139 fn pyiter_to_vec( |
121 &self, |
140 &self, |
122 py: Python, |
141 py: Python, |
123 iter: &PyObject, |
142 iter: &PyObject, |
124 ) -> PyResult<Vec<Revision>> { |
143 ) -> PyResult<Vec<Revision>> { |
125 let index = self.index(py).borrow(); |
144 let leaked = self.index(py).borrow(); |
|
145 let index = unsafe { leaked.try_borrow(py)? }; |
126 rev_pyiter_collect(py, iter, &*index) |
146 rev_pyiter_collect(py, iter, &*index) |
127 } |
147 } |
128 |
148 |
129 fn inner_addinfo( |
149 fn inner_addinfo( |
130 &self, |
150 &self, |
161 &self, |
182 &self, |
162 py: Python, |
183 py: Python, |
163 commons: PyObject, |
184 commons: PyObject, |
164 ) -> PyResult<PyObject> { |
185 ) -> PyResult<PyObject> { |
165 let commons_vec = self.pyiter_to_vec(py, &commons)?; |
186 let commons_vec = self.pyiter_to_vec(py, &commons)?; |
166 let mut inner = self.inner(py).borrow_mut(); |
187 let mut leaked = self.inner(py).borrow_mut(); |
|
188 let mut inner = unsafe { leaked.try_borrow_mut(py)? }; |
167 inner |
189 inner |
168 .add_common_revisions(commons_vec) |
190 .add_common_revisions(commons_vec) |
169 .map_err(|e| GraphError::pynew(py, e))?; |
191 .map_err(|e| GraphError::pynew(py, e))?; |
170 Ok(py.None()) |
192 Ok(py.None()) |
171 } |
193 } |
174 &self, |
196 &self, |
175 py: Python, |
197 py: Python, |
176 missings: PyObject, |
198 missings: PyObject, |
177 ) -> PyResult<PyObject> { |
199 ) -> PyResult<PyObject> { |
178 let missings_vec = self.pyiter_to_vec(py, &missings)?; |
200 let missings_vec = self.pyiter_to_vec(py, &missings)?; |
179 let mut inner = self.inner(py).borrow_mut(); |
201 let mut leaked = self.inner(py).borrow_mut(); |
|
202 let mut inner = unsafe { leaked.try_borrow_mut(py)? }; |
180 inner |
203 inner |
181 .add_missing_revisions(missings_vec) |
204 .add_missing_revisions(missings_vec) |
182 .map_err(|e| GraphError::pynew(py, e))?; |
205 .map_err(|e| GraphError::pynew(py, e))?; |
183 Ok(py.None()) |
206 Ok(py.None()) |
184 } |
207 } |
187 &self, |
210 &self, |
188 py: Python, |
211 py: Python, |
189 _headrevs: PyObject, |
212 _headrevs: PyObject, |
190 size: usize, |
213 size: usize, |
191 ) -> PyResult<PyObject> { |
214 ) -> PyResult<PyObject> { |
192 let mut inner = self.inner(py).borrow_mut(); |
215 let mut leaked = self.inner(py).borrow_mut(); |
|
216 let mut inner = unsafe { leaked.try_borrow_mut(py)? }; |
193 let sample = inner |
217 let sample = inner |
194 .take_full_sample(size) |
218 .take_full_sample(size) |
195 .map_err(|e| GraphError::pynew(py, e))?; |
219 .map_err(|e| GraphError::pynew(py, e))?; |
196 let as_vec: Vec<PyObject> = sample |
220 let as_vec: Vec<PyObject> = sample |
197 .iter() |
221 .iter() |
205 py: Python, |
229 py: Python, |
206 headrevs: PyObject, |
230 headrevs: PyObject, |
207 size: usize, |
231 size: usize, |
208 ) -> PyResult<PyObject> { |
232 ) -> PyResult<PyObject> { |
209 let revsvec = self.pyiter_to_vec(py, &headrevs)?; |
233 let revsvec = self.pyiter_to_vec(py, &headrevs)?; |
210 let mut inner = self.inner(py).borrow_mut(); |
234 let mut leaked = self.inner(py).borrow_mut(); |
|
235 let mut inner = unsafe { leaked.try_borrow_mut(py)? }; |
211 let sample = inner |
236 let sample = inner |
212 .take_quick_sample(revsvec, size) |
237 .take_quick_sample(revsvec, size) |
213 .map_err(|e| GraphError::pynew(py, e))?; |
238 .map_err(|e| GraphError::pynew(py, e))?; |
214 let as_vec: Vec<PyObject> = sample |
239 let as_vec: Vec<PyObject> = sample |
215 .iter() |
240 .iter() |