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