##// END OF EJS Templates
rust-index: add an abstraction to support bytes added at runtimes...
Raphaël Gomès -
r52081:1ef4a36a default
parent child Browse files
Show More
@@ -1,641 +1,682 b''
1 use std::fmt::Debug;
1 use std::fmt::Debug;
2 use std::ops::Deref;
2 use std::ops::Deref;
3
3
4 use byteorder::{BigEndian, ByteOrder};
4 use byteorder::{BigEndian, ByteOrder};
5
5
6 use crate::errors::HgError;
6 use crate::errors::HgError;
7 use crate::revlog::node::Node;
7 use crate::revlog::node::Node;
8 use crate::revlog::{Revision, NULL_REVISION};
8 use crate::revlog::{Revision, NULL_REVISION};
9 use crate::{Graph, GraphError, RevlogIndex, UncheckedRevision};
9 use crate::{Graph, GraphError, RevlogIndex, UncheckedRevision};
10
10
11 pub const INDEX_ENTRY_SIZE: usize = 64;
11 pub const INDEX_ENTRY_SIZE: usize = 64;
12
12
13 pub struct IndexHeader {
13 pub struct IndexHeader {
14 header_bytes: [u8; 4],
14 header_bytes: [u8; 4],
15 }
15 }
16
16
17 #[derive(Copy, Clone)]
17 #[derive(Copy, Clone)]
18 pub struct IndexHeaderFlags {
18 pub struct IndexHeaderFlags {
19 flags: u16,
19 flags: u16,
20 }
20 }
21
21
22 /// Corresponds to the high bits of `_format_flags` in python
22 /// Corresponds to the high bits of `_format_flags` in python
23 impl IndexHeaderFlags {
23 impl IndexHeaderFlags {
24 /// Corresponds to FLAG_INLINE_DATA in python
24 /// Corresponds to FLAG_INLINE_DATA in python
25 pub fn is_inline(self) -> bool {
25 pub fn is_inline(self) -> bool {
26 self.flags & 1 != 0
26 self.flags & 1 != 0
27 }
27 }
28 /// Corresponds to FLAG_GENERALDELTA in python
28 /// Corresponds to FLAG_GENERALDELTA in python
29 pub fn uses_generaldelta(self) -> bool {
29 pub fn uses_generaldelta(self) -> bool {
30 self.flags & 2 != 0
30 self.flags & 2 != 0
31 }
31 }
32 }
32 }
33
33
34 /// Corresponds to the INDEX_HEADER structure,
34 /// Corresponds to the INDEX_HEADER structure,
35 /// which is parsed as a `header` variable in `_loadindex` in `revlog.py`
35 /// which is parsed as a `header` variable in `_loadindex` in `revlog.py`
36 impl IndexHeader {
36 impl IndexHeader {
37 fn format_flags(&self) -> IndexHeaderFlags {
37 fn format_flags(&self) -> IndexHeaderFlags {
38 // No "unknown flags" check here, unlike in python. Maybe there should
38 // No "unknown flags" check here, unlike in python. Maybe there should
39 // be.
39 // be.
40 IndexHeaderFlags {
40 IndexHeaderFlags {
41 flags: BigEndian::read_u16(&self.header_bytes[0..2]),
41 flags: BigEndian::read_u16(&self.header_bytes[0..2]),
42 }
42 }
43 }
43 }
44
44
45 /// The only revlog version currently supported by rhg.
45 /// The only revlog version currently supported by rhg.
46 const REVLOGV1: u16 = 1;
46 const REVLOGV1: u16 = 1;
47
47
48 /// Corresponds to `_format_version` in Python.
48 /// Corresponds to `_format_version` in Python.
49 fn format_version(&self) -> u16 {
49 fn format_version(&self) -> u16 {
50 BigEndian::read_u16(&self.header_bytes[2..4])
50 BigEndian::read_u16(&self.header_bytes[2..4])
51 }
51 }
52
52
53 const EMPTY_INDEX_HEADER: IndexHeader = IndexHeader {
53 const EMPTY_INDEX_HEADER: IndexHeader = IndexHeader {
54 // We treat an empty file as a valid index with no entries.
54 // We treat an empty file as a valid index with no entries.
55 // Here we make an arbitrary choice of what we assume the format of the
55 // Here we make an arbitrary choice of what we assume the format of the
56 // index to be (V1, using generaldelta).
56 // index to be (V1, using generaldelta).
57 // This doesn't matter too much, since we're only doing read-only
57 // This doesn't matter too much, since we're only doing read-only
58 // access. but the value corresponds to the `new_header` variable in
58 // access. but the value corresponds to the `new_header` variable in
59 // `revlog.py`, `_loadindex`
59 // `revlog.py`, `_loadindex`
60 header_bytes: [0, 3, 0, 1],
60 header_bytes: [0, 3, 0, 1],
61 };
61 };
62
62
63 fn parse(index_bytes: &[u8]) -> Result<IndexHeader, HgError> {
63 fn parse(index_bytes: &[u8]) -> Result<IndexHeader, HgError> {
64 if index_bytes.is_empty() {
64 if index_bytes.is_empty() {
65 return Ok(IndexHeader::EMPTY_INDEX_HEADER);
65 return Ok(IndexHeader::EMPTY_INDEX_HEADER);
66 }
66 }
67 if index_bytes.len() < 4 {
67 if index_bytes.len() < 4 {
68 return Err(HgError::corrupted(
68 return Err(HgError::corrupted(
69 "corrupted revlog: can't read the index format header",
69 "corrupted revlog: can't read the index format header",
70 ));
70 ));
71 }
71 }
72 Ok(IndexHeader {
72 Ok(IndexHeader {
73 header_bytes: {
73 header_bytes: {
74 let bytes: [u8; 4] =
74 let bytes: [u8; 4] =
75 index_bytes[0..4].try_into().expect("impossible");
75 index_bytes[0..4].try_into().expect("impossible");
76 bytes
76 bytes
77 },
77 },
78 })
78 })
79 }
79 }
80 }
80 }
81
81
82 /// Abstracts the access to the index bytes since they can be spread between
83 /// the immutable (bytes) part and the mutable (added) part if any appends
84 /// happened. This makes it transparent for the callers.
85 struct IndexData {
86 /// Immutable bytes, most likely taken from disk
87 bytes: Box<dyn Deref<Target = [u8]> + Send>,
88 /// Bytes that were added after reading the index
89 added: Vec<u8>,
90 }
91
92 impl IndexData {
93 pub fn new(bytes: Box<dyn Deref<Target = [u8]> + Send>) -> Self {
94 Self {
95 bytes,
96 added: vec![],
97 }
98 }
99
100 pub fn len(&self) -> usize {
101 self.bytes.len() + self.added.len()
102 }
103 }
104
105 impl std::ops::Index<std::ops::Range<usize>> for IndexData {
106 type Output = [u8];
107
108 fn index(&self, index: std::ops::Range<usize>) -> &Self::Output {
109 let start = index.start;
110 let end = index.end;
111 let immutable_len = self.bytes.len();
112 if start < immutable_len {
113 if end > immutable_len {
114 panic!("index data cannot span existing and added ranges");
115 }
116 &self.bytes[index]
117 } else {
118 &self.added[start - immutable_len..end - immutable_len]
119 }
120 }
121 }
122
82 /// A Revlog index
123 /// A Revlog index
83 pub struct Index {
124 pub struct Index {
84 bytes: Box<dyn Deref<Target = [u8]> + Send>,
125 bytes: IndexData,
85 /// Offsets of starts of index blocks.
126 /// Offsets of starts of index blocks.
86 /// Only needed when the index is interleaved with data.
127 /// Only needed when the index is interleaved with data.
87 offsets: Option<Vec<usize>>,
128 offsets: Option<Vec<usize>>,
88 uses_generaldelta: bool,
129 uses_generaldelta: bool,
89 }
130 }
90
131
91 impl Debug for Index {
132 impl Debug for Index {
92 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
133 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93 f.debug_struct("Index")
134 f.debug_struct("Index")
94 .field("offsets", &self.offsets)
135 .field("offsets", &self.offsets)
95 .field("uses_generaldelta", &self.uses_generaldelta)
136 .field("uses_generaldelta", &self.uses_generaldelta)
96 .finish()
137 .finish()
97 }
138 }
98 }
139 }
99
140
100 impl Graph for Index {
141 impl Graph for Index {
101 fn parents(&self, rev: Revision) -> Result<[Revision; 2], GraphError> {
142 fn parents(&self, rev: Revision) -> Result<[Revision; 2], GraphError> {
102 let err = || GraphError::ParentOutOfRange(rev);
143 let err = || GraphError::ParentOutOfRange(rev);
103 match self.get_entry(rev) {
144 match self.get_entry(rev) {
104 Some(entry) => {
145 Some(entry) => {
105 // The C implementation checks that the parents are valid
146 // The C implementation checks that the parents are valid
106 // before returning
147 // before returning
107 Ok([
148 Ok([
108 self.check_revision(entry.p1()).ok_or_else(err)?,
149 self.check_revision(entry.p1()).ok_or_else(err)?,
109 self.check_revision(entry.p2()).ok_or_else(err)?,
150 self.check_revision(entry.p2()).ok_or_else(err)?,
110 ])
151 ])
111 }
152 }
112 None => Ok([NULL_REVISION, NULL_REVISION]),
153 None => Ok([NULL_REVISION, NULL_REVISION]),
113 }
154 }
114 }
155 }
115 }
156 }
116
157
117 impl Index {
158 impl Index {
118 /// Create an index from bytes.
159 /// Create an index from bytes.
119 /// Calculate the start of each entry when is_inline is true.
160 /// Calculate the start of each entry when is_inline is true.
120 pub fn new(
161 pub fn new(
121 bytes: Box<dyn Deref<Target = [u8]> + Send>,
162 bytes: Box<dyn Deref<Target = [u8]> + Send>,
122 ) -> Result<Self, HgError> {
163 ) -> Result<Self, HgError> {
123 let header = IndexHeader::parse(bytes.as_ref())?;
164 let header = IndexHeader::parse(bytes.as_ref())?;
124
165
125 if header.format_version() != IndexHeader::REVLOGV1 {
166 if header.format_version() != IndexHeader::REVLOGV1 {
126 // A proper new version should have had a repo/store
167 // A proper new version should have had a repo/store
127 // requirement.
168 // requirement.
128 return Err(HgError::corrupted("unsupported revlog version"));
169 return Err(HgError::corrupted("unsupported revlog version"));
129 }
170 }
130
171
131 // This is only correct because we know version is REVLOGV1.
172 // This is only correct because we know version is REVLOGV1.
132 // In v2 we always use generaldelta, while in v0 we never use
173 // In v2 we always use generaldelta, while in v0 we never use
133 // generaldelta. Similar for [is_inline] (it's only used in v1).
174 // generaldelta. Similar for [is_inline] (it's only used in v1).
134 let uses_generaldelta = header.format_flags().uses_generaldelta();
175 let uses_generaldelta = header.format_flags().uses_generaldelta();
135
176
136 if header.format_flags().is_inline() {
177 if header.format_flags().is_inline() {
137 let mut offset: usize = 0;
178 let mut offset: usize = 0;
138 let mut offsets = Vec::new();
179 let mut offsets = Vec::new();
139
180
140 while offset + INDEX_ENTRY_SIZE <= bytes.len() {
181 while offset + INDEX_ENTRY_SIZE <= bytes.len() {
141 offsets.push(offset);
182 offsets.push(offset);
142 let end = offset + INDEX_ENTRY_SIZE;
183 let end = offset + INDEX_ENTRY_SIZE;
143 let entry = IndexEntry {
184 let entry = IndexEntry {
144 bytes: &bytes[offset..end],
185 bytes: &bytes[offset..end],
145 offset_override: None,
186 offset_override: None,
146 };
187 };
147
188
148 offset += INDEX_ENTRY_SIZE + entry.compressed_len() as usize;
189 offset += INDEX_ENTRY_SIZE + entry.compressed_len() as usize;
149 }
190 }
150
191
151 if offset == bytes.len() {
192 if offset == bytes.len() {
152 Ok(Self {
193 Ok(Self {
153 bytes,
194 bytes: IndexData::new(bytes),
154 offsets: Some(offsets),
195 offsets: Some(offsets),
155 uses_generaldelta,
196 uses_generaldelta,
156 })
197 })
157 } else {
198 } else {
158 Err(HgError::corrupted("unexpected inline revlog length"))
199 Err(HgError::corrupted("unexpected inline revlog length"))
159 }
200 }
160 } else {
201 } else {
161 Ok(Self {
202 Ok(Self {
162 bytes,
203 bytes: IndexData::new(bytes),
163 offsets: None,
204 offsets: None,
164 uses_generaldelta,
205 uses_generaldelta,
165 })
206 })
166 }
207 }
167 }
208 }
168
209
169 pub fn uses_generaldelta(&self) -> bool {
210 pub fn uses_generaldelta(&self) -> bool {
170 self.uses_generaldelta
211 self.uses_generaldelta
171 }
212 }
172
213
173 /// Value of the inline flag.
214 /// Value of the inline flag.
174 pub fn is_inline(&self) -> bool {
215 pub fn is_inline(&self) -> bool {
175 self.offsets.is_some()
216 self.offsets.is_some()
176 }
217 }
177
218
178 /// Return a slice of bytes if `revlog` is inline. Panic if not.
219 /// Return a slice of bytes if `revlog` is inline. Panic if not.
179 pub fn data(&self, start: usize, end: usize) -> &[u8] {
220 pub fn data(&self, start: usize, end: usize) -> &[u8] {
180 if !self.is_inline() {
221 if !self.is_inline() {
181 panic!("tried to access data in the index of a revlog that is not inline");
222 panic!("tried to access data in the index of a revlog that is not inline");
182 }
223 }
183 &self.bytes[start..end]
224 &self.bytes[start..end]
184 }
225 }
185
226
186 /// Return number of entries of the revlog index.
227 /// Return number of entries of the revlog index.
187 pub fn len(&self) -> usize {
228 pub fn len(&self) -> usize {
188 if let Some(offsets) = &self.offsets {
229 if let Some(offsets) = &self.offsets {
189 offsets.len()
230 offsets.len()
190 } else {
231 } else {
191 self.bytes.len() / INDEX_ENTRY_SIZE
232 self.bytes.len() / INDEX_ENTRY_SIZE
192 }
233 }
193 }
234 }
194
235
195 /// Returns `true` if the `Index` has zero `entries`.
236 /// Returns `true` if the `Index` has zero `entries`.
196 pub fn is_empty(&self) -> bool {
237 pub fn is_empty(&self) -> bool {
197 self.len() == 0
238 self.len() == 0
198 }
239 }
199
240
200 /// Return the index entry corresponding to the given revision if it
241 /// Return the index entry corresponding to the given revision if it
201 /// exists.
242 /// exists.
202 pub fn get_entry(&self, rev: Revision) -> Option<IndexEntry> {
243 pub fn get_entry(&self, rev: Revision) -> Option<IndexEntry> {
203 if rev == NULL_REVISION {
244 if rev == NULL_REVISION {
204 return None;
245 return None;
205 }
246 }
206 Some(if let Some(offsets) = &self.offsets {
247 Some(if let Some(offsets) = &self.offsets {
207 self.get_entry_inline(rev, offsets)
248 self.get_entry_inline(rev, offsets)
208 } else {
249 } else {
209 self.get_entry_separated(rev)
250 self.get_entry_separated(rev)
210 })
251 })
211 }
252 }
212
253
213 fn get_entry_inline(
254 fn get_entry_inline(
214 &self,
255 &self,
215 rev: Revision,
256 rev: Revision,
216 offsets: &[usize],
257 offsets: &[usize],
217 ) -> IndexEntry {
258 ) -> IndexEntry {
218 let start = offsets[rev.0 as usize];
259 let start = offsets[rev.0 as usize];
219 let end = start + INDEX_ENTRY_SIZE;
260 let end = start + INDEX_ENTRY_SIZE;
220 let bytes = &self.bytes[start..end];
261 let bytes = &self.bytes[start..end];
221
262
222 // See IndexEntry for an explanation of this override.
263 // See IndexEntry for an explanation of this override.
223 let offset_override = Some(end);
264 let offset_override = Some(end);
224
265
225 IndexEntry {
266 IndexEntry {
226 bytes,
267 bytes,
227 offset_override,
268 offset_override,
228 }
269 }
229 }
270 }
230
271
231 fn get_entry_separated(&self, rev: Revision) -> IndexEntry {
272 fn get_entry_separated(&self, rev: Revision) -> IndexEntry {
232 let start = rev.0 as usize * INDEX_ENTRY_SIZE;
273 let start = rev.0 as usize * INDEX_ENTRY_SIZE;
233 let end = start + INDEX_ENTRY_SIZE;
274 let end = start + INDEX_ENTRY_SIZE;
234 let bytes = &self.bytes[start..end];
275 let bytes = &self.bytes[start..end];
235
276
236 // Override the offset of the first revision as its bytes are used
277 // Override the offset of the first revision as its bytes are used
237 // for the index's metadata (saving space because it is always 0)
278 // for the index's metadata (saving space because it is always 0)
238 let offset_override = if rev == Revision(0) { Some(0) } else { None };
279 let offset_override = if rev == Revision(0) { Some(0) } else { None };
239
280
240 IndexEntry {
281 IndexEntry {
241 bytes,
282 bytes,
242 offset_override,
283 offset_override,
243 }
284 }
244 }
285 }
245 }
286 }
246
287
247 impl super::RevlogIndex for Index {
288 impl super::RevlogIndex for Index {
248 fn len(&self) -> usize {
289 fn len(&self) -> usize {
249 self.len()
290 self.len()
250 }
291 }
251
292
252 fn node(&self, rev: Revision) -> Option<&Node> {
293 fn node(&self, rev: Revision) -> Option<&Node> {
253 self.get_entry(rev).map(|entry| entry.hash())
294 self.get_entry(rev).map(|entry| entry.hash())
254 }
295 }
255 }
296 }
256
297
257 #[derive(Debug)]
298 #[derive(Debug)]
258 pub struct IndexEntry<'a> {
299 pub struct IndexEntry<'a> {
259 bytes: &'a [u8],
300 bytes: &'a [u8],
260 /// Allows to override the offset value of the entry.
301 /// Allows to override the offset value of the entry.
261 ///
302 ///
262 /// For interleaved index and data, the offset stored in the index
303 /// For interleaved index and data, the offset stored in the index
263 /// corresponds to the separated data offset.
304 /// corresponds to the separated data offset.
264 /// It has to be overridden with the actual offset in the interleaved
305 /// It has to be overridden with the actual offset in the interleaved
265 /// index which is just after the index block.
306 /// index which is just after the index block.
266 ///
307 ///
267 /// For separated index and data, the offset stored in the first index
308 /// For separated index and data, the offset stored in the first index
268 /// entry is mixed with the index headers.
309 /// entry is mixed with the index headers.
269 /// It has to be overridden with 0.
310 /// It has to be overridden with 0.
270 offset_override: Option<usize>,
311 offset_override: Option<usize>,
271 }
312 }
272
313
273 impl<'a> IndexEntry<'a> {
314 impl<'a> IndexEntry<'a> {
274 /// Return the offset of the data.
315 /// Return the offset of the data.
275 pub fn offset(&self) -> usize {
316 pub fn offset(&self) -> usize {
276 if let Some(offset_override) = self.offset_override {
317 if let Some(offset_override) = self.offset_override {
277 offset_override
318 offset_override
278 } else {
319 } else {
279 let mut bytes = [0; 8];
320 let mut bytes = [0; 8];
280 bytes[2..8].copy_from_slice(&self.bytes[0..=5]);
321 bytes[2..8].copy_from_slice(&self.bytes[0..=5]);
281 BigEndian::read_u64(&bytes[..]) as usize
322 BigEndian::read_u64(&bytes[..]) as usize
282 }
323 }
283 }
324 }
284
325
285 pub fn flags(&self) -> u16 {
326 pub fn flags(&self) -> u16 {
286 BigEndian::read_u16(&self.bytes[6..=7])
327 BigEndian::read_u16(&self.bytes[6..=7])
287 }
328 }
288
329
289 /// Return the compressed length of the data.
330 /// Return the compressed length of the data.
290 pub fn compressed_len(&self) -> u32 {
331 pub fn compressed_len(&self) -> u32 {
291 BigEndian::read_u32(&self.bytes[8..=11])
332 BigEndian::read_u32(&self.bytes[8..=11])
292 }
333 }
293
334
294 /// Return the uncompressed length of the data.
335 /// Return the uncompressed length of the data.
295 pub fn uncompressed_len(&self) -> i32 {
336 pub fn uncompressed_len(&self) -> i32 {
296 BigEndian::read_i32(&self.bytes[12..=15])
337 BigEndian::read_i32(&self.bytes[12..=15])
297 }
338 }
298
339
299 /// Return the revision upon which the data has been derived.
340 /// Return the revision upon which the data has been derived.
300 pub fn base_revision_or_base_of_delta_chain(&self) -> UncheckedRevision {
341 pub fn base_revision_or_base_of_delta_chain(&self) -> UncheckedRevision {
301 // TODO Maybe return an Option when base_revision == rev?
342 // TODO Maybe return an Option when base_revision == rev?
302 // Requires to add rev to IndexEntry
343 // Requires to add rev to IndexEntry
303
344
304 BigEndian::read_i32(&self.bytes[16..]).into()
345 BigEndian::read_i32(&self.bytes[16..]).into()
305 }
346 }
306
347
307 pub fn link_revision(&self) -> UncheckedRevision {
348 pub fn link_revision(&self) -> UncheckedRevision {
308 BigEndian::read_i32(&self.bytes[20..]).into()
349 BigEndian::read_i32(&self.bytes[20..]).into()
309 }
350 }
310
351
311 pub fn p1(&self) -> UncheckedRevision {
352 pub fn p1(&self) -> UncheckedRevision {
312 BigEndian::read_i32(&self.bytes[24..]).into()
353 BigEndian::read_i32(&self.bytes[24..]).into()
313 }
354 }
314
355
315 pub fn p2(&self) -> UncheckedRevision {
356 pub fn p2(&self) -> UncheckedRevision {
316 BigEndian::read_i32(&self.bytes[28..]).into()
357 BigEndian::read_i32(&self.bytes[28..]).into()
317 }
358 }
318
359
319 /// Return the hash of revision's full text.
360 /// Return the hash of revision's full text.
320 ///
361 ///
321 /// Currently, SHA-1 is used and only the first 20 bytes of this field
362 /// Currently, SHA-1 is used and only the first 20 bytes of this field
322 /// are used.
363 /// are used.
323 pub fn hash(&self) -> &'a Node {
364 pub fn hash(&self) -> &'a Node {
324 (&self.bytes[32..52]).try_into().unwrap()
365 (&self.bytes[32..52]).try_into().unwrap()
325 }
366 }
326 }
367 }
327
368
328 #[cfg(test)]
369 #[cfg(test)]
329 mod tests {
370 mod tests {
330 use super::*;
371 use super::*;
331 use crate::node::NULL_NODE;
372 use crate::node::NULL_NODE;
332
373
333 #[cfg(test)]
374 #[cfg(test)]
334 #[derive(Debug, Copy, Clone)]
375 #[derive(Debug, Copy, Clone)]
335 pub struct IndexEntryBuilder {
376 pub struct IndexEntryBuilder {
336 is_first: bool,
377 is_first: bool,
337 is_inline: bool,
378 is_inline: bool,
338 is_general_delta: bool,
379 is_general_delta: bool,
339 version: u16,
380 version: u16,
340 offset: usize,
381 offset: usize,
341 compressed_len: usize,
382 compressed_len: usize,
342 uncompressed_len: usize,
383 uncompressed_len: usize,
343 base_revision_or_base_of_delta_chain: Revision,
384 base_revision_or_base_of_delta_chain: Revision,
344 link_revision: Revision,
385 link_revision: Revision,
345 p1: Revision,
386 p1: Revision,
346 p2: Revision,
387 p2: Revision,
347 node: Node,
388 node: Node,
348 }
389 }
349
390
350 #[cfg(test)]
391 #[cfg(test)]
351 impl IndexEntryBuilder {
392 impl IndexEntryBuilder {
352 #[allow(clippy::new_without_default)]
393 #[allow(clippy::new_without_default)]
353 pub fn new() -> Self {
394 pub fn new() -> Self {
354 Self {
395 Self {
355 is_first: false,
396 is_first: false,
356 is_inline: false,
397 is_inline: false,
357 is_general_delta: true,
398 is_general_delta: true,
358 version: 1,
399 version: 1,
359 offset: 0,
400 offset: 0,
360 compressed_len: 0,
401 compressed_len: 0,
361 uncompressed_len: 0,
402 uncompressed_len: 0,
362 base_revision_or_base_of_delta_chain: Revision(0),
403 base_revision_or_base_of_delta_chain: Revision(0),
363 link_revision: Revision(0),
404 link_revision: Revision(0),
364 p1: NULL_REVISION,
405 p1: NULL_REVISION,
365 p2: NULL_REVISION,
406 p2: NULL_REVISION,
366 node: NULL_NODE,
407 node: NULL_NODE,
367 }
408 }
368 }
409 }
369
410
370 pub fn is_first(&mut self, value: bool) -> &mut Self {
411 pub fn is_first(&mut self, value: bool) -> &mut Self {
371 self.is_first = value;
412 self.is_first = value;
372 self
413 self
373 }
414 }
374
415
375 pub fn with_inline(&mut self, value: bool) -> &mut Self {
416 pub fn with_inline(&mut self, value: bool) -> &mut Self {
376 self.is_inline = value;
417 self.is_inline = value;
377 self
418 self
378 }
419 }
379
420
380 pub fn with_general_delta(&mut self, value: bool) -> &mut Self {
421 pub fn with_general_delta(&mut self, value: bool) -> &mut Self {
381 self.is_general_delta = value;
422 self.is_general_delta = value;
382 self
423 self
383 }
424 }
384
425
385 pub fn with_version(&mut self, value: u16) -> &mut Self {
426 pub fn with_version(&mut self, value: u16) -> &mut Self {
386 self.version = value;
427 self.version = value;
387 self
428 self
388 }
429 }
389
430
390 pub fn with_offset(&mut self, value: usize) -> &mut Self {
431 pub fn with_offset(&mut self, value: usize) -> &mut Self {
391 self.offset = value;
432 self.offset = value;
392 self
433 self
393 }
434 }
394
435
395 pub fn with_compressed_len(&mut self, value: usize) -> &mut Self {
436 pub fn with_compressed_len(&mut self, value: usize) -> &mut Self {
396 self.compressed_len = value;
437 self.compressed_len = value;
397 self
438 self
398 }
439 }
399
440
400 pub fn with_uncompressed_len(&mut self, value: usize) -> &mut Self {
441 pub fn with_uncompressed_len(&mut self, value: usize) -> &mut Self {
401 self.uncompressed_len = value;
442 self.uncompressed_len = value;
402 self
443 self
403 }
444 }
404
445
405 pub fn with_base_revision_or_base_of_delta_chain(
446 pub fn with_base_revision_or_base_of_delta_chain(
406 &mut self,
447 &mut self,
407 value: Revision,
448 value: Revision,
408 ) -> &mut Self {
449 ) -> &mut Self {
409 self.base_revision_or_base_of_delta_chain = value;
450 self.base_revision_or_base_of_delta_chain = value;
410 self
451 self
411 }
452 }
412
453
413 pub fn with_link_revision(&mut self, value: Revision) -> &mut Self {
454 pub fn with_link_revision(&mut self, value: Revision) -> &mut Self {
414 self.link_revision = value;
455 self.link_revision = value;
415 self
456 self
416 }
457 }
417
458
418 pub fn with_p1(&mut self, value: Revision) -> &mut Self {
459 pub fn with_p1(&mut self, value: Revision) -> &mut Self {
419 self.p1 = value;
460 self.p1 = value;
420 self
461 self
421 }
462 }
422
463
423 pub fn with_p2(&mut self, value: Revision) -> &mut Self {
464 pub fn with_p2(&mut self, value: Revision) -> &mut Self {
424 self.p2 = value;
465 self.p2 = value;
425 self
466 self
426 }
467 }
427
468
428 pub fn with_node(&mut self, value: Node) -> &mut Self {
469 pub fn with_node(&mut self, value: Node) -> &mut Self {
429 self.node = value;
470 self.node = value;
430 self
471 self
431 }
472 }
432
473
433 pub fn build(&self) -> Vec<u8> {
474 pub fn build(&self) -> Vec<u8> {
434 let mut bytes = Vec::with_capacity(INDEX_ENTRY_SIZE);
475 let mut bytes = Vec::with_capacity(INDEX_ENTRY_SIZE);
435 if self.is_first {
476 if self.is_first {
436 bytes.extend(&match (self.is_general_delta, self.is_inline) {
477 bytes.extend(&match (self.is_general_delta, self.is_inline) {
437 (false, false) => [0u8, 0],
478 (false, false) => [0u8, 0],
438 (false, true) => [0u8, 1],
479 (false, true) => [0u8, 1],
439 (true, false) => [0u8, 2],
480 (true, false) => [0u8, 2],
440 (true, true) => [0u8, 3],
481 (true, true) => [0u8, 3],
441 });
482 });
442 bytes.extend(&self.version.to_be_bytes());
483 bytes.extend(&self.version.to_be_bytes());
443 // Remaining offset bytes.
484 // Remaining offset bytes.
444 bytes.extend(&[0u8; 2]);
485 bytes.extend(&[0u8; 2]);
445 } else {
486 } else {
446 // Offset stored on 48 bits (6 bytes)
487 // Offset stored on 48 bits (6 bytes)
447 bytes.extend(&(self.offset as u64).to_be_bytes()[2..]);
488 bytes.extend(&(self.offset as u64).to_be_bytes()[2..]);
448 }
489 }
449 bytes.extend(&[0u8; 2]); // Revision flags.
490 bytes.extend(&[0u8; 2]); // Revision flags.
450 bytes.extend(&(self.compressed_len as u32).to_be_bytes());
491 bytes.extend(&(self.compressed_len as u32).to_be_bytes());
451 bytes.extend(&(self.uncompressed_len as u32).to_be_bytes());
492 bytes.extend(&(self.uncompressed_len as u32).to_be_bytes());
452 bytes.extend(
493 bytes.extend(
453 &self.base_revision_or_base_of_delta_chain.0.to_be_bytes(),
494 &self.base_revision_or_base_of_delta_chain.0.to_be_bytes(),
454 );
495 );
455 bytes.extend(&self.link_revision.0.to_be_bytes());
496 bytes.extend(&self.link_revision.0.to_be_bytes());
456 bytes.extend(&self.p1.0.to_be_bytes());
497 bytes.extend(&self.p1.0.to_be_bytes());
457 bytes.extend(&self.p2.0.to_be_bytes());
498 bytes.extend(&self.p2.0.to_be_bytes());
458 bytes.extend(self.node.as_bytes());
499 bytes.extend(self.node.as_bytes());
459 bytes.extend(vec![0u8; 12]);
500 bytes.extend(vec![0u8; 12]);
460 bytes
501 bytes
461 }
502 }
462 }
503 }
463
504
464 pub fn is_inline(index_bytes: &[u8]) -> bool {
505 pub fn is_inline(index_bytes: &[u8]) -> bool {
465 IndexHeader::parse(index_bytes)
506 IndexHeader::parse(index_bytes)
466 .expect("too short")
507 .expect("too short")
467 .format_flags()
508 .format_flags()
468 .is_inline()
509 .is_inline()
469 }
510 }
470
511
471 pub fn uses_generaldelta(index_bytes: &[u8]) -> bool {
512 pub fn uses_generaldelta(index_bytes: &[u8]) -> bool {
472 IndexHeader::parse(index_bytes)
513 IndexHeader::parse(index_bytes)
473 .expect("too short")
514 .expect("too short")
474 .format_flags()
515 .format_flags()
475 .uses_generaldelta()
516 .uses_generaldelta()
476 }
517 }
477
518
478 pub fn get_version(index_bytes: &[u8]) -> u16 {
519 pub fn get_version(index_bytes: &[u8]) -> u16 {
479 IndexHeader::parse(index_bytes)
520 IndexHeader::parse(index_bytes)
480 .expect("too short")
521 .expect("too short")
481 .format_version()
522 .format_version()
482 }
523 }
483
524
484 #[test]
525 #[test]
485 fn flags_when_no_inline_flag_test() {
526 fn flags_when_no_inline_flag_test() {
486 let bytes = IndexEntryBuilder::new()
527 let bytes = IndexEntryBuilder::new()
487 .is_first(true)
528 .is_first(true)
488 .with_general_delta(false)
529 .with_general_delta(false)
489 .with_inline(false)
530 .with_inline(false)
490 .build();
531 .build();
491
532
492 assert!(!is_inline(&bytes));
533 assert!(!is_inline(&bytes));
493 assert!(!uses_generaldelta(&bytes));
534 assert!(!uses_generaldelta(&bytes));
494 }
535 }
495
536
496 #[test]
537 #[test]
497 fn flags_when_inline_flag_test() {
538 fn flags_when_inline_flag_test() {
498 let bytes = IndexEntryBuilder::new()
539 let bytes = IndexEntryBuilder::new()
499 .is_first(true)
540 .is_first(true)
500 .with_general_delta(false)
541 .with_general_delta(false)
501 .with_inline(true)
542 .with_inline(true)
502 .build();
543 .build();
503
544
504 assert!(is_inline(&bytes));
545 assert!(is_inline(&bytes));
505 assert!(!uses_generaldelta(&bytes));
546 assert!(!uses_generaldelta(&bytes));
506 }
547 }
507
548
508 #[test]
549 #[test]
509 fn flags_when_inline_and_generaldelta_flags_test() {
550 fn flags_when_inline_and_generaldelta_flags_test() {
510 let bytes = IndexEntryBuilder::new()
551 let bytes = IndexEntryBuilder::new()
511 .is_first(true)
552 .is_first(true)
512 .with_general_delta(true)
553 .with_general_delta(true)
513 .with_inline(true)
554 .with_inline(true)
514 .build();
555 .build();
515
556
516 assert!(is_inline(&bytes));
557 assert!(is_inline(&bytes));
517 assert!(uses_generaldelta(&bytes));
558 assert!(uses_generaldelta(&bytes));
518 }
559 }
519
560
520 #[test]
561 #[test]
521 fn test_offset() {
562 fn test_offset() {
522 let bytes = IndexEntryBuilder::new().with_offset(1).build();
563 let bytes = IndexEntryBuilder::new().with_offset(1).build();
523 let entry = IndexEntry {
564 let entry = IndexEntry {
524 bytes: &bytes,
565 bytes: &bytes,
525 offset_override: None,
566 offset_override: None,
526 };
567 };
527
568
528 assert_eq!(entry.offset(), 1)
569 assert_eq!(entry.offset(), 1)
529 }
570 }
530
571
531 #[test]
572 #[test]
532 fn test_with_overridden_offset() {
573 fn test_with_overridden_offset() {
533 let bytes = IndexEntryBuilder::new().with_offset(1).build();
574 let bytes = IndexEntryBuilder::new().with_offset(1).build();
534 let entry = IndexEntry {
575 let entry = IndexEntry {
535 bytes: &bytes,
576 bytes: &bytes,
536 offset_override: Some(2),
577 offset_override: Some(2),
537 };
578 };
538
579
539 assert_eq!(entry.offset(), 2)
580 assert_eq!(entry.offset(), 2)
540 }
581 }
541
582
542 #[test]
583 #[test]
543 fn test_compressed_len() {
584 fn test_compressed_len() {
544 let bytes = IndexEntryBuilder::new().with_compressed_len(1).build();
585 let bytes = IndexEntryBuilder::new().with_compressed_len(1).build();
545 let entry = IndexEntry {
586 let entry = IndexEntry {
546 bytes: &bytes,
587 bytes: &bytes,
547 offset_override: None,
588 offset_override: None,
548 };
589 };
549
590
550 assert_eq!(entry.compressed_len(), 1)
591 assert_eq!(entry.compressed_len(), 1)
551 }
592 }
552
593
553 #[test]
594 #[test]
554 fn test_uncompressed_len() {
595 fn test_uncompressed_len() {
555 let bytes = IndexEntryBuilder::new().with_uncompressed_len(1).build();
596 let bytes = IndexEntryBuilder::new().with_uncompressed_len(1).build();
556 let entry = IndexEntry {
597 let entry = IndexEntry {
557 bytes: &bytes,
598 bytes: &bytes,
558 offset_override: None,
599 offset_override: None,
559 };
600 };
560
601
561 assert_eq!(entry.uncompressed_len(), 1)
602 assert_eq!(entry.uncompressed_len(), 1)
562 }
603 }
563
604
564 #[test]
605 #[test]
565 fn test_base_revision_or_base_of_delta_chain() {
606 fn test_base_revision_or_base_of_delta_chain() {
566 let bytes = IndexEntryBuilder::new()
607 let bytes = IndexEntryBuilder::new()
567 .with_base_revision_or_base_of_delta_chain(Revision(1))
608 .with_base_revision_or_base_of_delta_chain(Revision(1))
568 .build();
609 .build();
569 let entry = IndexEntry {
610 let entry = IndexEntry {
570 bytes: &bytes,
611 bytes: &bytes,
571 offset_override: None,
612 offset_override: None,
572 };
613 };
573
614
574 assert_eq!(entry.base_revision_or_base_of_delta_chain(), 1.into())
615 assert_eq!(entry.base_revision_or_base_of_delta_chain(), 1.into())
575 }
616 }
576
617
577 #[test]
618 #[test]
578 fn link_revision_test() {
619 fn link_revision_test() {
579 let bytes = IndexEntryBuilder::new()
620 let bytes = IndexEntryBuilder::new()
580 .with_link_revision(Revision(123))
621 .with_link_revision(Revision(123))
581 .build();
622 .build();
582
623
583 let entry = IndexEntry {
624 let entry = IndexEntry {
584 bytes: &bytes,
625 bytes: &bytes,
585 offset_override: None,
626 offset_override: None,
586 };
627 };
587
628
588 assert_eq!(entry.link_revision(), 123.into());
629 assert_eq!(entry.link_revision(), 123.into());
589 }
630 }
590
631
591 #[test]
632 #[test]
592 fn p1_test() {
633 fn p1_test() {
593 let bytes = IndexEntryBuilder::new().with_p1(Revision(123)).build();
634 let bytes = IndexEntryBuilder::new().with_p1(Revision(123)).build();
594
635
595 let entry = IndexEntry {
636 let entry = IndexEntry {
596 bytes: &bytes,
637 bytes: &bytes,
597 offset_override: None,
638 offset_override: None,
598 };
639 };
599
640
600 assert_eq!(entry.p1(), 123.into());
641 assert_eq!(entry.p1(), 123.into());
601 }
642 }
602
643
603 #[test]
644 #[test]
604 fn p2_test() {
645 fn p2_test() {
605 let bytes = IndexEntryBuilder::new().with_p2(Revision(123)).build();
646 let bytes = IndexEntryBuilder::new().with_p2(Revision(123)).build();
606
647
607 let entry = IndexEntry {
648 let entry = IndexEntry {
608 bytes: &bytes,
649 bytes: &bytes,
609 offset_override: None,
650 offset_override: None,
610 };
651 };
611
652
612 assert_eq!(entry.p2(), 123.into());
653 assert_eq!(entry.p2(), 123.into());
613 }
654 }
614
655
615 #[test]
656 #[test]
616 fn node_test() {
657 fn node_test() {
617 let node = Node::from_hex("0123456789012345678901234567890123456789")
658 let node = Node::from_hex("0123456789012345678901234567890123456789")
618 .unwrap();
659 .unwrap();
619 let bytes = IndexEntryBuilder::new().with_node(node).build();
660 let bytes = IndexEntryBuilder::new().with_node(node).build();
620
661
621 let entry = IndexEntry {
662 let entry = IndexEntry {
622 bytes: &bytes,
663 bytes: &bytes,
623 offset_override: None,
664 offset_override: None,
624 };
665 };
625
666
626 assert_eq!(*entry.hash(), node);
667 assert_eq!(*entry.hash(), node);
627 }
668 }
628
669
629 #[test]
670 #[test]
630 fn version_test() {
671 fn version_test() {
631 let bytes = IndexEntryBuilder::new()
672 let bytes = IndexEntryBuilder::new()
632 .is_first(true)
673 .is_first(true)
633 .with_version(2)
674 .with_version(2)
634 .build();
675 .build();
635
676
636 assert_eq!(get_version(&bytes), 2)
677 assert_eq!(get_version(&bytes), 2)
637 }
678 }
638 }
679 }
639
680
640 #[cfg(test)]
681 #[cfg(test)]
641 pub use tests::IndexEntryBuilder;
682 pub use tests::IndexEntryBuilder;
General Comments 0
You need to be logged in to leave comments. Login now