##// END OF EJS Templates
hg-core: minor code style change (D8958#inline-14986 followup)...
Antoine cezar -
r46166:a886ffd2 default
parent child Browse files
Show More
@@ -1,331 +1,328
1 1 use byteorder::{BigEndian, ByteOrder};
2 2
3 3 use crate::revlog::{Revision, NULL_REVISION};
4 4
5 5 pub const INDEX_ENTRY_SIZE: usize = 64;
6 6
7 7 /// A Revlog index
8 8 #[derive(Debug)]
9 9 pub struct Index<'a> {
10 10 bytes: &'a [u8],
11 11 /// Offsets of starts of index blocks.
12 12 /// Only needed when the index is interleaved with data.
13 13 offsets: Option<Vec<usize>>,
14 14 }
15 15
16 16 impl<'a> Index<'a> {
17 17 /// Create an index from bytes.
18 18 /// Calculate the start of each entry when is_inline is true.
19 19 pub fn new(bytes: &'a [u8], is_inline: bool) -> Self {
20 20 if is_inline {
21 21 let mut offset: usize = 0;
22 22 let mut offsets = Vec::new();
23 23
24 24 while offset + INDEX_ENTRY_SIZE <= bytes.len() {
25 25 offsets.push(offset);
26 26 let end = offset + INDEX_ENTRY_SIZE;
27 27 let entry = IndexEntry {
28 28 bytes: &bytes[offset..end],
29 29 offset_override: None,
30 30 };
31 31
32 32 offset += INDEX_ENTRY_SIZE + entry.compressed_len();
33 33 }
34 34
35 35 Self {
36 36 bytes,
37 37 offsets: Some(offsets),
38 38 }
39 39 } else {
40 40 Self {
41 41 bytes,
42 42 offsets: None,
43 43 }
44 44 }
45 45 }
46 46
47 47 /// Return number of entries of the revlog index.
48 48 pub fn len(&self) -> usize {
49 49 if let Some(offsets) = &self.offsets {
50 50 offsets.len()
51 51 } else {
52 52 self.bytes.len() / INDEX_ENTRY_SIZE
53 53 }
54 54 }
55 55
56 56 /// Returns `true` if the `Index` has zero `entries`.
57 57 pub fn is_empty(&self) -> bool {
58 58 self.len() == 0
59 59 }
60 60
61 61 /// Return the index entry corresponding to the given revision if it
62 62 /// exists.
63 63 pub fn get_entry(&self, rev: Revision) -> Option<IndexEntry> {
64 64 if rev == NULL_REVISION {
65 65 return None;
66 66 }
67 67 if let Some(offsets) = &self.offsets {
68 68 self.get_entry_inline(rev, offsets)
69 69 } else {
70 70 self.get_entry_separated(rev)
71 71 }
72 72 }
73 73
74 74 fn get_entry_inline(
75 75 &self,
76 76 rev: Revision,
77 77 offsets: &[usize],
78 78 ) -> Option<IndexEntry> {
79 79 let start = *offsets.get(rev as usize)?;
80 80 let end = start.checked_add(INDEX_ENTRY_SIZE)?;
81 81 let bytes = &self.bytes[start..end];
82 82
83 83 // See IndexEntry for an explanation of this override.
84 84 let offset_override = Some(end);
85 85
86 86 Some(IndexEntry {
87 87 bytes,
88 88 offset_override,
89 89 })
90 90 }
91 91
92 92 fn get_entry_separated(&self, rev: Revision) -> Option<IndexEntry> {
93 93 let max_rev = self.bytes.len() / INDEX_ENTRY_SIZE;
94 94 if rev as usize >= max_rev {
95 95 return None;
96 96 }
97 97 let start = rev as usize * INDEX_ENTRY_SIZE;
98 98 let end = start + INDEX_ENTRY_SIZE;
99 99 let bytes = &self.bytes[start..end];
100 100
101 101 // Override the offset of the first revision as its bytes are used
102 102 // for the index's metadata (saving space because it is always 0)
103 let offset_override = match rev {
104 0 => Some(0),
105 _ => None,
106 };
103 let offset_override = if rev == 0 { Some(0) } else { None };
107 104
108 105 Some(IndexEntry {
109 106 bytes,
110 107 offset_override,
111 108 })
112 109 }
113 110 }
114 111
115 112 #[derive(Debug)]
116 113 pub struct IndexEntry<'a> {
117 114 bytes: &'a [u8],
118 115 /// Allows to override the offset value of the entry.
119 116 ///
120 117 /// For interleaved index and data, the offset stored in the index
121 118 /// corresponds to the separated data offset.
122 119 /// It has to be overridden with the actual offset in the interleaved
123 120 /// index which is just after the index block.
124 121 ///
125 122 /// For separated index and data, the offset stored in the first index
126 123 /// entry is mixed with the index headers.
127 124 /// It has to be overridden with 0.
128 125 offset_override: Option<usize>,
129 126 }
130 127
131 128 impl<'a> IndexEntry<'a> {
132 129 /// Return the offset of the data if not overridden by offset_override.
133 130 pub fn offset(&self) -> usize {
134 131 if let Some(offset_override) = self.offset_override {
135 132 offset_override
136 133 } else {
137 134 let mut bytes = [0; 8];
138 135 bytes[2..8].copy_from_slice(&self.bytes[0..=5]);
139 136 BigEndian::read_u64(&bytes[..]) as usize
140 137 }
141 138 }
142 139
143 140 /// Return the compressed length of the data.
144 141 pub fn compressed_len(&self) -> usize {
145 142 BigEndian::read_u32(&self.bytes[8..=11]) as usize
146 143 }
147 144
148 145 /// Return the uncompressed length of the data.
149 146 pub fn uncompressed_len(&self) -> usize {
150 147 BigEndian::read_u32(&self.bytes[12..=15]) as usize
151 148 }
152 149
153 150 /// Return the revision upon which the data has been derived.
154 151 pub fn base_revision(&self) -> Revision {
155 152 // TODO Maybe return an Option when base_revision == rev?
156 153 // Requires to add rev to IndexEntry
157 154
158 155 BigEndian::read_i32(&self.bytes[16..])
159 156 }
160 157
161 158 pub fn p1(&self) -> Revision {
162 159 BigEndian::read_i32(&self.bytes[24..])
163 160 }
164 161
165 162 pub fn p2(&self) -> Revision {
166 163 BigEndian::read_i32(&self.bytes[28..])
167 164 }
168 165
169 166 /// Return the hash of revision's full text.
170 167 ///
171 168 /// Currently, SHA-1 is used and only the first 20 bytes of this field
172 169 /// are used.
173 170 pub fn hash(&self) -> &[u8] {
174 171 &self.bytes[32..52]
175 172 }
176 173 }
177 174
178 175 #[cfg(test)]
179 176 mod tests {
180 177 use super::*;
181 178
182 179 #[cfg(test)]
183 180 #[derive(Debug, Copy, Clone)]
184 181 pub struct IndexEntryBuilder {
185 182 is_first: bool,
186 183 is_inline: bool,
187 184 is_general_delta: bool,
188 185 version: u16,
189 186 offset: usize,
190 187 compressed_len: usize,
191 188 uncompressed_len: usize,
192 189 base_revision: Revision,
193 190 }
194 191
195 192 #[cfg(test)]
196 193 impl IndexEntryBuilder {
197 194 pub fn new() -> Self {
198 195 Self {
199 196 is_first: false,
200 197 is_inline: false,
201 198 is_general_delta: true,
202 199 version: 2,
203 200 offset: 0,
204 201 compressed_len: 0,
205 202 uncompressed_len: 0,
206 203 base_revision: 0,
207 204 }
208 205 }
209 206
210 207 pub fn is_first(&mut self, value: bool) -> &mut Self {
211 208 self.is_first = value;
212 209 self
213 210 }
214 211
215 212 pub fn with_inline(&mut self, value: bool) -> &mut Self {
216 213 self.is_inline = value;
217 214 self
218 215 }
219 216
220 217 pub fn with_general_delta(&mut self, value: bool) -> &mut Self {
221 218 self.is_general_delta = value;
222 219 self
223 220 }
224 221
225 222 pub fn with_version(&mut self, value: u16) -> &mut Self {
226 223 self.version = value;
227 224 self
228 225 }
229 226
230 227 pub fn with_offset(&mut self, value: usize) -> &mut Self {
231 228 self.offset = value;
232 229 self
233 230 }
234 231
235 232 pub fn with_compressed_len(&mut self, value: usize) -> &mut Self {
236 233 self.compressed_len = value;
237 234 self
238 235 }
239 236
240 237 pub fn with_uncompressed_len(&mut self, value: usize) -> &mut Self {
241 238 self.uncompressed_len = value;
242 239 self
243 240 }
244 241
245 242 pub fn with_base_revision(&mut self, value: Revision) -> &mut Self {
246 243 self.base_revision = value;
247 244 self
248 245 }
249 246
250 247 pub fn build(&self) -> Vec<u8> {
251 248 let mut bytes = Vec::with_capacity(INDEX_ENTRY_SIZE);
252 249 if self.is_first {
253 250 bytes.extend(&match (self.is_general_delta, self.is_inline) {
254 251 (false, false) => [0u8, 0],
255 252 (false, true) => [0u8, 1],
256 253 (true, false) => [0u8, 2],
257 254 (true, true) => [0u8, 3],
258 255 });
259 256 bytes.extend(&self.version.to_be_bytes());
260 257 // Remaining offset bytes.
261 258 bytes.extend(&[0u8; 2]);
262 259 } else {
263 260 // Offset is only 6 bytes will usize is 8.
264 261 bytes.extend(&self.offset.to_be_bytes()[2..]);
265 262 }
266 263 bytes.extend(&[0u8; 2]); // Revision flags.
267 264 bytes.extend(&self.compressed_len.to_be_bytes()[4..]);
268 265 bytes.extend(&self.uncompressed_len.to_be_bytes()[4..]);
269 266 bytes.extend(&self.base_revision.to_be_bytes());
270 267 bytes
271 268 }
272 269 }
273 270
274 271 #[test]
275 272 fn test_offset() {
276 273 let bytes = IndexEntryBuilder::new().with_offset(1).build();
277 274 let entry = IndexEntry {
278 275 bytes: &bytes,
279 276 offset_override: None,
280 277 };
281 278
282 279 assert_eq!(entry.offset(), 1)
283 280 }
284 281
285 282 #[test]
286 283 fn test_with_overridden_offset() {
287 284 let bytes = IndexEntryBuilder::new().with_offset(1).build();
288 285 let entry = IndexEntry {
289 286 bytes: &bytes,
290 287 offset_override: Some(2),
291 288 };
292 289
293 290 assert_eq!(entry.offset(), 2)
294 291 }
295 292
296 293 #[test]
297 294 fn test_compressed_len() {
298 295 let bytes = IndexEntryBuilder::new().with_compressed_len(1).build();
299 296 let entry = IndexEntry {
300 297 bytes: &bytes,
301 298 offset_override: None,
302 299 };
303 300
304 301 assert_eq!(entry.compressed_len(), 1)
305 302 }
306 303
307 304 #[test]
308 305 fn test_uncompressed_len() {
309 306 let bytes = IndexEntryBuilder::new().with_uncompressed_len(1).build();
310 307 let entry = IndexEntry {
311 308 bytes: &bytes,
312 309 offset_override: None,
313 310 };
314 311
315 312 assert_eq!(entry.uncompressed_len(), 1)
316 313 }
317 314
318 315 #[test]
319 316 fn test_base_revision() {
320 317 let bytes = IndexEntryBuilder::new().with_base_revision(1).build();
321 318 let entry = IndexEntry {
322 319 bytes: &bytes,
323 320 offset_override: None,
324 321 };
325 322
326 323 assert_eq!(entry.base_revision(), 1)
327 324 }
328 325 }
329 326
330 327 #[cfg(test)]
331 328 pub use tests::IndexEntryBuilder;
General Comments 0
You need to be logged in to leave comments. Login now