rust/hg-core/src/revlog/index.rs
changeset 48458 96ea4db4741b
parent 48457 1fb3615dfce2
child 48543 0a4ac916673e
equal deleted inserted replaced
48457:1fb3615dfce2 48458:96ea4db4741b
    82 pub struct Index {
    82 pub struct Index {
    83     bytes: Box<dyn Deref<Target = [u8]> + Send>,
    83     bytes: Box<dyn Deref<Target = [u8]> + Send>,
    84     /// Offsets of starts of index blocks.
    84     /// Offsets of starts of index blocks.
    85     /// Only needed when the index is interleaved with data.
    85     /// Only needed when the index is interleaved with data.
    86     offsets: Option<Vec<usize>>,
    86     offsets: Option<Vec<usize>>,
       
    87     uses_generaldelta: bool,
    87 }
    88 }
    88 
    89 
    89 impl Index {
    90 impl Index {
    90     /// Create an index from bytes.
    91     /// Create an index from bytes.
    91     /// Calculate the start of each entry when is_inline is true.
    92     /// Calculate the start of each entry when is_inline is true.
    98             // A proper new version should have had a repo/store
    99             // A proper new version should have had a repo/store
    99             // requirement.
   100             // requirement.
   100             return Err(HgError::corrupted("unsupported revlog version"));
   101             return Err(HgError::corrupted("unsupported revlog version"));
   101         }
   102         }
   102 
   103 
       
   104         // This is only correct because we know version is REVLOGV1.
       
   105         // In v2 we always use generaldelta, while in v0 we never use
       
   106         // generaldelta. Similar for [is_inline] (it's only used in v1).
       
   107         let uses_generaldelta = header.format_flags().uses_generaldelta();
       
   108 
   103         if header.format_flags().is_inline() {
   109         if header.format_flags().is_inline() {
   104             let mut offset: usize = 0;
   110             let mut offset: usize = 0;
   105             let mut offsets = Vec::new();
   111             let mut offsets = Vec::new();
   106 
   112 
   107             while offset + INDEX_ENTRY_SIZE <= bytes.len() {
   113             while offset + INDEX_ENTRY_SIZE <= bytes.len() {
   117 
   123 
   118             if offset == bytes.len() {
   124             if offset == bytes.len() {
   119                 Ok(Self {
   125                 Ok(Self {
   120                     bytes,
   126                     bytes,
   121                     offsets: Some(offsets),
   127                     offsets: Some(offsets),
       
   128                     uses_generaldelta,
   122                 })
   129                 })
   123             } else {
   130             } else {
   124                 Err(HgError::corrupted("unexpected inline revlog length")
   131                 Err(HgError::corrupted("unexpected inline revlog length")
   125                     .into())
   132                     .into())
   126             }
   133             }
   127         } else {
   134         } else {
   128             Ok(Self {
   135             Ok(Self {
   129                 bytes,
   136                 bytes,
   130                 offsets: None,
   137                 offsets: None,
       
   138                 uses_generaldelta,
   131             })
   139             })
   132         }
   140         }
       
   141     }
       
   142 
       
   143     pub fn uses_generaldelta(&self) -> bool {
       
   144         self.uses_generaldelta
   133     }
   145     }
   134 
   146 
   135     /// Value of the inline flag.
   147     /// Value of the inline flag.
   136     pub fn is_inline(&self) -> bool {
   148     pub fn is_inline(&self) -> bool {
   137         self.offsets.is_some()
   149         self.offsets.is_some()
   257     pub fn uncompressed_len(&self) -> usize {
   269     pub fn uncompressed_len(&self) -> usize {
   258         BigEndian::read_u32(&self.bytes[12..=15]) as usize
   270         BigEndian::read_u32(&self.bytes[12..=15]) as usize
   259     }
   271     }
   260 
   272 
   261     /// Return the revision upon which the data has been derived.
   273     /// Return the revision upon which the data has been derived.
   262     pub fn base_revision(&self) -> Revision {
   274     pub fn base_revision_or_base_of_delta_chain(&self) -> Revision {
   263         // TODO Maybe return an Option when base_revision == rev?
   275         // TODO Maybe return an Option when base_revision == rev?
   264         //      Requires to add rev to IndexEntry
   276         //      Requires to add rev to IndexEntry
   265 
   277 
   266         BigEndian::read_i32(&self.bytes[16..])
   278         BigEndian::read_i32(&self.bytes[16..])
   267     }
   279     }
   295         is_general_delta: bool,
   307         is_general_delta: bool,
   296         version: u16,
   308         version: u16,
   297         offset: usize,
   309         offset: usize,
   298         compressed_len: usize,
   310         compressed_len: usize,
   299         uncompressed_len: usize,
   311         uncompressed_len: usize,
   300         base_revision: Revision,
   312         base_revision_or_base_of_delta_chain: Revision,
   301     }
   313     }
   302 
   314 
   303     #[cfg(test)]
   315     #[cfg(test)]
   304     impl IndexEntryBuilder {
   316     impl IndexEntryBuilder {
   305         pub fn new() -> Self {
   317         pub fn new() -> Self {
   309                 is_general_delta: true,
   321                 is_general_delta: true,
   310                 version: 2,
   322                 version: 2,
   311                 offset: 0,
   323                 offset: 0,
   312                 compressed_len: 0,
   324                 compressed_len: 0,
   313                 uncompressed_len: 0,
   325                 uncompressed_len: 0,
   314                 base_revision: 0,
   326                 base_revision_or_base_of_delta_chain: 0,
   315             }
   327             }
   316         }
   328         }
   317 
   329 
   318         pub fn is_first(&mut self, value: bool) -> &mut Self {
   330         pub fn is_first(&mut self, value: bool) -> &mut Self {
   319             self.is_first = value;
   331             self.is_first = value;
   348         pub fn with_uncompressed_len(&mut self, value: usize) -> &mut Self {
   360         pub fn with_uncompressed_len(&mut self, value: usize) -> &mut Self {
   349             self.uncompressed_len = value;
   361             self.uncompressed_len = value;
   350             self
   362             self
   351         }
   363         }
   352 
   364 
   353         pub fn with_base_revision(&mut self, value: Revision) -> &mut Self {
   365         pub fn with_base_revision_or_base_of_delta_chain(
   354             self.base_revision = value;
   366             &mut self,
       
   367             value: Revision,
       
   368         ) -> &mut Self {
       
   369             self.base_revision_or_base_of_delta_chain = value;
   355             self
   370             self
   356         }
   371         }
   357 
   372 
   358         pub fn build(&self) -> Vec<u8> {
   373         pub fn build(&self) -> Vec<u8> {
   359             let mut bytes = Vec::with_capacity(INDEX_ENTRY_SIZE);
   374             let mut bytes = Vec::with_capacity(INDEX_ENTRY_SIZE);
   372                 bytes.extend(&(self.offset as u64).to_be_bytes()[2..]);
   387                 bytes.extend(&(self.offset as u64).to_be_bytes()[2..]);
   373             }
   388             }
   374             bytes.extend(&[0u8; 2]); // Revision flags.
   389             bytes.extend(&[0u8; 2]); // Revision flags.
   375             bytes.extend(&(self.compressed_len as u32).to_be_bytes());
   390             bytes.extend(&(self.compressed_len as u32).to_be_bytes());
   376             bytes.extend(&(self.uncompressed_len as u32).to_be_bytes());
   391             bytes.extend(&(self.uncompressed_len as u32).to_be_bytes());
   377             bytes.extend(&self.base_revision.to_be_bytes());
   392             bytes.extend(
       
   393                 &self.base_revision_or_base_of_delta_chain.to_be_bytes(),
       
   394             );
   378             bytes
   395             bytes
   379         }
   396         }
   380     }
   397     }
   381 
   398 
   382     pub fn is_inline(index_bytes: &[u8]) -> bool {
   399     pub fn is_inline(index_bytes: &[u8]) -> bool {
   478 
   495 
   479         assert_eq!(entry.uncompressed_len(), 1)
   496         assert_eq!(entry.uncompressed_len(), 1)
   480     }
   497     }
   481 
   498 
   482     #[test]
   499     #[test]
   483     fn test_base_revision() {
   500     fn test_base_revision_or_base_of_delta_chain() {
   484         let bytes = IndexEntryBuilder::new().with_base_revision(1).build();
   501         let bytes = IndexEntryBuilder::new()
       
   502             .with_base_revision_or_base_of_delta_chain(1)
       
   503             .build();
   485         let entry = IndexEntry {
   504         let entry = IndexEntry {
   486             bytes: &bytes,
   505             bytes: &bytes,
   487             offset_override: None,
   506             offset_override: None,
   488         };
   507         };
   489 
   508 
   490         assert_eq!(entry.base_revision(), 1)
   509         assert_eq!(entry.base_revision_or_base_of_delta_chain(), 1)
   491     }
   510     }
   492 
   511 
   493     #[test]
   512     #[test]
   494     fn version_test() {
   513     fn version_test() {
   495         let bytes = IndexEntryBuilder::new()
   514         let bytes = IndexEntryBuilder::new()