equal
deleted
inserted
replaced
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() |