rust-index: synchronize remove to Rust index
authorRaphaël Gomès <rgomes@octobus.net>
Wed, 28 Jun 2023 16:43:39 +0200
changeset 51195 f6403bcd9f96
parent 51194 f0fa98752d67
child 51196 f95f70cf2ee2
rust-index: synchronize remove to Rust index Future steps will bring the two indexes further together until we can rip the C index entirely when running Rust code.
rust/hg-core/src/revlog/index.rs
rust/hg-cpython/src/revlog.rs
--- a/rust/hg-core/src/revlog/index.rs	Wed Jun 28 11:59:43 2023 +0200
+++ b/rust/hg-core/src/revlog/index.rs	Wed Jun 28 16:43:39 2023 +0200
@@ -79,6 +79,10 @@
 struct IndexData {
     /// Immutable bytes, most likely taken from disk
     bytes: Box<dyn Deref<Target = [u8]> + Send>,
+    /// Used when stripping index contents, keeps track of the start of the
+    /// first stripped revision, which is used to give a slice of the
+    /// `bytes` field.
+    truncation: Option<usize>,
     /// Bytes that were added after reading the index
     added: Vec<u8>,
 }
@@ -87,12 +91,36 @@
     pub fn new(bytes: Box<dyn Deref<Target = [u8]> + Send>) -> Self {
         Self {
             bytes,
+            truncation: None,
             added: vec![],
         }
     }
 
     pub fn len(&self) -> usize {
-        self.bytes.len() + self.added.len()
+        match self.truncation {
+            Some(truncation) => truncation + self.added.len(),
+            None => self.bytes.len() + self.added.len(),
+        }
+    }
+
+    fn remove(
+        &mut self,
+        rev: Revision,
+        offsets: Option<&[usize]>,
+    ) -> Result<(), RevlogError> {
+        let rev = rev.0 as usize;
+        let truncation = if let Some(offsets) = offsets {
+            offsets[rev]
+        } else {
+            rev * INDEX_ENTRY_SIZE
+        };
+        if truncation < self.bytes.len() {
+            self.truncation = Some(truncation);
+            self.added.clear();
+        } else {
+            self.added.truncate(truncation - self.bytes.len());
+        }
+        Ok(())
     }
 }
 
@@ -102,7 +130,10 @@
     fn index(&self, index: std::ops::Range<usize>) -> &Self::Output {
         let start = index.start;
         let end = index.end;
-        let immutable_len = self.bytes.len();
+        let immutable_len = match self.truncation {
+            Some(truncation) => truncation,
+            None => self.bytes.len(),
+        };
         if start < immutable_len {
             if end > immutable_len {
                 panic!("index data cannot span existing and added ranges");
@@ -368,6 +399,14 @@
         self.bytes.added.extend(revision_data.into_v1().as_bytes());
         Ok(())
     }
+
+    pub fn remove(&mut self, rev: Revision) -> Result<(), RevlogError> {
+        self.bytes.remove(rev, self.offsets.as_deref())?;
+        if let Some(offsets) = self.offsets.as_mut() {
+            offsets.truncate(rev.0 as usize)
+        }
+        Ok(())
+    }
 }
 
 impl super::RevlogIndex for Index {
--- a/rust/hg-cpython/src/revlog.rs	Wed Jun 28 11:59:43 2023 +0200
+++ b/rust/hg-cpython/src/revlog.rs	Wed Jun 28 16:43:39 2023 +0200
@@ -160,7 +160,16 @@
 
     def __delitem__(&self, key: PyObject) -> PyResult<()> {
         // __delitem__ is both for `del idx[r]` and `del idx[r1:r2]`
-        self.cindex(py).borrow().inner().del_item(py, key)?;
+        self.cindex(py).borrow().inner().del_item(py, &key)?;
+        let start = key.getattr(py, "start")?;
+        let start = UncheckedRevision(start.extract(py)?);
+        let start = self.index(py)
+            .borrow()
+            .check_revision(start)
+            .ok_or_else(|| {
+                nodemap_error(py, NodeMapError::RevisionNotInIndex(start))
+            })?;
+        self.index(py).borrow_mut().remove(start).unwrap();
         let mut opt = self.get_nodetree(py)?.borrow_mut();
         let nt = opt.as_mut().unwrap();
         nt.invalidate_all();