Mercurial > hg
comparison 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 |
comparison
equal
deleted
inserted
replaced
45600:b68b19104d16 | 45601:900b9b79b99c |
---|---|
1 use std::ops::Deref; | |
2 | |
1 use byteorder::{BigEndian, ByteOrder}; | 3 use byteorder::{BigEndian, ByteOrder}; |
2 | 4 |
3 use crate::revlog::{Revision, NULL_REVISION}; | 5 use crate::revlog::{Revision, NULL_REVISION}; |
4 | 6 |
5 pub const INDEX_ENTRY_SIZE: usize = 64; | 7 pub const INDEX_ENTRY_SIZE: usize = 64; |
6 | 8 |
7 /// A Revlog index | 9 /// A Revlog index |
8 #[derive(Debug)] | 10 pub struct Index { |
9 pub struct Index<'a> { | 11 bytes: Box<dyn Deref<Target = [u8]> + Send>, |
10 bytes: &'a [u8], | |
11 /// Offsets of starts of index blocks. | 12 /// Offsets of starts of index blocks. |
12 /// Only needed when the index is interleaved with data. | 13 /// Only needed when the index is interleaved with data. |
13 offsets: Option<Vec<usize>>, | 14 offsets: Option<Vec<usize>>, |
14 } | 15 } |
15 | 16 |
16 impl<'a> Index<'a> { | 17 impl Index { |
17 /// Create an index from bytes. | 18 /// Create an index from bytes. |
18 /// Calculate the start of each entry when is_inline is true. | 19 /// Calculate the start of each entry when is_inline is true. |
19 pub fn new(bytes: &'a [u8], is_inline: bool) -> Self { | 20 pub fn new(bytes: Box<dyn Deref<Target = [u8]> + Send>) -> Self { |
20 if is_inline { | 21 if is_inline(&bytes) { |
21 let mut offset: usize = 0; | 22 let mut offset: usize = 0; |
22 let mut offsets = Vec::new(); | 23 let mut offsets = Vec::new(); |
23 | 24 |
24 while offset + INDEX_ENTRY_SIZE <= bytes.len() { | 25 while offset + INDEX_ENTRY_SIZE <= bytes.len() { |
25 offsets.push(offset); | 26 offsets.push(offset); |
40 Self { | 41 Self { |
41 bytes, | 42 bytes, |
42 offsets: None, | 43 offsets: None, |
43 } | 44 } |
44 } | 45 } |
46 } | |
47 | |
48 /// Value of the inline flag. | |
49 pub fn is_inline(&self) -> bool { | |
50 is_inline(&self.bytes) | |
51 } | |
52 | |
53 /// Return a slice of bytes if `revlog` is inline. Panic if not. | |
54 pub fn data(&self, start: usize, end: usize) -> &[u8] { | |
55 if !self.is_inline() { | |
56 panic!("tried to access data in the index of a revlog that is not inline"); | |
57 } | |
58 &self.bytes[start..end] | |
45 } | 59 } |
46 | 60 |
47 /// Return number of entries of the revlog index. | 61 /// Return number of entries of the revlog index. |
48 pub fn len(&self) -> usize { | 62 pub fn len(&self) -> usize { |
49 if let Some(offsets) = &self.offsets { | 63 if let Some(offsets) = &self.offsets { |
167 /// | 181 /// |
168 /// Currently, SHA-1 is used and only the first 20 bytes of this field | 182 /// Currently, SHA-1 is used and only the first 20 bytes of this field |
169 /// are used. | 183 /// are used. |
170 pub fn hash(&self) -> &[u8] { | 184 pub fn hash(&self) -> &[u8] { |
171 &self.bytes[32..52] | 185 &self.bytes[32..52] |
186 } | |
187 } | |
188 | |
189 /// Value of the inline flag. | |
190 pub fn is_inline(index_bytes: &[u8]) -> bool { | |
191 match &index_bytes[0..=1] { | |
192 [0, 0] | [0, 2] => false, | |
193 _ => true, | |
172 } | 194 } |
173 } | 195 } |
174 | 196 |
175 #[cfg(test)] | 197 #[cfg(test)] |
176 mod tests { | 198 mod tests { |
267 bytes | 289 bytes |
268 } | 290 } |
269 } | 291 } |
270 | 292 |
271 #[test] | 293 #[test] |
294 fn is_not_inline_when_no_inline_flag_test() { | |
295 let bytes = IndexEntryBuilder::new() | |
296 .is_first(true) | |
297 .with_general_delta(false) | |
298 .with_inline(false) | |
299 .build(); | |
300 | |
301 assert_eq!(is_inline(&bytes), false) | |
302 } | |
303 | |
304 #[test] | |
305 fn is_inline_when_inline_flag_test() { | |
306 let bytes = IndexEntryBuilder::new() | |
307 .is_first(true) | |
308 .with_general_delta(false) | |
309 .with_inline(true) | |
310 .build(); | |
311 | |
312 assert_eq!(is_inline(&bytes), true) | |
313 } | |
314 | |
315 #[test] | |
316 fn is_inline_when_inline_and_generaldelta_flags_test() { | |
317 let bytes = IndexEntryBuilder::new() | |
318 .is_first(true) | |
319 .with_general_delta(true) | |
320 .with_inline(true) | |
321 .build(); | |
322 | |
323 assert_eq!(is_inline(&bytes), true) | |
324 } | |
325 | |
326 #[test] | |
272 fn test_offset() { | 327 fn test_offset() { |
273 let bytes = IndexEntryBuilder::new().with_offset(1).build(); | 328 let bytes = IndexEntryBuilder::new().with_offset(1).build(); |
274 let entry = IndexEntry { | 329 let entry = IndexEntry { |
275 bytes: &bytes, | 330 bytes: &bytes, |
276 offset_override: None, | 331 offset_override: None, |