7 // This software may be used and distributed according to the terms of the |
7 // This software may be used and distributed according to the terms of the |
8 // GNU General Public License version 2 or any later version. |
8 // GNU General Public License version 2 or any later version. |
9 #![allow(non_snake_case)] |
9 #![allow(non_snake_case)] |
10 use pyo3::buffer::PyBuffer; |
10 use pyo3::buffer::PyBuffer; |
11 use pyo3::prelude::*; |
11 use pyo3::prelude::*; |
12 use pyo3::types::{PyBytes, PyBytesMethods, PyList}; |
12 use pyo3::types::{PyBytes, PyBytesMethods, PyList, PyTuple}; |
13 use pyo3_sharedref::PyShareable; |
13 use pyo3_sharedref::PyShareable; |
14 |
14 |
15 use std::sync::{ |
15 use std::sync::{ |
16 atomic::{AtomicUsize, Ordering}, |
16 atomic::{AtomicUsize, Ordering}, |
17 RwLock, RwLockReadGuard, RwLockWriteGuard, |
17 RwLock, RwLockReadGuard, RwLockWriteGuard, |
19 |
19 |
20 use hg::{ |
20 use hg::{ |
21 revlog::{ |
21 revlog::{ |
22 index::Index, |
22 index::Index, |
23 inner_revlog::InnerRevlog as CoreInnerRevlog, |
23 inner_revlog::InnerRevlog as CoreInnerRevlog, |
24 nodemap::{NodeMap, NodeTree as CoreNodeTree}, |
24 nodemap::{NodeMap, NodeMapError, NodeTree as CoreNodeTree}, |
25 options::RevlogOpenOptions, |
25 options::RevlogOpenOptions, |
26 RevlogIndex, RevlogType, |
26 RevlogIndex, RevlogType, |
27 }, |
27 }, |
28 utils::files::get_path_from_bytes, |
28 utils::files::get_path_from_bytes, |
29 vfs::FnCacheVfs, |
29 vfs::FnCacheVfs, |
30 BaseRevision, Revision, |
30 BaseRevision, Revision, UncheckedRevision, |
31 }; |
31 }; |
32 |
32 |
33 use crate::{ |
33 use crate::{ |
34 exceptions::{ |
34 exceptions::{ |
35 map_lock_error, map_try_lock_error, nodemap_error, revlog_error_bare, |
35 map_lock_error, map_try_lock_error, nodemap_error, revlog_error_bare, |
223 .map_err(nodemap_error)? |
225 .map_err(nodemap_error)? |
224 .map(|rev| py_node_for_rev(slf.py(), idx, rev))) |
226 .map(|rev| py_node_for_rev(slf.py(), idx, rev))) |
225 }) |
227 }) |
226 } |
228 } |
227 |
229 |
|
230 /// append an index entry |
|
231 fn _index_append( |
|
232 slf: &Bound<'_, Self>, |
|
233 tup: &Bound<'_, PyTuple>, |
|
234 ) -> PyResult<()> { |
|
235 // no need to check length: in PyO3 tup.get_item() does return |
|
236 // proper errors |
|
237 let node_bytes = tup.get_item(7)?.extract()?; |
|
238 let node = node_from_py_bytes(&node_bytes)?; |
|
239 |
|
240 Self::with_index_nt_write(slf, |idx, nt| { |
|
241 let rev = idx.len() as BaseRevision; |
|
242 // This is ok since we will immediately add the revision to the |
|
243 // index |
|
244 let rev = Revision(rev); |
|
245 idx.append(py_tuple_to_revision_data_params(tup)?) |
|
246 .map_err(revlog_error_from_msg)?; |
|
247 |
|
248 nt.insert(idx, &node, rev).map_err(nodemap_error)?; |
|
249 Ok(()) |
|
250 }) |
|
251 } |
|
252 |
|
253 /// Removes one or several entries from the index. |
|
254 /// |
|
255 /// Historically, on the Mercurial revlog index, `__delitem__` has always |
|
256 /// been both for `del idx[r1]` and `del idx[r1:r2]`. In both cases, |
|
257 /// all entries starting from `r1` are removed anyway. |
|
258 fn _index___delitem__( |
|
259 slf: &Bound<'_, Self>, |
|
260 arg: &Bound<'_, PyAny>, |
|
261 ) -> PyResult<()> { |
|
262 let start = if let Ok(rev) = arg.extract() { |
|
263 UncheckedRevision(rev) |
|
264 } else { |
|
265 // here we could downcast to `PySlice` and use `indices()`, *but* |
|
266 // the rust-cpython based version could not do that, and |
|
267 // `indices()` does some resolving that makes it not equivalent, |
|
268 // e.g., `idx[-1::]` has `start=0`. As we are currently in |
|
269 // transition, we keep it the old way (hoping it was consistent |
|
270 // with the C index). |
|
271 let start = arg.getattr("start")?; |
|
272 UncheckedRevision(start.extract()?) |
|
273 }; |
|
274 |
|
275 Self::with_index_nt_write(slf, |idx, nt| { |
|
276 // In the case of a slice, the check is possibly already done by |
|
277 // `slice.indices`, which is itself an FFI wrapper for CPython's |
|
278 // `PySlice_GetIndicesEx` |
|
279 // (Python integration tests will tell us) |
|
280 let start = idx.check_revision(start).ok_or_else(|| { |
|
281 nodemap_error(NodeMapError::RevisionNotInIndex(start)) |
|
282 })?; |
|
283 idx.remove(start).map_err(revlog_error_from_msg)?; |
|
284 nt.invalidate_all(); |
|
285 Self::fill_nodemap(idx, nt)?; |
|
286 Ok(()) |
|
287 }) |
|
288 } |
|
289 |
228 fn _index___len__(slf: &Bound<'_, Self>) -> PyResult<usize> { |
290 fn _index___len__(slf: &Bound<'_, Self>) -> PyResult<usize> { |
229 Self::with_index_read(slf, |idx| Ok(idx.len())) |
291 Self::with_index_read(slf, |idx| Ok(idx.len())) |
230 } |
292 } |
231 } |
293 } |
232 |
294 |
256 let shareable_ref = unsafe { self_ref.irl.borrow_with_owner(slf) }; |
318 let shareable_ref = unsafe { self_ref.irl.borrow_with_owner(slf) }; |
257 let guard = shareable_ref.try_read().map_err(map_try_lock_error)?; |
319 let guard = shareable_ref.try_read().map_err(map_try_lock_error)?; |
258 f(&self_ref, guard) |
320 f(&self_ref, guard) |
259 } |
321 } |
260 |
322 |
261 #[allow(dead_code)] |
|
262 /// Take the lock on `slf.irl` for writing and call a closure. |
323 /// Take the lock on `slf.irl` for writing and call a closure. |
263 /// |
324 /// |
264 /// See [`Self::with_core_read`] for more explanations. |
325 /// See [`Self::with_core_read`] for more explanations. |
265 fn with_core_write<'py, T>( |
326 fn with_core_write<'py, T>( |
266 slf: &Bound<'py, Self>, |
327 slf: &Bound<'py, Self>, |
308 let nt = nt.as_ref().expect("nodetree should be set"); |
369 let nt = nt.as_ref().expect("nodetree should be set"); |
309 f(idx, nt) |
370 f(idx, nt) |
310 }) |
371 }) |
311 } |
372 } |
312 |
373 |
313 #[allow(dead_code)] |
|
314 fn with_index_nt_write<T>( |
374 fn with_index_nt_write<T>( |
315 slf: &Bound<'_, Self>, |
375 slf: &Bound<'_, Self>, |
316 f: impl FnOnce(&mut Index, &mut CoreNodeTree) -> PyResult<T>, |
376 f: impl FnOnce(&mut Index, &mut CoreNodeTree) -> PyResult<T>, |
317 ) -> PyResult<T> { |
377 ) -> PyResult<T> { |
318 Self::with_core_write(slf, |self_ref, mut guard| { |
378 Self::with_core_write(slf, |self_ref, mut guard| { |