##// END OF EJS Templates
dirstate-tree: Add "non normal" and "from other parent" sets...
Simon Sapin -
r47878:e3cebe96 default
parent child Browse files
Show More
@@ -1,107 +1,119 b''
1 1 // dirstate module
2 2 //
3 3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
4 4 //
5 5 // This software may be used and distributed according to the terms of the
6 6 // GNU General Public License version 2 or any later version.
7 7
8 8 use crate::errors::HgError;
9 9 use crate::revlog::Node;
10 10 use crate::{utils::hg_path::HgPathBuf, FastHashMap};
11 11 use bytes_cast::{unaligned, BytesCast};
12 12 use std::convert::TryFrom;
13 13
14 14 pub mod dirs_multiset;
15 15 pub mod dirstate_map;
16 16 pub mod parsers;
17 17 pub mod status;
18 18
19 19 #[derive(Debug, PartialEq, Clone, BytesCast)]
20 20 #[repr(C)]
21 21 pub struct DirstateParents {
22 22 pub p1: Node,
23 23 pub p2: Node,
24 24 }
25 25
26 26 /// The C implementation uses all signed types. This will be an issue
27 27 /// either when 4GB+ source files are commonplace or in 2038, whichever
28 28 /// comes first.
29 29 #[derive(Debug, PartialEq, Copy, Clone)]
30 30 pub struct DirstateEntry {
31 31 pub state: EntryState,
32 32 pub mode: i32,
33 33 pub mtime: i32,
34 34 pub size: i32,
35 35 }
36 36
37 impl DirstateEntry {
38 pub fn is_non_normal(&self) -> bool {
39 self.state != EntryState::Normal || self.mtime == MTIME_UNSET
40 }
41
42 pub fn is_from_other_parent(&self) -> bool {
43 self.state == EntryState::Normal && self.size == SIZE_FROM_OTHER_PARENT
44 }
45 }
46
37 47 #[derive(BytesCast)]
38 48 #[repr(C)]
39 49 struct RawEntry {
40 50 state: u8,
41 51 mode: unaligned::I32Be,
42 52 size: unaligned::I32Be,
43 53 mtime: unaligned::I32Be,
44 54 length: unaligned::I32Be,
45 55 }
46 56
57 const MTIME_UNSET: i32 = -1;
58
47 59 /// A `DirstateEntry` with a size of `-2` means that it was merged from the
48 60 /// other parent. This allows revert to pick the right status back during a
49 61 /// merge.
50 62 pub const SIZE_FROM_OTHER_PARENT: i32 = -2;
51 63
52 64 pub type StateMap = FastHashMap<HgPathBuf, DirstateEntry>;
53 65 pub type StateMapIter<'a> =
54 66 Box<dyn Iterator<Item = (&'a HgPathBuf, &'a DirstateEntry)> + Send + 'a>;
55 67
56 68 pub type CopyMap = FastHashMap<HgPathBuf, HgPathBuf>;
57 69 pub type CopyMapIter<'a> =
58 70 Box<dyn Iterator<Item = (&'a HgPathBuf, &'a HgPathBuf)> + Send + 'a>;
59 71
60 72 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
61 73 pub enum EntryState {
62 74 Normal,
63 75 Added,
64 76 Removed,
65 77 Merged,
66 78 Unknown,
67 79 }
68 80
69 81 impl EntryState {
70 82 pub fn is_tracked(self) -> bool {
71 83 use EntryState::*;
72 84 match self {
73 85 Normal | Added | Merged => true,
74 86 Removed | Unknown => false,
75 87 }
76 88 }
77 89 }
78 90
79 91 impl TryFrom<u8> for EntryState {
80 92 type Error = HgError;
81 93
82 94 fn try_from(value: u8) -> Result<Self, Self::Error> {
83 95 match value {
84 96 b'n' => Ok(EntryState::Normal),
85 97 b'a' => Ok(EntryState::Added),
86 98 b'r' => Ok(EntryState::Removed),
87 99 b'm' => Ok(EntryState::Merged),
88 100 b'?' => Ok(EntryState::Unknown),
89 101 _ => Err(HgError::CorruptedRepository(format!(
90 102 "Incorrect dirstate entry state {}",
91 103 value
92 104 ))),
93 105 }
94 106 }
95 107 }
96 108
97 109 impl Into<u8> for EntryState {
98 110 fn into(self) -> u8 {
99 111 match self {
100 112 EntryState::Normal => b'n',
101 113 EntryState::Added => b'a',
102 114 EntryState::Removed => b'r',
103 115 EntryState::Merged => b'm',
104 116 EntryState::Unknown => b'?',
105 117 }
106 118 }
107 119 }
@@ -1,498 +1,487 b''
1 1 // dirstate_map.rs
2 2 //
3 3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
4 4 //
5 5 // This software may be used and distributed according to the terms of the
6 6 // GNU General Public License version 2 or any later version.
7 7
8 8 use crate::dirstate::parsers::clear_ambiguous_mtime;
9 9 use crate::dirstate::parsers::Timestamp;
10 10 use crate::errors::HgError;
11 11 use crate::revlog::node::NULL_NODE;
12 12 use crate::{
13 dirstate::{parsers::PARENT_SIZE, EntryState, SIZE_FROM_OTHER_PARENT},
13 dirstate::{parsers::PARENT_SIZE, EntryState},
14 14 pack_dirstate, parse_dirstate,
15 15 utils::{
16 16 files::normalize_case,
17 17 hg_path::{HgPath, HgPathBuf},
18 18 },
19 19 CopyMap, DirsMultiset, DirstateEntry, DirstateError, DirstateMapError,
20 20 DirstateParents, FastHashMap, StateMap,
21 21 };
22 22 use micro_timer::timed;
23 23 use std::collections::HashSet;
24 24 use std::convert::TryInto;
25 25 use std::iter::FromIterator;
26 26 use std::ops::Deref;
27 27
28 28 pub type FileFoldMap = FastHashMap<HgPathBuf, HgPathBuf>;
29 29
30 const MTIME_UNSET: i32 = -1;
31
32 30 #[derive(Default)]
33 31 pub struct DirstateMap {
34 32 state_map: StateMap,
35 33 pub copy_map: CopyMap,
36 34 file_fold_map: Option<FileFoldMap>,
37 35 pub dirs: Option<DirsMultiset>,
38 36 pub all_dirs: Option<DirsMultiset>,
39 37 non_normal_set: Option<HashSet<HgPathBuf>>,
40 38 other_parent_set: Option<HashSet<HgPathBuf>>,
41 39 parents: Option<DirstateParents>,
42 40 dirty_parents: bool,
43 41 }
44 42
45 43 /// Should only really be used in python interface code, for clarity
46 44 impl Deref for DirstateMap {
47 45 type Target = StateMap;
48 46
49 47 fn deref(&self) -> &Self::Target {
50 48 &self.state_map
51 49 }
52 50 }
53 51
54 52 impl FromIterator<(HgPathBuf, DirstateEntry)> for DirstateMap {
55 53 fn from_iter<I: IntoIterator<Item = (HgPathBuf, DirstateEntry)>>(
56 54 iter: I,
57 55 ) -> Self {
58 56 Self {
59 57 state_map: iter.into_iter().collect(),
60 58 ..Self::default()
61 59 }
62 60 }
63 61 }
64 62
65 63 impl DirstateMap {
66 64 pub fn new() -> Self {
67 65 Self::default()
68 66 }
69 67
70 68 pub fn clear(&mut self) {
71 69 self.state_map = StateMap::default();
72 70 self.copy_map.clear();
73 71 self.file_fold_map = None;
74 72 self.non_normal_set = None;
75 73 self.other_parent_set = None;
76 74 self.set_parents(&DirstateParents {
77 75 p1: NULL_NODE,
78 76 p2: NULL_NODE,
79 77 })
80 78 }
81 79
82 80 /// Add a tracked file to the dirstate
83 81 pub fn add_file(
84 82 &mut self,
85 83 filename: &HgPath,
86 84 old_state: EntryState,
87 85 entry: DirstateEntry,
88 86 ) -> Result<(), DirstateMapError> {
89 87 if old_state == EntryState::Unknown || old_state == EntryState::Removed
90 88 {
91 89 if let Some(ref mut dirs) = self.dirs {
92 90 dirs.add_path(filename)?;
93 91 }
94 92 }
95 93 if old_state == EntryState::Unknown {
96 94 if let Some(ref mut all_dirs) = self.all_dirs {
97 95 all_dirs.add_path(filename)?;
98 96 }
99 97 }
100 98 self.state_map.insert(filename.to_owned(), entry.to_owned());
101 99
102 if entry.state != EntryState::Normal || entry.mtime == MTIME_UNSET {
100 if entry.is_non_normal() {
103 101 self.get_non_normal_other_parent_entries()
104 102 .0
105 103 .insert(filename.to_owned());
106 104 }
107 105
108 if entry.size == SIZE_FROM_OTHER_PARENT {
106 if entry.is_from_other_parent() {
109 107 self.get_non_normal_other_parent_entries()
110 108 .1
111 109 .insert(filename.to_owned());
112 110 }
113 111 Ok(())
114 112 }
115 113
116 114 /// Mark a file as removed in the dirstate.
117 115 ///
118 116 /// The `size` parameter is used to store sentinel values that indicate
119 117 /// the file's previous state. In the future, we should refactor this
120 118 /// to be more explicit about what that state is.
121 119 pub fn remove_file(
122 120 &mut self,
123 121 filename: &HgPath,
124 122 old_state: EntryState,
125 123 size: i32,
126 124 ) -> Result<(), DirstateMapError> {
127 125 if old_state != EntryState::Unknown && old_state != EntryState::Removed
128 126 {
129 127 if let Some(ref mut dirs) = self.dirs {
130 128 dirs.delete_path(filename)?;
131 129 }
132 130 }
133 131 if old_state == EntryState::Unknown {
134 132 if let Some(ref mut all_dirs) = self.all_dirs {
135 133 all_dirs.add_path(filename)?;
136 134 }
137 135 }
138 136
139 137 if let Some(ref mut file_fold_map) = self.file_fold_map {
140 138 file_fold_map.remove(&normalize_case(filename));
141 139 }
142 140 self.state_map.insert(
143 141 filename.to_owned(),
144 142 DirstateEntry {
145 143 state: EntryState::Removed,
146 144 mode: 0,
147 145 size,
148 146 mtime: 0,
149 147 },
150 148 );
151 149 self.get_non_normal_other_parent_entries()
152 150 .0
153 151 .insert(filename.to_owned());
154 152 Ok(())
155 153 }
156 154
157 155 /// Remove a file from the dirstate.
158 156 /// Returns `true` if the file was previously recorded.
159 157 pub fn drop_file(
160 158 &mut self,
161 159 filename: &HgPath,
162 160 old_state: EntryState,
163 161 ) -> Result<bool, DirstateMapError> {
164 162 let exists = self.state_map.remove(filename).is_some();
165 163
166 164 if exists {
167 165 if old_state != EntryState::Removed {
168 166 if let Some(ref mut dirs) = self.dirs {
169 167 dirs.delete_path(filename)?;
170 168 }
171 169 }
172 170 if let Some(ref mut all_dirs) = self.all_dirs {
173 171 all_dirs.delete_path(filename)?;
174 172 }
175 173 }
176 174 if let Some(ref mut file_fold_map) = self.file_fold_map {
177 175 file_fold_map.remove(&normalize_case(filename));
178 176 }
179 177 self.get_non_normal_other_parent_entries()
180 178 .0
181 179 .remove(filename);
182 180
183 181 Ok(exists)
184 182 }
185 183
186 184 pub fn clear_ambiguous_times(
187 185 &mut self,
188 186 filenames: Vec<HgPathBuf>,
189 187 now: i32,
190 188 ) {
191 189 for filename in filenames {
192 190 if let Some(entry) = self.state_map.get_mut(&filename) {
193 191 if clear_ambiguous_mtime(entry, now) {
194 192 self.get_non_normal_other_parent_entries()
195 193 .0
196 194 .insert(filename.to_owned());
197 195 }
198 196 }
199 197 }
200 198 }
201 199
202 pub fn non_normal_entries_remove(
203 &mut self,
204 key: impl AsRef<HgPath>,
205 ) -> bool {
200 pub fn non_normal_entries_remove(&mut self, key: impl AsRef<HgPath>) {
206 201 self.get_non_normal_other_parent_entries()
207 202 .0
208 .remove(key.as_ref())
203 .remove(key.as_ref());
209 204 }
205
210 206 pub fn non_normal_entries_union(
211 207 &mut self,
212 208 other: HashSet<HgPathBuf>,
213 209 ) -> Vec<HgPathBuf> {
214 210 self.get_non_normal_other_parent_entries()
215 211 .0
216 212 .union(&other)
217 213 .map(ToOwned::to_owned)
218 214 .collect()
219 215 }
220 216
221 217 pub fn get_non_normal_other_parent_entries(
222 218 &mut self,
223 219 ) -> (&mut HashSet<HgPathBuf>, &mut HashSet<HgPathBuf>) {
224 220 self.set_non_normal_other_parent_entries(false);
225 221 (
226 222 self.non_normal_set.as_mut().unwrap(),
227 223 self.other_parent_set.as_mut().unwrap(),
228 224 )
229 225 }
230 226
231 227 /// Useful to get immutable references to those sets in contexts where
232 228 /// you only have an immutable reference to the `DirstateMap`, like when
233 229 /// sharing references with Python.
234 230 ///
235 231 /// TODO, get rid of this along with the other "setter/getter" stuff when
236 232 /// a nice typestate plan is defined.
237 233 ///
238 234 /// # Panics
239 235 ///
240 236 /// Will panic if either set is `None`.
241 237 pub fn get_non_normal_other_parent_entries_panic(
242 238 &self,
243 239 ) -> (&HashSet<HgPathBuf>, &HashSet<HgPathBuf>) {
244 240 (
245 241 self.non_normal_set.as_ref().unwrap(),
246 242 self.other_parent_set.as_ref().unwrap(),
247 243 )
248 244 }
249 245
250 246 pub fn set_non_normal_other_parent_entries(&mut self, force: bool) {
251 247 if !force
252 248 && self.non_normal_set.is_some()
253 249 && self.other_parent_set.is_some()
254 250 {
255 251 return;
256 252 }
257 253 let mut non_normal = HashSet::new();
258 254 let mut other_parent = HashSet::new();
259 255
260 for (
261 filename,
262 DirstateEntry {
263 state, size, mtime, ..
264 },
265 ) in self.state_map.iter()
266 {
267 if *state != EntryState::Normal || *mtime == MTIME_UNSET {
256 for (filename, entry) in self.state_map.iter() {
257 if entry.is_non_normal() {
268 258 non_normal.insert(filename.to_owned());
269 259 }
270 if *state == EntryState::Normal && *size == SIZE_FROM_OTHER_PARENT
271 {
260 if entry.is_from_other_parent() {
272 261 other_parent.insert(filename.to_owned());
273 262 }
274 263 }
275 264 self.non_normal_set = Some(non_normal);
276 265 self.other_parent_set = Some(other_parent);
277 266 }
278 267
279 268 /// Both of these setters and their uses appear to be the simplest way to
280 269 /// emulate a Python lazy property, but it is ugly and unidiomatic.
281 270 /// TODO One day, rewriting this struct using the typestate might be a
282 271 /// good idea.
283 272 pub fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> {
284 273 if self.all_dirs.is_none() {
285 274 self.all_dirs = Some(DirsMultiset::from_dirstate(
286 275 self.state_map.iter(),
287 276 None,
288 277 )?);
289 278 }
290 279 Ok(())
291 280 }
292 281
293 282 pub fn set_dirs(&mut self) -> Result<(), DirstateMapError> {
294 283 if self.dirs.is_none() {
295 284 self.dirs = Some(DirsMultiset::from_dirstate(
296 285 &self.state_map,
297 286 Some(EntryState::Removed),
298 287 )?);
299 288 }
300 289 Ok(())
301 290 }
302 291
303 292 pub fn has_tracked_dir(
304 293 &mut self,
305 294 directory: &HgPath,
306 295 ) -> Result<bool, DirstateMapError> {
307 296 self.set_dirs()?;
308 297 Ok(self.dirs.as_ref().unwrap().contains(directory))
309 298 }
310 299
311 300 pub fn has_dir(
312 301 &mut self,
313 302 directory: &HgPath,
314 303 ) -> Result<bool, DirstateMapError> {
315 304 self.set_all_dirs()?;
316 305 Ok(self.all_dirs.as_ref().unwrap().contains(directory))
317 306 }
318 307
319 308 pub fn parents(
320 309 &mut self,
321 310 file_contents: &[u8],
322 311 ) -> Result<&DirstateParents, DirstateError> {
323 312 if let Some(ref parents) = self.parents {
324 313 return Ok(parents);
325 314 }
326 315 let parents;
327 316 if file_contents.len() == PARENT_SIZE * 2 {
328 317 parents = DirstateParents {
329 318 p1: file_contents[..PARENT_SIZE].try_into().unwrap(),
330 319 p2: file_contents[PARENT_SIZE..PARENT_SIZE * 2]
331 320 .try_into()
332 321 .unwrap(),
333 322 };
334 323 } else if file_contents.is_empty() {
335 324 parents = DirstateParents {
336 325 p1: NULL_NODE,
337 326 p2: NULL_NODE,
338 327 };
339 328 } else {
340 329 return Err(
341 330 HgError::corrupted("Dirstate appears to be damaged").into()
342 331 );
343 332 }
344 333
345 334 self.parents = Some(parents);
346 335 Ok(self.parents.as_ref().unwrap())
347 336 }
348 337
349 338 pub fn set_parents(&mut self, parents: &DirstateParents) {
350 339 self.parents = Some(parents.clone());
351 340 self.dirty_parents = true;
352 341 }
353 342
354 343 #[timed]
355 344 pub fn read<'a>(
356 345 &mut self,
357 346 file_contents: &'a [u8],
358 347 ) -> Result<Option<&'a DirstateParents>, DirstateError> {
359 348 if file_contents.is_empty() {
360 349 return Ok(None);
361 350 }
362 351
363 352 let (parents, entries, copies) = parse_dirstate(file_contents)?;
364 353 self.state_map.extend(
365 354 entries
366 355 .into_iter()
367 356 .map(|(path, entry)| (path.to_owned(), entry)),
368 357 );
369 358 self.copy_map.extend(
370 359 copies
371 360 .into_iter()
372 361 .map(|(path, copy)| (path.to_owned(), copy.to_owned())),
373 362 );
374 363
375 364 if !self.dirty_parents {
376 365 self.set_parents(&parents);
377 366 }
378 367
379 368 Ok(Some(parents))
380 369 }
381 370
382 371 pub fn pack(
383 372 &mut self,
384 373 parents: DirstateParents,
385 374 now: Timestamp,
386 375 ) -> Result<Vec<u8>, DirstateError> {
387 376 let packed =
388 377 pack_dirstate(&mut self.state_map, &self.copy_map, parents, now)?;
389 378
390 379 self.dirty_parents = false;
391 380
392 381 self.set_non_normal_other_parent_entries(true);
393 382 Ok(packed)
394 383 }
395 384 pub fn build_file_fold_map(&mut self) -> &FileFoldMap {
396 385 if let Some(ref file_fold_map) = self.file_fold_map {
397 386 return file_fold_map;
398 387 }
399 388 let mut new_file_fold_map = FileFoldMap::default();
400 389
401 390 for (filename, DirstateEntry { state, .. }) in self.state_map.iter() {
402 391 if *state != EntryState::Removed {
403 392 new_file_fold_map
404 393 .insert(normalize_case(&filename), filename.to_owned());
405 394 }
406 395 }
407 396 self.file_fold_map = Some(new_file_fold_map);
408 397 self.file_fold_map.as_ref().unwrap()
409 398 }
410 399 }
411 400
412 401 #[cfg(test)]
413 402 mod tests {
414 403 use super::*;
415 404
416 405 #[test]
417 406 fn test_dirs_multiset() {
418 407 let mut map = DirstateMap::new();
419 408 assert!(map.dirs.is_none());
420 409 assert!(map.all_dirs.is_none());
421 410
422 411 assert_eq!(map.has_dir(HgPath::new(b"nope")).unwrap(), false);
423 412 assert!(map.all_dirs.is_some());
424 413 assert!(map.dirs.is_none());
425 414
426 415 assert_eq!(map.has_tracked_dir(HgPath::new(b"nope")).unwrap(), false);
427 416 assert!(map.dirs.is_some());
428 417 }
429 418
430 419 #[test]
431 420 fn test_add_file() {
432 421 let mut map = DirstateMap::new();
433 422
434 423 assert_eq!(0, map.len());
435 424
436 425 map.add_file(
437 426 HgPath::new(b"meh"),
438 427 EntryState::Normal,
439 428 DirstateEntry {
440 429 state: EntryState::Normal,
441 430 mode: 1337,
442 431 mtime: 1337,
443 432 size: 1337,
444 433 },
445 434 )
446 435 .unwrap();
447 436
448 437 assert_eq!(1, map.len());
449 438 assert_eq!(0, map.get_non_normal_other_parent_entries().0.len());
450 439 assert_eq!(0, map.get_non_normal_other_parent_entries().1.len());
451 440 }
452 441
453 442 #[test]
454 443 fn test_non_normal_other_parent_entries() {
455 444 let mut map: DirstateMap = [
456 445 (b"f1", (EntryState::Removed, 1337, 1337, 1337)),
457 446 (b"f2", (EntryState::Normal, 1337, 1337, -1)),
458 447 (b"f3", (EntryState::Normal, 1337, 1337, 1337)),
459 448 (b"f4", (EntryState::Normal, 1337, -2, 1337)),
460 449 (b"f5", (EntryState::Added, 1337, 1337, 1337)),
461 450 (b"f6", (EntryState::Added, 1337, 1337, -1)),
462 451 (b"f7", (EntryState::Merged, 1337, 1337, -1)),
463 452 (b"f8", (EntryState::Merged, 1337, 1337, 1337)),
464 453 (b"f9", (EntryState::Merged, 1337, -2, 1337)),
465 454 (b"fa", (EntryState::Added, 1337, -2, 1337)),
466 455 (b"fb", (EntryState::Removed, 1337, -2, 1337)),
467 456 ]
468 457 .iter()
469 458 .map(|(fname, (state, mode, size, mtime))| {
470 459 (
471 460 HgPathBuf::from_bytes(fname.as_ref()),
472 461 DirstateEntry {
473 462 state: *state,
474 463 mode: *mode,
475 464 size: *size,
476 465 mtime: *mtime,
477 466 },
478 467 )
479 468 })
480 469 .collect();
481 470
482 471 let mut non_normal = [
483 472 b"f1", b"f2", b"f5", b"f6", b"f7", b"f8", b"f9", b"fa", b"fb",
484 473 ]
485 474 .iter()
486 475 .map(|x| HgPathBuf::from_bytes(x.as_ref()))
487 476 .collect();
488 477
489 478 let mut other_parent = HashSet::new();
490 479 other_parent.insert(HgPathBuf::from_bytes(b"f4"));
491 480 let entries = map.get_non_normal_other_parent_entries();
492 481
493 482 assert_eq!(
494 483 (&mut non_normal, &mut other_parent),
495 484 (entries.0, entries.1)
496 485 );
497 486 }
498 487 }
@@ -1,642 +1,663 b''
1 1 use bytes_cast::BytesCast;
2 2 use std::path::PathBuf;
3 3 use std::{collections::BTreeMap, convert::TryInto};
4 4
5 5 use super::path_with_basename::WithBasename;
6 6 use crate::dirstate::parsers::clear_ambiguous_mtime;
7 7 use crate::dirstate::parsers::pack_entry;
8 8 use crate::dirstate::parsers::packed_entry_size;
9 9 use crate::dirstate::parsers::parse_dirstate_entries;
10 10 use crate::dirstate::parsers::parse_dirstate_parents;
11 11 use crate::dirstate::parsers::Timestamp;
12 12 use crate::matchers::Matcher;
13 13 use crate::revlog::node::NULL_NODE;
14 14 use crate::utils::hg_path::{HgPath, HgPathBuf};
15 15 use crate::CopyMapIter;
16 16 use crate::DirstateEntry;
17 17 use crate::DirstateError;
18 18 use crate::DirstateMapError;
19 19 use crate::DirstateParents;
20 20 use crate::DirstateStatus;
21 21 use crate::EntryState;
22 22 use crate::FastHashMap;
23 23 use crate::HgPathCow;
24 24 use crate::PatternFileWarning;
25 25 use crate::StateMapIter;
26 26 use crate::StatusError;
27 27 use crate::StatusOptions;
28 28
29 29 pub struct DirstateMap {
30 30 parents: Option<DirstateParents>,
31 31 dirty_parents: bool,
32 32 root: ChildNodes,
33 33
34 34 /// Number of nodes anywhere in the tree that have `.entry.is_some()`.
35 35 nodes_with_entry_count: usize,
36 36
37 37 /// Number of nodes anywhere in the tree that have
38 38 /// `.copy_source.is_some()`.
39 39 nodes_with_copy_source_count: usize,
40 40 }
41 41
42 42 /// Using a plain `HgPathBuf` of the full path from the repository root as a
43 43 /// map key would also work: all paths in a given map have the same parent
44 44 /// path, so comparing full paths gives the same result as comparing base
45 45 /// names. However `BTreeMap` would waste time always re-comparing the same
46 46 /// string prefix.
47 47 type ChildNodes = BTreeMap<WithBasename<HgPathBuf>, Node>;
48 48
49 49 /// Represents a file or a directory
50 50 #[derive(Default)]
51 51 struct Node {
52 52 /// `None` for directories
53 53 entry: Option<DirstateEntry>,
54 54
55 55 copy_source: Option<HgPathBuf>,
56 56
57 57 children: ChildNodes,
58 58
59 59 /// How many (non-inclusive) descendants of this node are tracked files
60 60 tracked_descendants_count: usize,
61 61 }
62 62
63 63 impl Node {
64 64 /// Whether this node has a `DirstateEntry` with `.state.is_tracked()`
65 65 fn is_tracked_file(&self) -> bool {
66 66 if let Some(entry) = &self.entry {
67 67 entry.state.is_tracked()
68 68 } else {
69 69 false
70 70 }
71 71 }
72 72 }
73 73
74 74 /// `(full_path, entry, copy_source)`
75 75 type NodeDataMut<'a> = (
76 76 &'a WithBasename<HgPathBuf>,
77 77 &'a mut Option<DirstateEntry>,
78 78 &'a mut Option<HgPathBuf>,
79 79 );
80 80
81 81 impl DirstateMap {
82 82 pub fn new() -> Self {
83 83 Self {
84 84 parents: None,
85 85 dirty_parents: false,
86 86 root: ChildNodes::new(),
87 87 nodes_with_entry_count: 0,
88 88 nodes_with_copy_source_count: 0,
89 89 }
90 90 }
91 91
92 92 fn get_node(&self, path: &HgPath) -> Option<&Node> {
93 93 let mut children = &self.root;
94 94 let mut components = path.components();
95 95 let mut component =
96 96 components.next().expect("expected at least one components");
97 97 loop {
98 98 let child = children.get(component)?;
99 99 if let Some(next_component) = components.next() {
100 100 component = next_component;
101 101 children = &child.children;
102 102 } else {
103 103 return Some(child);
104 104 }
105 105 }
106 106 }
107 107
108 108 /// Returns a mutable reference to the node at `path` if it exists
109 109 ///
110 110 /// This takes `root` instead of `&mut self` so that callers can mutate
111 111 /// other fields while the returned borrow is still valid
112 112 fn get_node_mut<'tree>(
113 113 root: &'tree mut ChildNodes,
114 114 path: &HgPath,
115 115 ) -> Option<&'tree mut Node> {
116 116 Self::each_and_get(root, path, |_| {})
117 117 }
118 118
119 119 /// Call `each` for each ancestor node of the one at `path` (not including
120 120 /// that node itself), starting from nearest the root.
121 121 ///
122 122 /// Panics (possibly after some calls to `each`) if there is no node at
123 123 /// `path`.
124 124 fn for_each_ancestor_node<'tree>(
125 125 &mut self,
126 126 path: &HgPath,
127 127 each: impl FnMut(&mut Node),
128 128 ) {
129 129 let parent = path.parent();
130 130 if !parent.is_empty() {
131 131 Self::each_and_get(&mut self.root, parent, each)
132 132 .expect("missing dirstate node");
133 133 }
134 134 }
135 135
136 136 /// Common implementation detail of `get_node_mut` and
137 137 /// `for_each_ancestor_node`
138 138 fn each_and_get<'tree>(
139 139 root: &'tree mut ChildNodes,
140 140 path: &HgPath,
141 141 mut each: impl FnMut(&mut Node),
142 142 ) -> Option<&'tree mut Node> {
143 143 let mut children = root;
144 144 let mut components = path.components();
145 145 let mut component =
146 146 components.next().expect("expected at least one components");
147 147 loop {
148 148 let child = children.get_mut(component)?;
149 149 each(child);
150 150 if let Some(next_component) = components.next() {
151 151 component = next_component;
152 152 children = &mut child.children;
153 153 } else {
154 154 return Some(child);
155 155 }
156 156 }
157 157 }
158 158
159 159 fn get_or_insert_node<'tree>(
160 160 root: &'tree mut ChildNodes,
161 161 path: &HgPath,
162 162 ) -> &'tree mut Node {
163 163 let mut child_nodes = root;
164 164 let mut inclusive_ancestor_paths =
165 165 WithBasename::inclusive_ancestors_of(path);
166 166 let mut ancestor_path = inclusive_ancestor_paths
167 167 .next()
168 168 .expect("expected at least one inclusive ancestor");
169 169 loop {
170 170 // TODO: can we avoid double lookup in all cases without allocating
171 171 // an owned key in cases where the map already contains that key?
172 172 let child_node =
173 173 if child_nodes.contains_key(ancestor_path.base_name()) {
174 174 child_nodes.get_mut(ancestor_path.base_name()).unwrap()
175 175 } else {
176 176 // This is always a vacant entry, using `.entry()` lets us
177 177 // return a `&mut Node` of the newly-inserted node without
178 178 // yet another lookup. `BTreeMap::insert` doesn’t do this.
179 179 child_nodes.entry(ancestor_path.to_owned()).or_default()
180 180 };
181 181 if let Some(next) = inclusive_ancestor_paths.next() {
182 182 ancestor_path = next;
183 183 child_nodes = &mut child_node.children;
184 184 } else {
185 185 return child_node;
186 186 }
187 187 }
188 188 }
189 189
190 190 /// The meaning of `new_copy_source` is:
191 191 ///
192 192 /// * `Some(Some(x))`: set `Node::copy_source` to `Some(x)`
193 193 /// * `Some(None)`: set `Node::copy_source` to `None`
194 194 /// * `None`: leave `Node::copy_source` unchanged
195 195 fn add_file_node(
196 196 &mut self,
197 197 path: &HgPath,
198 198 new_entry: DirstateEntry,
199 199 new_copy_source: Option<Option<HgPathBuf>>,
200 200 ) {
201 201 let node = Self::get_or_insert_node(&mut self.root, path);
202 202 if node.entry.is_none() {
203 203 self.nodes_with_entry_count += 1
204 204 }
205 205 if let Some(source) = &new_copy_source {
206 206 if node.copy_source.is_none() && source.is_some() {
207 207 self.nodes_with_copy_source_count += 1
208 208 }
209 209 if node.copy_source.is_some() && source.is_none() {
210 210 self.nodes_with_copy_source_count -= 1
211 211 }
212 212 }
213 213 let tracked_count_increment =
214 214 match (node.is_tracked_file(), new_entry.state.is_tracked()) {
215 215 (false, true) => 1,
216 216 (true, false) => -1,
217 217 _ => 0,
218 218 };
219 219
220 220 node.entry = Some(new_entry);
221 221 if let Some(source) = new_copy_source {
222 222 node.copy_source = source
223 223 }
224 224 // Borrow of `self.root` through `node` ends here
225 225
226 226 match tracked_count_increment {
227 227 1 => self.for_each_ancestor_node(path, |node| {
228 228 node.tracked_descendants_count += 1
229 229 }),
230 230 // We can’t use `+= -1` because the counter is unsigned
231 231 -1 => self.for_each_ancestor_node(path, |node| {
232 232 node.tracked_descendants_count -= 1
233 233 }),
234 234 _ => {}
235 235 }
236 236 }
237 237
238 238 fn iter_nodes<'a>(
239 239 &'a self,
240 240 ) -> impl Iterator<Item = (&'a WithBasename<HgPathBuf>, &'a Node)> + 'a
241 241 {
242 242 // Depth first tree traversal.
243 243 //
244 244 // If we could afford internal iteration and recursion,
245 245 // this would look like:
246 246 //
247 247 // ```
248 248 // fn traverse_children(
249 249 // children: &ChildNodes,
250 250 // each: &mut impl FnMut(&Node),
251 251 // ) {
252 252 // for child in children.values() {
253 253 // traverse_children(&child.children, each);
254 254 // each(child);
255 255 // }
256 256 // }
257 257 // ```
258 258 //
259 259 // However we want an external iterator and therefore can’t use the
260 260 // call stack. Use an explicit stack instead:
261 261 let mut stack = Vec::new();
262 262 let mut iter = self.root.iter();
263 263 std::iter::from_fn(move || {
264 264 while let Some((key, child_node)) = iter.next() {
265 265 // Pseudo-recursion
266 266 let new_iter = child_node.children.iter();
267 267 let old_iter = std::mem::replace(&mut iter, new_iter);
268 268 stack.push((key, child_node, old_iter));
269 269 }
270 270 // Found the end of a `children.iter()` iterator.
271 271 if let Some((key, child_node, next_iter)) = stack.pop() {
272 272 // "Return" from pseudo-recursion by restoring state from the
273 273 // explicit stack
274 274 iter = next_iter;
275 275
276 276 Some((key, child_node))
277 277 } else {
278 278 // Reached the bottom of the stack, we’re done
279 279 None
280 280 }
281 281 })
282 282 }
283 283
284 284 /// Mutable iterator for the `(entry, copy source)` of each node.
285 285 ///
286 286 /// It would not be safe to yield mutable references to nodes themeselves
287 287 /// with `-> impl Iterator<Item = &mut Node>` since child nodes are
288 288 /// reachable from their ancestor nodes, potentially creating multiple
289 289 /// `&mut` references to a given node.
290 290 fn iter_node_data_mut<'a>(
291 291 &'a mut self,
292 292 ) -> impl Iterator<Item = NodeDataMut<'a>> + 'a {
293 293 // Explict stack for pseudo-recursion, see `iter_nodes` above.
294 294 let mut stack = Vec::new();
295 295 let mut iter = self.root.iter_mut();
296 296 std::iter::from_fn(move || {
297 297 while let Some((key, child_node)) = iter.next() {
298 298 // Pseudo-recursion
299 299 let data =
300 300 (key, &mut child_node.entry, &mut child_node.copy_source);
301 301 let new_iter = child_node.children.iter_mut();
302 302 let old_iter = std::mem::replace(&mut iter, new_iter);
303 303 stack.push((data, old_iter));
304 304 }
305 305 // Found the end of a `children.values_mut()` iterator.
306 306 if let Some((data, next_iter)) = stack.pop() {
307 307 // "Return" from pseudo-recursion by restoring state from the
308 308 // explicit stack
309 309 iter = next_iter;
310 310
311 311 Some(data)
312 312 } else {
313 313 // Reached the bottom of the stack, we’re done
314 314 None
315 315 }
316 316 })
317 317 }
318 318 }
319 319
320 320 impl super::dispatch::DirstateMapMethods for DirstateMap {
321 321 fn clear(&mut self) {
322 322 self.set_parents(&DirstateParents {
323 323 p1: NULL_NODE,
324 324 p2: NULL_NODE,
325 325 });
326 326 self.root.clear();
327 327 self.nodes_with_entry_count = 0;
328 328 self.nodes_with_copy_source_count = 0;
329 329 }
330 330
331 331 fn add_file(
332 332 &mut self,
333 333 filename: &HgPath,
334 334 _old_state: EntryState,
335 335 entry: DirstateEntry,
336 336 ) -> Result<(), DirstateMapError> {
337 337 self.add_file_node(filename, entry, None);
338 338 Ok(())
339 339 }
340 340
341 341 fn remove_file(
342 342 &mut self,
343 343 filename: &HgPath,
344 344 _old_state: EntryState,
345 345 size: i32,
346 346 ) -> Result<(), DirstateMapError> {
347 347 let entry = DirstateEntry {
348 348 state: EntryState::Removed,
349 349 mode: 0,
350 350 size,
351 351 mtime: 0,
352 352 };
353 353 self.add_file_node(filename, entry, None);
354 354 Ok(())
355 355 }
356 356
357 357 fn drop_file(
358 358 &mut self,
359 359 filename: &HgPath,
360 360 _old_state: EntryState,
361 361 ) -> Result<bool, DirstateMapError> {
362 362 if let Some(node) = Self::get_node_mut(&mut self.root, filename) {
363 363 let was_tracked = node.is_tracked_file();
364 364 let had_entry = node.entry.is_some();
365 365 let had_copy_source = node.copy_source.is_some();
366 366
367 367 // TODO: this leaves in the tree a "non-file" node. Should we
368 368 // remove the node instead, together with ancestor nodes for
369 369 // directories that become empty?
370 370 node.entry = None;
371 371 node.copy_source = None;
372 372
373 373 if had_entry {
374 374 self.nodes_with_entry_count -= 1
375 375 }
376 376 if had_copy_source {
377 377 self.nodes_with_copy_source_count -= 1
378 378 }
379 379 if was_tracked {
380 380 self.for_each_ancestor_node(filename, |node| {
381 381 node.tracked_descendants_count -= 1
382 382 })
383 383 }
384 384 Ok(had_entry)
385 385 } else {
386 386 Ok(false)
387 387 }
388 388 }
389 389
390 390 fn clear_ambiguous_times(&mut self, filenames: Vec<HgPathBuf>, now: i32) {
391 391 for filename in filenames {
392 392 if let Some(node) = Self::get_node_mut(&mut self.root, &filename) {
393 393 if let Some(entry) = node.entry.as_mut() {
394 394 clear_ambiguous_mtime(entry, now);
395 395 }
396 396 }
397 397 }
398 398 }
399 399
400 fn non_normal_entries_contains(&mut self, _key: &HgPath) -> bool {
401 todo!()
400 fn non_normal_entries_contains(&mut self, key: &HgPath) -> bool {
401 self.get_node(key)
402 .and_then(|node| node.entry.as_ref())
403 .map_or(false, DirstateEntry::is_non_normal)
402 404 }
403 405
404 fn non_normal_entries_remove(&mut self, _key: &HgPath) -> bool {
405 todo!()
406 fn non_normal_entries_remove(&mut self, _key: &HgPath) {
407 // Do nothing, this `DirstateMap` does not have a separate "non normal
408 // entries" set that need to be kept up to date
406 409 }
407 410
408 411 fn non_normal_or_other_parent_paths(
409 412 &mut self,
410 413 ) -> Box<dyn Iterator<Item = &HgPathBuf> + '_> {
411 todo!()
414 Box::new(self.iter_nodes().filter_map(|(path, node)| {
415 node.entry
416 .as_ref()
417 .filter(|entry| {
418 entry.is_non_normal() || entry.is_from_other_parent()
419 })
420 .map(|_| path.full_path())
421 }))
412 422 }
413 423
414 424 fn set_non_normal_other_parent_entries(&mut self, _force: bool) {
415 todo!()
425 // Do nothing, this `DirstateMap` does not have a separate "non normal
426 // entries" and "from other parent" sets that need to be recomputed
416 427 }
417 428
418 429 fn iter_non_normal_paths(
419 430 &mut self,
420 431 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
421 todo!()
432 self.iter_non_normal_paths_panic()
422 433 }
423 434
424 435 fn iter_non_normal_paths_panic(
425 436 &self,
426 437 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
427 todo!()
438 Box::new(self.iter_nodes().filter_map(|(path, node)| {
439 node.entry
440 .as_ref()
441 .filter(|entry| entry.is_non_normal())
442 .map(|_| path.full_path())
443 }))
428 444 }
429 445
430 446 fn iter_other_parent_paths(
431 447 &mut self,
432 448 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
433 todo!()
449 Box::new(self.iter_nodes().filter_map(|(path, node)| {
450 node.entry
451 .as_ref()
452 .filter(|entry| entry.is_from_other_parent())
453 .map(|_| path.full_path())
454 }))
434 455 }
435 456
436 457 fn has_tracked_dir(
437 458 &mut self,
438 459 directory: &HgPath,
439 460 ) -> Result<bool, DirstateMapError> {
440 461 if let Some(node) = self.get_node(directory) {
441 462 // A node without a `DirstateEntry` was created to hold child
442 463 // nodes, and is therefore a directory.
443 464 Ok(node.entry.is_none() && node.tracked_descendants_count > 0)
444 465 } else {
445 466 Ok(false)
446 467 }
447 468 }
448 469
449 470 fn has_dir(
450 471 &mut self,
451 472 directory: &HgPath,
452 473 ) -> Result<bool, DirstateMapError> {
453 474 if let Some(node) = self.get_node(directory) {
454 475 // A node without a `DirstateEntry` was created to hold child
455 476 // nodes, and is therefore a directory.
456 477 Ok(node.entry.is_none())
457 478 } else {
458 479 Ok(false)
459 480 }
460 481 }
461 482
462 483 fn parents(
463 484 &mut self,
464 485 file_contents: &[u8],
465 486 ) -> Result<&DirstateParents, DirstateError> {
466 487 if self.parents.is_none() {
467 488 let parents = if !file_contents.is_empty() {
468 489 parse_dirstate_parents(file_contents)?.clone()
469 490 } else {
470 491 DirstateParents {
471 492 p1: NULL_NODE,
472 493 p2: NULL_NODE,
473 494 }
474 495 };
475 496 self.parents = Some(parents);
476 497 }
477 498 Ok(self.parents.as_ref().unwrap())
478 499 }
479 500
480 501 fn set_parents(&mut self, parents: &DirstateParents) {
481 502 self.parents = Some(parents.clone());
482 503 self.dirty_parents = true;
483 504 }
484 505
485 506 fn read<'a>(
486 507 &mut self,
487 508 file_contents: &'a [u8],
488 509 ) -> Result<Option<&'a DirstateParents>, DirstateError> {
489 510 if file_contents.is_empty() {
490 511 return Ok(None);
491 512 }
492 513
493 514 let parents = parse_dirstate_entries(
494 515 file_contents,
495 516 |path, entry, copy_source| {
496 517 self.add_file_node(
497 518 path,
498 519 *entry,
499 520 Some(copy_source.map(HgPath::to_owned)),
500 521 )
501 522 },
502 523 )?;
503 524
504 525 if !self.dirty_parents {
505 526 self.set_parents(parents);
506 527 }
507 528
508 529 Ok(Some(parents))
509 530 }
510 531
511 532 fn pack(
512 533 &mut self,
513 534 parents: DirstateParents,
514 535 now: Timestamp,
515 536 ) -> Result<Vec<u8>, DirstateError> {
516 537 // Optizimation (to be measured?): pre-compute size to avoid `Vec`
517 538 // reallocations
518 539 let mut size = parents.as_bytes().len();
519 540 for (path, node) in self.iter_nodes() {
520 541 if node.entry.is_some() {
521 542 size += packed_entry_size(
522 543 path.full_path(),
523 544 node.copy_source.as_ref(),
524 545 )
525 546 }
526 547 }
527 548
528 549 let mut packed = Vec::with_capacity(size);
529 550 packed.extend(parents.as_bytes());
530 551
531 552 let now: i32 = now.0.try_into().expect("time overflow");
532 553 for (path, opt_entry, copy_source) in self.iter_node_data_mut() {
533 554 if let Some(entry) = opt_entry {
534 555 clear_ambiguous_mtime(entry, now);
535 556 pack_entry(
536 557 path.full_path(),
537 558 entry,
538 559 copy_source.as_ref(),
539 560 &mut packed,
540 561 );
541 562 }
542 563 }
543 564 self.dirty_parents = false;
544 565 Ok(packed)
545 566 }
546 567
547 568 fn build_file_fold_map(&mut self) -> &FastHashMap<HgPathBuf, HgPathBuf> {
548 569 todo!()
549 570 }
550 571
551 572 fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> {
552 573 // Do nothing, this `DirstateMap` does not a separate `all_dirs` that
553 574 // needs to be recomputed
554 575 Ok(())
555 576 }
556 577
557 578 fn set_dirs(&mut self) -> Result<(), DirstateMapError> {
558 579 // Do nothing, this `DirstateMap` does not a separate `dirs` that needs
559 580 // to be recomputed
560 581 Ok(())
561 582 }
562 583
563 584 fn status<'a>(
564 585 &'a self,
565 586 _matcher: &'a (dyn Matcher + Sync),
566 587 _root_dir: PathBuf,
567 588 _ignore_files: Vec<PathBuf>,
568 589 _options: StatusOptions,
569 590 ) -> Result<
570 591 (
571 592 (Vec<HgPathCow<'a>>, DirstateStatus<'a>),
572 593 Vec<PatternFileWarning>,
573 594 ),
574 595 StatusError,
575 596 > {
576 597 todo!()
577 598 }
578 599
579 600 fn copy_map_len(&self) -> usize {
580 601 self.nodes_with_copy_source_count
581 602 }
582 603
583 604 fn copy_map_iter(&self) -> CopyMapIter<'_> {
584 605 Box::new(self.iter_nodes().filter_map(|(path, node)| {
585 606 node.copy_source
586 607 .as_ref()
587 608 .map(|copy_source| (path.full_path(), copy_source))
588 609 }))
589 610 }
590 611
591 612 fn copy_map_contains_key(&self, key: &HgPath) -> bool {
592 613 if let Some(node) = self.get_node(key) {
593 614 node.copy_source.is_some()
594 615 } else {
595 616 false
596 617 }
597 618 }
598 619
599 620 fn copy_map_get(&self, key: &HgPath) -> Option<&HgPathBuf> {
600 621 self.get_node(key)?.copy_source.as_ref()
601 622 }
602 623
603 624 fn copy_map_remove(&mut self, key: &HgPath) -> Option<HgPathBuf> {
604 625 let count = &mut self.nodes_with_copy_source_count;
605 626 Self::get_node_mut(&mut self.root, key).and_then(|node| {
606 627 if node.copy_source.is_some() {
607 628 *count -= 1
608 629 }
609 630 node.copy_source.take()
610 631 })
611 632 }
612 633
613 634 fn copy_map_insert(
614 635 &mut self,
615 636 key: HgPathBuf,
616 637 value: HgPathBuf,
617 638 ) -> Option<HgPathBuf> {
618 639 let node = Self::get_or_insert_node(&mut self.root, &key);
619 640 if node.copy_source.is_none() {
620 641 self.nodes_with_copy_source_count += 1
621 642 }
622 643 node.copy_source.replace(value)
623 644 }
624 645
625 646 fn len(&self) -> usize {
626 647 self.nodes_with_entry_count
627 648 }
628 649
629 650 fn contains_key(&self, key: &HgPath) -> bool {
630 651 self.get(key).is_some()
631 652 }
632 653
633 654 fn get(&self, key: &HgPath) -> Option<&DirstateEntry> {
634 655 self.get_node(key)?.entry.as_ref()
635 656 }
636 657
637 658 fn iter(&self) -> StateMapIter<'_> {
638 659 Box::new(self.iter_nodes().filter_map(|(path, node)| {
639 660 node.entry.as_ref().map(|entry| (path.full_path(), entry))
640 661 }))
641 662 }
642 663 }
@@ -1,333 +1,333 b''
1 1 use std::path::PathBuf;
2 2
3 3 use crate::dirstate::parsers::Timestamp;
4 4 use crate::matchers::Matcher;
5 5 use crate::utils::hg_path::{HgPath, HgPathBuf};
6 6 use crate::CopyMapIter;
7 7 use crate::DirstateEntry;
8 8 use crate::DirstateError;
9 9 use crate::DirstateMap;
10 10 use crate::DirstateMapError;
11 11 use crate::DirstateParents;
12 12 use crate::DirstateStatus;
13 13 use crate::EntryState;
14 14 use crate::FastHashMap;
15 15 use crate::HgPathCow;
16 16 use crate::PatternFileWarning;
17 17 use crate::StateMapIter;
18 18 use crate::StatusError;
19 19 use crate::StatusOptions;
20 20
21 21 pub trait DirstateMapMethods {
22 22 fn clear(&mut self);
23 23
24 24 fn add_file(
25 25 &mut self,
26 26 filename: &HgPath,
27 27 old_state: EntryState,
28 28 entry: DirstateEntry,
29 29 ) -> Result<(), DirstateMapError>;
30 30
31 31 fn remove_file(
32 32 &mut self,
33 33 filename: &HgPath,
34 34 old_state: EntryState,
35 35 size: i32,
36 36 ) -> Result<(), DirstateMapError>;
37 37
38 38 fn drop_file(
39 39 &mut self,
40 40 filename: &HgPath,
41 41 old_state: EntryState,
42 42 ) -> Result<bool, DirstateMapError>;
43 43
44 44 fn clear_ambiguous_times(&mut self, filenames: Vec<HgPathBuf>, now: i32);
45 45
46 46 fn non_normal_entries_contains(&mut self, key: &HgPath) -> bool;
47 47
48 fn non_normal_entries_remove(&mut self, key: &HgPath) -> bool;
48 fn non_normal_entries_remove(&mut self, key: &HgPath);
49 49
50 50 fn non_normal_or_other_parent_paths(
51 51 &mut self,
52 52 ) -> Box<dyn Iterator<Item = &HgPathBuf> + '_>;
53 53
54 54 fn set_non_normal_other_parent_entries(&mut self, force: bool);
55 55
56 56 fn iter_non_normal_paths(
57 57 &mut self,
58 58 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_>;
59 59
60 60 fn iter_non_normal_paths_panic(
61 61 &self,
62 62 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_>;
63 63
64 64 fn iter_other_parent_paths(
65 65 &mut self,
66 66 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_>;
67 67
68 68 fn has_tracked_dir(
69 69 &mut self,
70 70 directory: &HgPath,
71 71 ) -> Result<bool, DirstateMapError>;
72 72
73 73 fn has_dir(
74 74 &mut self,
75 75 directory: &HgPath,
76 76 ) -> Result<bool, DirstateMapError>;
77 77
78 78 fn parents(
79 79 &mut self,
80 80 file_contents: &[u8],
81 81 ) -> Result<&DirstateParents, DirstateError>;
82 82
83 83 fn set_parents(&mut self, parents: &DirstateParents);
84 84
85 85 fn read<'a>(
86 86 &mut self,
87 87 file_contents: &'a [u8],
88 88 ) -> Result<Option<&'a DirstateParents>, DirstateError>;
89 89
90 90 fn pack(
91 91 &mut self,
92 92 parents: DirstateParents,
93 93 now: Timestamp,
94 94 ) -> Result<Vec<u8>, DirstateError>;
95 95
96 96 fn build_file_fold_map(&mut self) -> &FastHashMap<HgPathBuf, HgPathBuf>;
97 97
98 98 fn set_all_dirs(&mut self) -> Result<(), DirstateMapError>;
99 99
100 100 fn set_dirs(&mut self) -> Result<(), DirstateMapError>;
101 101
102 102 fn status<'a>(
103 103 &'a self,
104 104 matcher: &'a (dyn Matcher + Sync),
105 105 root_dir: PathBuf,
106 106 ignore_files: Vec<PathBuf>,
107 107 options: StatusOptions,
108 108 ) -> Result<
109 109 (
110 110 (Vec<HgPathCow<'a>>, DirstateStatus<'a>),
111 111 Vec<PatternFileWarning>,
112 112 ),
113 113 StatusError,
114 114 >;
115 115
116 116 fn copy_map_len(&self) -> usize;
117 117
118 118 fn copy_map_iter(&self) -> CopyMapIter<'_>;
119 119
120 120 fn copy_map_contains_key(&self, key: &HgPath) -> bool;
121 121
122 122 fn copy_map_get(&self, key: &HgPath) -> Option<&HgPathBuf>;
123 123
124 124 fn copy_map_remove(&mut self, key: &HgPath) -> Option<HgPathBuf>;
125 125
126 126 fn copy_map_insert(
127 127 &mut self,
128 128 key: HgPathBuf,
129 129 value: HgPathBuf,
130 130 ) -> Option<HgPathBuf>;
131 131
132 132 fn len(&self) -> usize;
133 133
134 134 fn contains_key(&self, key: &HgPath) -> bool;
135 135
136 136 fn get(&self, key: &HgPath) -> Option<&DirstateEntry>;
137 137
138 138 fn iter(&self) -> StateMapIter<'_>;
139 139 }
140 140
141 141 impl DirstateMapMethods for DirstateMap {
142 142 fn clear(&mut self) {
143 143 self.clear()
144 144 }
145 145
146 146 fn add_file(
147 147 &mut self,
148 148 filename: &HgPath,
149 149 old_state: EntryState,
150 150 entry: DirstateEntry,
151 151 ) -> Result<(), DirstateMapError> {
152 152 self.add_file(filename, old_state, entry)
153 153 }
154 154
155 155 fn remove_file(
156 156 &mut self,
157 157 filename: &HgPath,
158 158 old_state: EntryState,
159 159 size: i32,
160 160 ) -> Result<(), DirstateMapError> {
161 161 self.remove_file(filename, old_state, size)
162 162 }
163 163
164 164 fn drop_file(
165 165 &mut self,
166 166 filename: &HgPath,
167 167 old_state: EntryState,
168 168 ) -> Result<bool, DirstateMapError> {
169 169 self.drop_file(filename, old_state)
170 170 }
171 171
172 172 fn clear_ambiguous_times(&mut self, filenames: Vec<HgPathBuf>, now: i32) {
173 173 self.clear_ambiguous_times(filenames, now)
174 174 }
175 175
176 176 fn non_normal_entries_contains(&mut self, key: &HgPath) -> bool {
177 177 let (non_normal, _other_parent) =
178 178 self.get_non_normal_other_parent_entries();
179 179 non_normal.contains(key)
180 180 }
181 181
182 fn non_normal_entries_remove(&mut self, key: &HgPath) -> bool {
182 fn non_normal_entries_remove(&mut self, key: &HgPath) {
183 183 self.non_normal_entries_remove(key)
184 184 }
185 185
186 186 fn non_normal_or_other_parent_paths(
187 187 &mut self,
188 188 ) -> Box<dyn Iterator<Item = &HgPathBuf> + '_> {
189 189 let (non_normal, other_parent) =
190 190 self.get_non_normal_other_parent_entries();
191 191 Box::new(non_normal.union(other_parent))
192 192 }
193 193
194 194 fn set_non_normal_other_parent_entries(&mut self, force: bool) {
195 195 self.set_non_normal_other_parent_entries(force)
196 196 }
197 197
198 198 fn iter_non_normal_paths(
199 199 &mut self,
200 200 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
201 201 let (non_normal, _other_parent) =
202 202 self.get_non_normal_other_parent_entries();
203 203 Box::new(non_normal.iter())
204 204 }
205 205
206 206 fn iter_non_normal_paths_panic(
207 207 &self,
208 208 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
209 209 let (non_normal, _other_parent) =
210 210 self.get_non_normal_other_parent_entries_panic();
211 211 Box::new(non_normal.iter())
212 212 }
213 213
214 214 fn iter_other_parent_paths(
215 215 &mut self,
216 216 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
217 217 let (_non_normal, other_parent) =
218 218 self.get_non_normal_other_parent_entries();
219 219 Box::new(other_parent.iter())
220 220 }
221 221
222 222 fn has_tracked_dir(
223 223 &mut self,
224 224 directory: &HgPath,
225 225 ) -> Result<bool, DirstateMapError> {
226 226 self.has_tracked_dir(directory)
227 227 }
228 228
229 229 fn has_dir(
230 230 &mut self,
231 231 directory: &HgPath,
232 232 ) -> Result<bool, DirstateMapError> {
233 233 self.has_dir(directory)
234 234 }
235 235
236 236 fn parents(
237 237 &mut self,
238 238 file_contents: &[u8],
239 239 ) -> Result<&DirstateParents, DirstateError> {
240 240 self.parents(file_contents)
241 241 }
242 242
243 243 fn set_parents(&mut self, parents: &DirstateParents) {
244 244 self.set_parents(parents)
245 245 }
246 246
247 247 fn read<'a>(
248 248 &mut self,
249 249 file_contents: &'a [u8],
250 250 ) -> Result<Option<&'a DirstateParents>, DirstateError> {
251 251 self.read(file_contents)
252 252 }
253 253
254 254 fn pack(
255 255 &mut self,
256 256 parents: DirstateParents,
257 257 now: Timestamp,
258 258 ) -> Result<Vec<u8>, DirstateError> {
259 259 self.pack(parents, now)
260 260 }
261 261
262 262 fn build_file_fold_map(&mut self) -> &FastHashMap<HgPathBuf, HgPathBuf> {
263 263 self.build_file_fold_map()
264 264 }
265 265
266 266 fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> {
267 267 self.set_all_dirs()
268 268 }
269 269
270 270 fn set_dirs(&mut self) -> Result<(), DirstateMapError> {
271 271 self.set_dirs()
272 272 }
273 273
274 274 fn status<'a>(
275 275 &'a self,
276 276 matcher: &'a (dyn Matcher + Sync),
277 277 root_dir: PathBuf,
278 278 ignore_files: Vec<PathBuf>,
279 279 options: StatusOptions,
280 280 ) -> Result<
281 281 (
282 282 (Vec<HgPathCow<'a>>, DirstateStatus<'a>),
283 283 Vec<PatternFileWarning>,
284 284 ),
285 285 StatusError,
286 286 > {
287 287 crate::status(self, matcher, root_dir, ignore_files, options)
288 288 }
289 289
290 290 fn copy_map_len(&self) -> usize {
291 291 self.copy_map.len()
292 292 }
293 293
294 294 fn copy_map_iter(&self) -> CopyMapIter<'_> {
295 295 Box::new(self.copy_map.iter())
296 296 }
297 297
298 298 fn copy_map_contains_key(&self, key: &HgPath) -> bool {
299 299 self.copy_map.contains_key(key)
300 300 }
301 301
302 302 fn copy_map_get(&self, key: &HgPath) -> Option<&HgPathBuf> {
303 303 self.copy_map.get(key)
304 304 }
305 305
306 306 fn copy_map_remove(&mut self, key: &HgPath) -> Option<HgPathBuf> {
307 307 self.copy_map.remove(key)
308 308 }
309 309
310 310 fn copy_map_insert(
311 311 &mut self,
312 312 key: HgPathBuf,
313 313 value: HgPathBuf,
314 314 ) -> Option<HgPathBuf> {
315 315 self.copy_map.insert(key, value)
316 316 }
317 317
318 318 fn len(&self) -> usize {
319 319 (&**self).len()
320 320 }
321 321
322 322 fn contains_key(&self, key: &HgPath) -> bool {
323 323 (&**self).contains_key(key)
324 324 }
325 325
326 326 fn get(&self, key: &HgPath) -> Option<&DirstateEntry> {
327 327 (&**self).get(key)
328 328 }
329 329
330 330 fn iter(&self) -> StateMapIter<'_> {
331 331 Box::new((&**self).iter())
332 332 }
333 333 }
General Comments 0
You need to be logged in to leave comments. Login now