comparison rust/hg-cpython/src/revlog.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 f94c10334bcb
children 8b89f7cc953a
comparison
equal deleted inserted replaced
51251:f94c10334bcb 51252:24d3298189d7
40 py: Python, 40 py: Python,
41 index: PyObject, 41 index: PyObject,
42 ) -> PyResult<UnsafePyLeaked<PySharedIndex>> { 42 ) -> PyResult<UnsafePyLeaked<PySharedIndex>> {
43 let midx = index.extract::<Index>(py)?; 43 let midx = index.extract::<Index>(py)?;
44 let leaked = midx.index(py).leak_immutable(); 44 let leaked = midx.index(py).leak_immutable();
45 // Safety: we don't leak the "faked" reference out of the `UnsafePyLeaked`
45 Ok(unsafe { leaked.map(py, |idx| PySharedIndex { inner: idx }) }) 46 Ok(unsafe { leaked.map(py, |idx| PySharedIndex { inner: idx }) })
46 } 47 }
47 48
48 impl Clone for PySharedIndex { 49 impl Clone for PySharedIndex {
49 fn clone(&self) -> Self { 50 fn clone(&self) -> Self {
973 /// the inner index would fail because of `PySharedRef` poisoning 974 /// the inner index would fail because of `PySharedRef` poisoning
974 /// (generation-based guard), same as iterating on a `dict` that has 975 /// (generation-based guard), same as iterating on a `dict` that has
975 /// been meanwhile mutated. 976 /// been meanwhile mutated.
976 def is_invalidated(&self) -> PyResult<bool> { 977 def is_invalidated(&self) -> PyResult<bool> {
977 let leaked = self.index(py).borrow(); 978 let leaked = self.index(py).borrow();
979 // Safety: we don't leak the "faked" reference out of `UnsafePyLeaked`
978 let result = unsafe { leaked.try_borrow(py) }; 980 let result = unsafe { leaked.try_borrow(py) };
979 // two cases for result to be an error: 981 // two cases for result to be an error:
980 // - the index has previously been mutably borrowed 982 // - the index has previously been mutably borrowed
981 // - there is currently a mutable borrow 983 // - there is currently a mutable borrow
982 // in both cases this amounts for previous results related to 984 // in both cases this amounts for previous results related to
984 Ok(result.is_err()) 986 Ok(result.is_err())
985 } 987 }
986 988
987 def insert(&self, rev: PyRevision) -> PyResult<PyObject> { 989 def insert(&self, rev: PyRevision) -> PyResult<PyObject> {
988 let leaked = self.index(py).borrow(); 990 let leaked = self.index(py).borrow();
991 // Safety: we don't leak the "faked" reference out of `UnsafePyLeaked`
989 let index = &*unsafe { leaked.try_borrow(py)? }; 992 let index = &*unsafe { leaked.try_borrow(py)? };
990 993
991 let rev = UncheckedRevision(rev.0); 994 let rev = UncheckedRevision(rev.0);
992 let rev = index 995 let rev = index
993 .check_revision(rev) 996 .check_revision(rev)
1018 node_prefix.as_object())) 1021 node_prefix.as_object()))
1019 )?; 1022 )?;
1020 1023
1021 let nt = self.nt(py).borrow(); 1024 let nt = self.nt(py).borrow();
1022 let leaked = self.index(py).borrow(); 1025 let leaked = self.index(py).borrow();
1026 // Safety: we don't leak the "faked" reference out of `UnsafePyLeaked`
1023 let index = &*unsafe { leaked.try_borrow(py)? }; 1027 let index = &*unsafe { leaked.try_borrow(py)? };
1024 1028
1025 Ok(nt.find_bin(index, prefix) 1029 Ok(nt.find_bin(index, prefix)
1026 .map_err(|e| nodemap_error(py, e))? 1030 .map_err(|e| nodemap_error(py, e))?
1027 .map(|r| r.into()) 1031 .map(|r| r.into())
1029 } 1033 }
1030 1034
1031 def shortest(&self, node: PyBytes) -> PyResult<usize> { 1035 def shortest(&self, node: PyBytes) -> PyResult<usize> {
1032 let nt = self.nt(py).borrow(); 1036 let nt = self.nt(py).borrow();
1033 let leaked = self.index(py).borrow(); 1037 let leaked = self.index(py).borrow();
1038 // Safety: we don't leak the "faked" reference out of `UnsafePyLeaked`
1034 let idx = &*unsafe { leaked.try_borrow(py)? }; 1039 let idx = &*unsafe { leaked.try_borrow(py)? };
1035 match nt.unique_prefix_len_node(idx, &node_from_py_bytes(py, &node)?) 1040 match nt.unique_prefix_len_node(idx, &node_from_py_bytes(py, &node)?)
1036 { 1041 {
1037 Ok(Some(l)) => Ok(l), 1042 Ok(Some(l)) => Ok(l),
1038 Ok(None) => Err(revlog_error(py)), 1043 Ok(None) => Err(revlog_error(py)),