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