diff rust/hg-core/src/revlog/index.rs @ 45601:900b9b79b99c

hg-core: make `Index` owner of its bytes (D8958#inline-14994 followup 1/2) Prevent building `Index` every time it is needed. It was a bad idea anyway. When `Index::new` will return `Result` it will avoid things like `Revlog::len` returning `Result<usize>` instead of `usize`. [X] make `Index` owner of its bytes [ ] make `Index::new` return an error if `offset != bytes.len()` Differential Revision: https://phab.mercurial-scm.org/D9106
author Antoine cezar<acezar@chwitlabs.fr>
date Mon, 28 Sep 2020 15:13:51 +0200
parents da30e4b553c3
children 1cef583541c0
line wrap: on
line diff
--- a/rust/hg-core/src/revlog/index.rs	Mon Sep 28 14:33:52 2020 +0200
+++ b/rust/hg-core/src/revlog/index.rs	Mon Sep 28 15:13:51 2020 +0200
@@ -1,3 +1,5 @@
+use std::ops::Deref;
+
 use byteorder::{BigEndian, ByteOrder};
 
 use crate::revlog::{Revision, NULL_REVISION};
@@ -5,19 +7,18 @@
 pub const INDEX_ENTRY_SIZE: usize = 64;
 
 /// A Revlog index
-#[derive(Debug)]
-pub struct Index<'a> {
-    bytes: &'a [u8],
+pub struct Index {
+    bytes: Box<dyn Deref<Target = [u8]> + Send>,
     /// Offsets of starts of index blocks.
     /// Only needed when the index is interleaved with data.
     offsets: Option<Vec<usize>>,
 }
 
-impl<'a> Index<'a> {
+impl Index {
     /// Create an index from bytes.
     /// Calculate the start of each entry when is_inline is true.
-    pub fn new(bytes: &'a [u8], is_inline: bool) -> Self {
-        if is_inline {
+    pub fn new(bytes: Box<dyn Deref<Target = [u8]> + Send>) -> Self {
+        if is_inline(&bytes) {
             let mut offset: usize = 0;
             let mut offsets = Vec::new();
 
@@ -44,6 +45,19 @@
         }
     }
 
+    /// Value of the inline flag.
+    pub fn is_inline(&self) -> bool {
+        is_inline(&self.bytes)
+    }
+
+    /// Return a slice of bytes if `revlog` is inline. Panic if not.
+    pub fn data(&self, start: usize, end: usize) -> &[u8] {
+        if !self.is_inline() {
+            panic!("tried to access data in the index of a revlog that is not inline");
+        }
+        &self.bytes[start..end]
+    }
+
     /// Return number of entries of the revlog index.
     pub fn len(&self) -> usize {
         if let Some(offsets) = &self.offsets {
@@ -172,6 +186,14 @@
     }
 }
 
+/// Value of the inline flag.
+pub fn is_inline(index_bytes: &[u8]) -> bool {
+    match &index_bytes[0..=1] {
+        [0, 0] | [0, 2] => false,
+        _ => true,
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -269,6 +291,39 @@
     }
 
     #[test]
+    fn is_not_inline_when_no_inline_flag_test() {
+        let bytes = IndexEntryBuilder::new()
+            .is_first(true)
+            .with_general_delta(false)
+            .with_inline(false)
+            .build();
+
+        assert_eq!(is_inline(&bytes), false)
+    }
+
+    #[test]
+    fn is_inline_when_inline_flag_test() {
+        let bytes = IndexEntryBuilder::new()
+            .is_first(true)
+            .with_general_delta(false)
+            .with_inline(true)
+            .build();
+
+        assert_eq!(is_inline(&bytes), true)
+    }
+
+    #[test]
+    fn is_inline_when_inline_and_generaldelta_flags_test() {
+        let bytes = IndexEntryBuilder::new()
+            .is_first(true)
+            .with_general_delta(true)
+            .with_inline(true)
+            .build();
+
+        assert_eq!(is_inline(&bytes), true)
+    }
+
+    #[test]
     fn test_offset() {
         let bytes = IndexEntryBuilder::new().with_offset(1).build();
         let entry = IndexEntry {