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