Mercurial > public > mercurial-scm > hg
diff rust/hg-cpython/src/discovery.rs @ 51252:24d3298189d7
rust-index: document safety invariants being upheld for every `unsafe` block
We've added a lot of `unsafe` code that shares Rust structs with Python.
While this is unfortunate, it is also unavoidable, so let's at least
systematically explain why each call to `unsafe` is sound.
If any of the unsafe code ends up being wrong (because everyone screws up
at some point), this change at least continues the unspoken rule of always
explaining the need for `unsafe`, so we at least get a chance to think.
author | Rapha?l Gom?s <rgomes@octobus.net> |
---|---|
date | Thu, 23 Nov 2023 03:41:58 +0100 |
parents | 0b81440e2a73 |
children |
line wrap: on
line diff
--- a/rust/hg-cpython/src/discovery.rs Sun Oct 29 12:18:03 2023 +0100 +++ b/rust/hg-cpython/src/discovery.rs Thu Nov 23 03:41:58 2023 +0100 @@ -60,18 +60,21 @@ def hasinfo(&self) -> PyResult<bool> { let leaked = self.inner(py).borrow(); + // Safety: we don't leak the "faked" reference out of `UnsafePyLeaked` let inner = unsafe { leaked.try_borrow(py)? }; Ok(inner.has_info()) } def iscomplete(&self) -> PyResult<bool> { let leaked = self.inner(py).borrow(); + // Safety: we don't leak the "faked" reference out of `UnsafePyLeaked` let inner = unsafe { leaked.try_borrow(py)? }; Ok(inner.is_complete()) } def stats(&self) -> PyResult<PyDict> { let leaked = self.inner(py).borrow(); + // Safety: we don't leak the "faked" reference out of `UnsafePyLeaked` let inner = unsafe { leaked.try_borrow(py)? }; let stats = inner.stats(); let as_dict: PyDict = PyDict::new(py); @@ -84,6 +87,7 @@ def commonheads(&self) -> PyResult<HashSet<PyRevision>> { let leaked = self.inner(py).borrow(); + // Safety: we don't leak the "faked" reference out of `UnsafePyLeaked` let inner = unsafe { leaked.try_borrow(py)? }; let res = inner.common_heads() .map_err(|e| GraphError::pynew(py, e))?; @@ -113,11 +117,12 @@ let index = repo.getattr(py, "changelog")?.getattr(py, "index")?; let cloned_index = py_rust_index_to_graph(py, index.clone_ref(py))?; let index = py_rust_index_to_graph(py, index)?; - + // Safety: we don't leak the "faked" reference out of `UnsafePyLeaked` let target_heads = { let borrowed_idx = unsafe { index.try_borrow(py)? }; rev_pyiter_collect(py, &targetheads, &*borrowed_idx)? }; + // Safety: we don't leak the "faked" reference out of `UnsafePyLeaked` let lazy_disco = unsafe { index.map(py, |idx| { CorePartialDiscovery::new( @@ -142,6 +147,7 @@ iter: &PyObject, ) -> PyResult<Vec<Revision>> { let leaked = self.index(py).borrow(); + // Safety: we don't leak the "faked" reference out of `UnsafePyLeaked` let index = unsafe { leaked.try_borrow(py)? }; rev_pyiter_collect(py, iter, &*index) } @@ -168,6 +174,7 @@ } } let mut leaked = self.inner(py).borrow_mut(); + // Safety: we don't leak the "faked" reference out of `UnsafePyLeaked` let mut inner = unsafe { leaked.try_borrow_mut(py)? }; inner .add_common_revisions(common) @@ -185,6 +192,7 @@ ) -> PyResult<PyObject> { let commons_vec = self.pyiter_to_vec(py, &commons)?; let mut leaked = self.inner(py).borrow_mut(); + // Safety: we don't leak the "faked" reference out of `UnsafePyLeaked` let mut inner = unsafe { leaked.try_borrow_mut(py)? }; inner .add_common_revisions(commons_vec) @@ -199,6 +207,7 @@ ) -> PyResult<PyObject> { let missings_vec = self.pyiter_to_vec(py, &missings)?; let mut leaked = self.inner(py).borrow_mut(); + // Safety: we don't leak the "faked" reference out of `UnsafePyLeaked` let mut inner = unsafe { leaked.try_borrow_mut(py)? }; inner .add_missing_revisions(missings_vec) @@ -213,6 +222,7 @@ size: usize, ) -> PyResult<PyObject> { let mut leaked = self.inner(py).borrow_mut(); + // Safety: we don't leak the "faked" reference out of `UnsafePyLeaked` let mut inner = unsafe { leaked.try_borrow_mut(py)? }; let sample = inner .take_full_sample(size) @@ -232,6 +242,7 @@ ) -> PyResult<PyObject> { let revsvec = self.pyiter_to_vec(py, &headrevs)?; let mut leaked = self.inner(py).borrow_mut(); + // Safety: we don't leak the "faked" reference out of `UnsafePyLeaked` let mut inner = unsafe { leaked.try_borrow_mut(py)? }; let sample = inner .take_quick_sample(revsvec, size)