##// END OF EJS Templates
dirstate-tree: Add has_dir and has_tracked_dir...
Simon Sapin -
r47876:52906934 default
parent child Browse files
Show More
@@ -1,97 +1,107 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 #[derive(BytesCast)]
37 #[derive(BytesCast)]
38 #[repr(C)]
38 #[repr(C)]
39 struct RawEntry {
39 struct RawEntry {
40 state: u8,
40 state: u8,
41 mode: unaligned::I32Be,
41 mode: unaligned::I32Be,
42 size: unaligned::I32Be,
42 size: unaligned::I32Be,
43 mtime: unaligned::I32Be,
43 mtime: unaligned::I32Be,
44 length: unaligned::I32Be,
44 length: unaligned::I32Be,
45 }
45 }
46
46
47 /// A `DirstateEntry` with a size of `-2` means that it was merged from the
47 /// 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
48 /// other parent. This allows revert to pick the right status back during a
49 /// merge.
49 /// merge.
50 pub const SIZE_FROM_OTHER_PARENT: i32 = -2;
50 pub const SIZE_FROM_OTHER_PARENT: i32 = -2;
51
51
52 pub type StateMap = FastHashMap<HgPathBuf, DirstateEntry>;
52 pub type StateMap = FastHashMap<HgPathBuf, DirstateEntry>;
53 pub type StateMapIter<'a> =
53 pub type StateMapIter<'a> =
54 Box<dyn Iterator<Item = (&'a HgPathBuf, &'a DirstateEntry)> + Send + 'a>;
54 Box<dyn Iterator<Item = (&'a HgPathBuf, &'a DirstateEntry)> + Send + 'a>;
55
55
56 pub type CopyMap = FastHashMap<HgPathBuf, HgPathBuf>;
56 pub type CopyMap = FastHashMap<HgPathBuf, HgPathBuf>;
57 pub type CopyMapIter<'a> =
57 pub type CopyMapIter<'a> =
58 Box<dyn Iterator<Item = (&'a HgPathBuf, &'a HgPathBuf)> + Send + 'a>;
58 Box<dyn Iterator<Item = (&'a HgPathBuf, &'a HgPathBuf)> + Send + 'a>;
59
59
60 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
60 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
61 pub enum EntryState {
61 pub enum EntryState {
62 Normal,
62 Normal,
63 Added,
63 Added,
64 Removed,
64 Removed,
65 Merged,
65 Merged,
66 Unknown,
66 Unknown,
67 }
67 }
68
68
69 impl EntryState {
70 pub fn is_tracked(self) -> bool {
71 use EntryState::*;
72 match self {
73 Normal | Added | Merged => true,
74 Removed | Unknown => false,
75 }
76 }
77 }
78
69 impl TryFrom<u8> for EntryState {
79 impl TryFrom<u8> for EntryState {
70 type Error = HgError;
80 type Error = HgError;
71
81
72 fn try_from(value: u8) -> Result<Self, Self::Error> {
82 fn try_from(value: u8) -> Result<Self, Self::Error> {
73 match value {
83 match value {
74 b'n' => Ok(EntryState::Normal),
84 b'n' => Ok(EntryState::Normal),
75 b'a' => Ok(EntryState::Added),
85 b'a' => Ok(EntryState::Added),
76 b'r' => Ok(EntryState::Removed),
86 b'r' => Ok(EntryState::Removed),
77 b'm' => Ok(EntryState::Merged),
87 b'm' => Ok(EntryState::Merged),
78 b'?' => Ok(EntryState::Unknown),
88 b'?' => Ok(EntryState::Unknown),
79 _ => Err(HgError::CorruptedRepository(format!(
89 _ => Err(HgError::CorruptedRepository(format!(
80 "Incorrect dirstate entry state {}",
90 "Incorrect dirstate entry state {}",
81 value
91 value
82 ))),
92 ))),
83 }
93 }
84 }
94 }
85 }
95 }
86
96
87 impl Into<u8> for EntryState {
97 impl Into<u8> for EntryState {
88 fn into(self) -> u8 {
98 fn into(self) -> u8 {
89 match self {
99 match self {
90 EntryState::Normal => b'n',
100 EntryState::Normal => b'n',
91 EntryState::Added => b'a',
101 EntryState::Added => b'a',
92 EntryState::Removed => b'r',
102 EntryState::Removed => b'r',
93 EntryState::Merged => b'm',
103 EntryState::Merged => b'm',
94 EntryState::Unknown => b'?',
104 EntryState::Unknown => b'?',
95 }
105 }
96 }
106 }
97 }
107 }
@@ -1,526 +1,609 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 #[derive(Default)]
50 #[derive(Default)]
50 struct Node {
51 struct Node {
52 /// `None` for directories
51 entry: Option<DirstateEntry>,
53 entry: Option<DirstateEntry>,
54
52 copy_source: Option<HgPathBuf>,
55 copy_source: Option<HgPathBuf>,
56
53 children: ChildNodes,
57 children: ChildNodes,
58
59 /// How many (non-inclusive) descendants of this node are tracked files
60 tracked_descendants_count: usize,
61 }
62
63 impl Node {
64 /// Whether this node has a `DirstateEntry` with `.state.is_tracked()`
65 fn is_tracked_file(&self) -> bool {
66 if let Some(entry) = &self.entry {
67 entry.state.is_tracked()
68 } else {
69 false
70 }
71 }
54 }
72 }
55
73
56 /// `(full_path, entry, copy_source)`
74 /// `(full_path, entry, copy_source)`
57 type NodeDataMut<'a> = (
75 type NodeDataMut<'a> = (
58 &'a WithBasename<HgPathBuf>,
76 &'a WithBasename<HgPathBuf>,
59 &'a mut Option<DirstateEntry>,
77 &'a mut Option<DirstateEntry>,
60 &'a mut Option<HgPathBuf>,
78 &'a mut Option<HgPathBuf>,
61 );
79 );
62
80
63 impl DirstateMap {
81 impl DirstateMap {
64 pub fn new() -> Self {
82 pub fn new() -> Self {
65 Self {
83 Self {
66 parents: None,
84 parents: None,
67 dirty_parents: false,
85 dirty_parents: false,
68 root: ChildNodes::new(),
86 root: ChildNodes::new(),
69 nodes_with_entry_count: 0,
87 nodes_with_entry_count: 0,
70 nodes_with_copy_source_count: 0,
88 nodes_with_copy_source_count: 0,
71 }
89 }
72 }
90 }
73
91
74 fn get_node(&self, path: &HgPath) -> Option<&Node> {
92 fn get_node(&self, path: &HgPath) -> Option<&Node> {
75 let mut children = &self.root;
93 let mut children = &self.root;
76 let mut components = path.components();
94 let mut components = path.components();
77 let mut component =
95 let mut component =
78 components.next().expect("expected at least one components");
96 components.next().expect("expected at least one components");
79 loop {
97 loop {
80 let child = children.get(component)?;
98 let child = children.get(component)?;
81 if let Some(next_component) = components.next() {
99 if let Some(next_component) = components.next() {
82 component = next_component;
100 component = next_component;
83 children = &child.children;
101 children = &child.children;
84 } else {
102 } else {
85 return Some(child);
103 return Some(child);
86 }
104 }
87 }
105 }
88 }
106 }
89
107
108 /// Returns a mutable reference to the node at `path` if it exists
109 ///
90 /// 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
91 /// other fields while the returned borrow is still valid
111 /// other fields while the returned borrow is still valid
92 fn get_node_mut<'tree>(
112 fn get_node_mut<'tree>(
93 root: &'tree mut ChildNodes,
113 root: &'tree mut ChildNodes,
94 path: &HgPath,
114 path: &HgPath,
95 ) -> Option<&'tree mut Node> {
115 ) -> Option<&'tree mut Node> {
116 Self::each_and_get(root, path, |_| {})
117 }
118
119 /// Call `each` for each ancestor node of the one at `path` (not including
120 /// that node itself), starting from nearest the root.
121 ///
122 /// Panics (possibly after some calls to `each`) if there is no node at
123 /// `path`.
124 fn for_each_ancestor_node<'tree>(
125 &mut self,
126 path: &HgPath,
127 each: impl FnMut(&mut Node),
128 ) {
129 let parent = path.parent();
130 if !parent.is_empty() {
131 Self::each_and_get(&mut self.root, parent, each)
132 .expect("missing dirstate node");
133 }
134 }
135
136 /// Common implementation detail of `get_node_mut` and
137 /// `for_each_ancestor_node`
138 fn each_and_get<'tree>(
139 root: &'tree mut ChildNodes,
140 path: &HgPath,
141 mut each: impl FnMut(&mut Node),
142 ) -> Option<&'tree mut Node> {
96 let mut children = root;
143 let mut children = root;
97 let mut components = path.components();
144 let mut components = path.components();
98 let mut component =
145 let mut component =
99 components.next().expect("expected at least one components");
146 components.next().expect("expected at least one components");
100 loop {
147 loop {
101 let child = children.get_mut(component)?;
148 let child = children.get_mut(component)?;
149 each(child);
102 if let Some(next_component) = components.next() {
150 if let Some(next_component) = components.next() {
103 component = next_component;
151 component = next_component;
104 children = &mut child.children;
152 children = &mut child.children;
105 } else {
153 } else {
106 return Some(child);
154 return Some(child);
107 }
155 }
108 }
156 }
109 }
157 }
110
158
111 fn get_or_insert_node<'tree>(
159 fn get_or_insert_node<'tree>(
112 root: &'tree mut ChildNodes,
160 root: &'tree mut ChildNodes,
113 path: &HgPath,
161 path: &HgPath,
114 ) -> &'tree mut Node {
162 ) -> &'tree mut Node {
115 let mut child_nodes = root;
163 let mut child_nodes = root;
116 let mut inclusive_ancestor_paths =
164 let mut inclusive_ancestor_paths =
117 WithBasename::inclusive_ancestors_of(path);
165 WithBasename::inclusive_ancestors_of(path);
118 let mut ancestor_path = inclusive_ancestor_paths
166 let mut ancestor_path = inclusive_ancestor_paths
119 .next()
167 .next()
120 .expect("expected at least one inclusive ancestor");
168 .expect("expected at least one inclusive ancestor");
121 loop {
169 loop {
122 // TODO: can we avoid double lookup in all cases without allocating
170 // TODO: can we avoid double lookup in all cases without allocating
123 // 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?
124 let child_node =
172 let child_node =
125 if child_nodes.contains_key(ancestor_path.base_name()) {
173 if child_nodes.contains_key(ancestor_path.base_name()) {
126 child_nodes.get_mut(ancestor_path.base_name()).unwrap()
174 child_nodes.get_mut(ancestor_path.base_name()).unwrap()
127 } else {
175 } else {
128 // This is always a vacant entry, using `.entry()` lets us
176 // This is always a vacant entry, using `.entry()` lets us
129 // return a `&mut Node` of the newly-inserted node without
177 // return a `&mut Node` of the newly-inserted node without
130 // yet another lookup. `BTreeMap::insert` doesn’t do this.
178 // yet another lookup. `BTreeMap::insert` doesn’t do this.
131 child_nodes.entry(ancestor_path.to_owned()).or_default()
179 child_nodes.entry(ancestor_path.to_owned()).or_default()
132 };
180 };
133 if let Some(next) = inclusive_ancestor_paths.next() {
181 if let Some(next) = inclusive_ancestor_paths.next() {
134 ancestor_path = next;
182 ancestor_path = next;
135 child_nodes = &mut child_node.children;
183 child_nodes = &mut child_node.children;
136 } else {
184 } else {
137 return child_node;
185 return child_node;
138 }
186 }
139 }
187 }
140 }
188 }
141
189
142 /// The meaning of `new_copy_source` is:
190 /// The meaning of `new_copy_source` is:
143 ///
191 ///
144 /// * `Some(Some(x))`: set `Node::copy_source` to `Some(x)`
192 /// * `Some(Some(x))`: set `Node::copy_source` to `Some(x)`
145 /// * `Some(None)`: set `Node::copy_source` to `None`
193 /// * `Some(None)`: set `Node::copy_source` to `None`
146 /// * `None`: leave `Node::copy_source` unchanged
194 /// * `None`: leave `Node::copy_source` unchanged
147 fn add_file_node(
195 fn add_file_node(
148 &mut self,
196 &mut self,
149 path: &HgPath,
197 path: &HgPath,
150 new_entry: DirstateEntry,
198 new_entry: DirstateEntry,
151 new_copy_source: Option<Option<HgPathBuf>>,
199 new_copy_source: Option<Option<HgPathBuf>>,
152 ) {
200 ) {
153 let node = Self::get_or_insert_node(&mut self.root, path);
201 let node = Self::get_or_insert_node(&mut self.root, path);
154 if node.entry.is_none() {
202 if node.entry.is_none() {
155 self.nodes_with_entry_count += 1
203 self.nodes_with_entry_count += 1
156 }
204 }
157 if let Some(source) = &new_copy_source {
205 if let Some(source) = &new_copy_source {
158 if node.copy_source.is_none() && source.is_some() {
206 if node.copy_source.is_none() && source.is_some() {
159 self.nodes_with_copy_source_count += 1
207 self.nodes_with_copy_source_count += 1
160 }
208 }
161 if node.copy_source.is_some() && source.is_none() {
209 if node.copy_source.is_some() && source.is_none() {
162 self.nodes_with_copy_source_count -= 1
210 self.nodes_with_copy_source_count -= 1
163 }
211 }
164 }
212 }
213 let tracked_count_increment =
214 match (node.is_tracked_file(), new_entry.state.is_tracked()) {
215 (false, true) => 1,
216 (true, false) => -1,
217 _ => 0,
218 };
219
165 node.entry = Some(new_entry);
220 node.entry = Some(new_entry);
166 if let Some(source) = new_copy_source {
221 if let Some(source) = new_copy_source {
167 node.copy_source = source
222 node.copy_source = source
168 }
223 }
224 // Borrow of `self.root` through `node` ends here
225
226 match tracked_count_increment {
227 1 => self.for_each_ancestor_node(path, |node| {
228 node.tracked_descendants_count += 1
229 }),
230 // We can’t use `+= -1` because the counter is unsigned
231 -1 => self.for_each_ancestor_node(path, |node| {
232 node.tracked_descendants_count -= 1
233 }),
234 _ => {}
235 }
169 }
236 }
170
237
171 fn iter_nodes<'a>(
238 fn iter_nodes<'a>(
172 &'a self,
239 &'a self,
173 ) -> impl Iterator<Item = (&'a WithBasename<HgPathBuf>, &'a Node)> + 'a
240 ) -> impl Iterator<Item = (&'a WithBasename<HgPathBuf>, &'a Node)> + 'a
174 {
241 {
175 // Depth first tree traversal.
242 // Depth first tree traversal.
176 //
243 //
177 // If we could afford internal iteration and recursion,
244 // If we could afford internal iteration and recursion,
178 // this would look like:
245 // this would look like:
179 //
246 //
180 // ```
247 // ```
181 // fn traverse_children(
248 // fn traverse_children(
182 // children: &ChildNodes,
249 // children: &ChildNodes,
183 // each: &mut impl FnMut(&Node),
250 // each: &mut impl FnMut(&Node),
184 // ) {
251 // ) {
185 // for child in children.values() {
252 // for child in children.values() {
186 // traverse_children(&child.children, each);
253 // traverse_children(&child.children, each);
187 // each(child);
254 // each(child);
188 // }
255 // }
189 // }
256 // }
190 // ```
257 // ```
191 //
258 //
192 // 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
193 // call stack. Use an explicit stack instead:
260 // call stack. Use an explicit stack instead:
194 let mut stack = Vec::new();
261 let mut stack = Vec::new();
195 let mut iter = self.root.iter();
262 let mut iter = self.root.iter();
196 std::iter::from_fn(move || {
263 std::iter::from_fn(move || {
197 while let Some((key, child_node)) = iter.next() {
264 while let Some((key, child_node)) = iter.next() {
198 // Pseudo-recursion
265 // Pseudo-recursion
199 let new_iter = child_node.children.iter();
266 let new_iter = child_node.children.iter();
200 let old_iter = std::mem::replace(&mut iter, new_iter);
267 let old_iter = std::mem::replace(&mut iter, new_iter);
201 stack.push((key, child_node, old_iter));
268 stack.push((key, child_node, old_iter));
202 }
269 }
203 // Found the end of a `children.iter()` iterator.
270 // Found the end of a `children.iter()` iterator.
204 if let Some((key, child_node, next_iter)) = stack.pop() {
271 if let Some((key, child_node, next_iter)) = stack.pop() {
205 // "Return" from pseudo-recursion by restoring state from the
272 // "Return" from pseudo-recursion by restoring state from the
206 // explicit stack
273 // explicit stack
207 iter = next_iter;
274 iter = next_iter;
208
275
209 Some((key, child_node))
276 Some((key, child_node))
210 } else {
277 } else {
211 // Reached the bottom of the stack, we’re done
278 // Reached the bottom of the stack, we’re done
212 None
279 None
213 }
280 }
214 })
281 })
215 }
282 }
216
283
217 /// Mutable iterator for the `(entry, copy source)` of each node.
284 /// Mutable iterator for the `(entry, copy source)` of each node.
218 ///
285 ///
219 /// 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
220 /// with `-> impl Iterator<Item = &mut Node>` since child nodes are
287 /// with `-> impl Iterator<Item = &mut Node>` since child nodes are
221 /// reachable from their ancestor nodes, potentially creating multiple
288 /// reachable from their ancestor nodes, potentially creating multiple
222 /// `&mut` references to a given node.
289 /// `&mut` references to a given node.
223 fn iter_node_data_mut<'a>(
290 fn iter_node_data_mut<'a>(
224 &'a mut self,
291 &'a mut self,
225 ) -> impl Iterator<Item = NodeDataMut<'a>> + 'a {
292 ) -> impl Iterator<Item = NodeDataMut<'a>> + 'a {
226 // Explict stack for pseudo-recursion, see `iter_nodes` above.
293 // Explict stack for pseudo-recursion, see `iter_nodes` above.
227 let mut stack = Vec::new();
294 let mut stack = Vec::new();
228 let mut iter = self.root.iter_mut();
295 let mut iter = self.root.iter_mut();
229 std::iter::from_fn(move || {
296 std::iter::from_fn(move || {
230 while let Some((key, child_node)) = iter.next() {
297 while let Some((key, child_node)) = iter.next() {
231 // Pseudo-recursion
298 // Pseudo-recursion
232 let data =
299 let data =
233 (key, &mut child_node.entry, &mut child_node.copy_source);
300 (key, &mut child_node.entry, &mut child_node.copy_source);
234 let new_iter = child_node.children.iter_mut();
301 let new_iter = child_node.children.iter_mut();
235 let old_iter = std::mem::replace(&mut iter, new_iter);
302 let old_iter = std::mem::replace(&mut iter, new_iter);
236 stack.push((data, old_iter));
303 stack.push((data, old_iter));
237 }
304 }
238 // Found the end of a `children.values_mut()` iterator.
305 // Found the end of a `children.values_mut()` iterator.
239 if let Some((data, next_iter)) = stack.pop() {
306 if let Some((data, next_iter)) = stack.pop() {
240 // "Return" from pseudo-recursion by restoring state from the
307 // "Return" from pseudo-recursion by restoring state from the
241 // explicit stack
308 // explicit stack
242 iter = next_iter;
309 iter = next_iter;
243
310
244 Some(data)
311 Some(data)
245 } else {
312 } else {
246 // Reached the bottom of the stack, we’re done
313 // Reached the bottom of the stack, we’re done
247 None
314 None
248 }
315 }
249 })
316 })
250 }
317 }
251 }
318 }
252
319
253 impl super::dispatch::DirstateMapMethods for DirstateMap {
320 impl super::dispatch::DirstateMapMethods for DirstateMap {
254 fn clear(&mut self) {
321 fn clear(&mut self) {
255 self.set_parents(&DirstateParents {
322 self.set_parents(&DirstateParents {
256 p1: NULL_NODE,
323 p1: NULL_NODE,
257 p2: NULL_NODE,
324 p2: NULL_NODE,
258 });
325 });
259 self.root.clear();
326 self.root.clear();
260 self.nodes_with_entry_count = 0;
327 self.nodes_with_entry_count = 0;
261 self.nodes_with_copy_source_count = 0;
328 self.nodes_with_copy_source_count = 0;
262 }
329 }
263
330
264 fn add_file(
331 fn add_file(
265 &mut self,
332 &mut self,
266 _filename: &HgPath,
333 _filename: &HgPath,
267 _old_state: EntryState,
334 _old_state: EntryState,
268 _entry: DirstateEntry,
335 _entry: DirstateEntry,
269 ) -> Result<(), DirstateMapError> {
336 ) -> Result<(), DirstateMapError> {
270 todo!()
337 todo!()
271 }
338 }
272
339
273 fn remove_file(
340 fn remove_file(
274 &mut self,
341 &mut self,
275 _filename: &HgPath,
342 _filename: &HgPath,
276 _old_state: EntryState,
343 _old_state: EntryState,
277 _size: i32,
344 _size: i32,
278 ) -> Result<(), DirstateMapError> {
345 ) -> Result<(), DirstateMapError> {
279 todo!()
346 todo!()
280 }
347 }
281
348
282 fn drop_file(
349 fn drop_file(
283 &mut self,
350 &mut self,
284 _filename: &HgPath,
351 _filename: &HgPath,
285 _old_state: EntryState,
352 _old_state: EntryState,
286 ) -> Result<bool, DirstateMapError> {
353 ) -> Result<bool, DirstateMapError> {
287 todo!()
354 todo!()
288 }
355 }
289
356
290 fn clear_ambiguous_times(&mut self, filenames: Vec<HgPathBuf>, now: i32) {
357 fn clear_ambiguous_times(&mut self, filenames: Vec<HgPathBuf>, now: i32) {
291 for filename in filenames {
358 for filename in filenames {
292 if let Some(node) = Self::get_node_mut(&mut self.root, &filename) {
359 if let Some(node) = Self::get_node_mut(&mut self.root, &filename) {
293 if let Some(entry) = node.entry.as_mut() {
360 if let Some(entry) = node.entry.as_mut() {
294 clear_ambiguous_mtime(entry, now);
361 clear_ambiguous_mtime(entry, now);
295 }
362 }
296 }
363 }
297 }
364 }
298 }
365 }
299
366
300 fn non_normal_entries_contains(&mut self, _key: &HgPath) -> bool {
367 fn non_normal_entries_contains(&mut self, _key: &HgPath) -> bool {
301 todo!()
368 todo!()
302 }
369 }
303
370
304 fn non_normal_entries_remove(&mut self, _key: &HgPath) -> bool {
371 fn non_normal_entries_remove(&mut self, _key: &HgPath) -> bool {
305 todo!()
372 todo!()
306 }
373 }
307
374
308 fn non_normal_or_other_parent_paths(
375 fn non_normal_or_other_parent_paths(
309 &mut self,
376 &mut self,
310 ) -> Box<dyn Iterator<Item = &HgPathBuf> + '_> {
377 ) -> Box<dyn Iterator<Item = &HgPathBuf> + '_> {
311 todo!()
378 todo!()
312 }
379 }
313
380
314 fn set_non_normal_other_parent_entries(&mut self, _force: bool) {
381 fn set_non_normal_other_parent_entries(&mut self, _force: bool) {
315 todo!()
382 todo!()
316 }
383 }
317
384
318 fn iter_non_normal_paths(
385 fn iter_non_normal_paths(
319 &mut self,
386 &mut self,
320 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
387 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
321 todo!()
388 todo!()
322 }
389 }
323
390
324 fn iter_non_normal_paths_panic(
391 fn iter_non_normal_paths_panic(
325 &self,
392 &self,
326 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
393 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
327 todo!()
394 todo!()
328 }
395 }
329
396
330 fn iter_other_parent_paths(
397 fn iter_other_parent_paths(
331 &mut self,
398 &mut self,
332 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
399 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
333 todo!()
400 todo!()
334 }
401 }
335
402
336 fn has_tracked_dir(
403 fn has_tracked_dir(
337 &mut self,
404 &mut self,
338 _directory: &HgPath,
405 directory: &HgPath,
339 ) -> Result<bool, DirstateMapError> {
406 ) -> Result<bool, DirstateMapError> {
340 todo!()
407 if let Some(node) = self.get_node(directory) {
408 // A node without a `DirstateEntry` was created to hold child
409 // nodes, and is therefore a directory.
410 Ok(node.entry.is_none() && node.tracked_descendants_count > 0)
411 } else {
412 Ok(false)
413 }
341 }
414 }
342
415
343 fn has_dir(
416 fn has_dir(
344 &mut self,
417 &mut self,
345 _directory: &HgPath,
418 directory: &HgPath,
346 ) -> Result<bool, DirstateMapError> {
419 ) -> Result<bool, DirstateMapError> {
347 todo!()
420 if let Some(node) = self.get_node(directory) {
421 // A node without a `DirstateEntry` was created to hold child
422 // nodes, and is therefore a directory.
423 Ok(node.entry.is_none())
424 } else {
425 Ok(false)
426 }
348 }
427 }
349
428
350 fn parents(
429 fn parents(
351 &mut self,
430 &mut self,
352 file_contents: &[u8],
431 file_contents: &[u8],
353 ) -> Result<&DirstateParents, DirstateError> {
432 ) -> Result<&DirstateParents, DirstateError> {
354 if self.parents.is_none() {
433 if self.parents.is_none() {
355 let parents = if !file_contents.is_empty() {
434 let parents = if !file_contents.is_empty() {
356 parse_dirstate_parents(file_contents)?.clone()
435 parse_dirstate_parents(file_contents)?.clone()
357 } else {
436 } else {
358 DirstateParents {
437 DirstateParents {
359 p1: NULL_NODE,
438 p1: NULL_NODE,
360 p2: NULL_NODE,
439 p2: NULL_NODE,
361 }
440 }
362 };
441 };
363 self.parents = Some(parents);
442 self.parents = Some(parents);
364 }
443 }
365 Ok(self.parents.as_ref().unwrap())
444 Ok(self.parents.as_ref().unwrap())
366 }
445 }
367
446
368 fn set_parents(&mut self, parents: &DirstateParents) {
447 fn set_parents(&mut self, parents: &DirstateParents) {
369 self.parents = Some(parents.clone());
448 self.parents = Some(parents.clone());
370 self.dirty_parents = true;
449 self.dirty_parents = true;
371 }
450 }
372
451
373 fn read<'a>(
452 fn read<'a>(
374 &mut self,
453 &mut self,
375 file_contents: &'a [u8],
454 file_contents: &'a [u8],
376 ) -> Result<Option<&'a DirstateParents>, DirstateError> {
455 ) -> Result<Option<&'a DirstateParents>, DirstateError> {
377 if file_contents.is_empty() {
456 if file_contents.is_empty() {
378 return Ok(None);
457 return Ok(None);
379 }
458 }
380
459
381 let parents = parse_dirstate_entries(
460 let parents = parse_dirstate_entries(
382 file_contents,
461 file_contents,
383 |path, entry, copy_source| {
462 |path, entry, copy_source| {
384 self.add_file_node(
463 self.add_file_node(
385 path,
464 path,
386 *entry,
465 *entry,
387 Some(copy_source.map(HgPath::to_owned)),
466 Some(copy_source.map(HgPath::to_owned)),
388 )
467 )
389 },
468 },
390 )?;
469 )?;
391
470
392 if !self.dirty_parents {
471 if !self.dirty_parents {
393 self.set_parents(parents);
472 self.set_parents(parents);
394 }
473 }
395
474
396 Ok(Some(parents))
475 Ok(Some(parents))
397 }
476 }
398
477
399 fn pack(
478 fn pack(
400 &mut self,
479 &mut self,
401 parents: DirstateParents,
480 parents: DirstateParents,
402 now: Timestamp,
481 now: Timestamp,
403 ) -> Result<Vec<u8>, DirstateError> {
482 ) -> Result<Vec<u8>, DirstateError> {
404 // Optizimation (to be measured?): pre-compute size to avoid `Vec`
483 // Optizimation (to be measured?): pre-compute size to avoid `Vec`
405 // reallocations
484 // reallocations
406 let mut size = parents.as_bytes().len();
485 let mut size = parents.as_bytes().len();
407 for (path, node) in self.iter_nodes() {
486 for (path, node) in self.iter_nodes() {
408 if node.entry.is_some() {
487 if node.entry.is_some() {
409 size += packed_entry_size(
488 size += packed_entry_size(
410 path.full_path(),
489 path.full_path(),
411 node.copy_source.as_ref(),
490 node.copy_source.as_ref(),
412 )
491 )
413 }
492 }
414 }
493 }
415
494
416 let mut packed = Vec::with_capacity(size);
495 let mut packed = Vec::with_capacity(size);
417 packed.extend(parents.as_bytes());
496 packed.extend(parents.as_bytes());
418
497
419 let now: i32 = now.0.try_into().expect("time overflow");
498 let now: i32 = now.0.try_into().expect("time overflow");
420 for (path, opt_entry, copy_source) in self.iter_node_data_mut() {
499 for (path, opt_entry, copy_source) in self.iter_node_data_mut() {
421 if let Some(entry) = opt_entry {
500 if let Some(entry) = opt_entry {
422 clear_ambiguous_mtime(entry, now);
501 clear_ambiguous_mtime(entry, now);
423 pack_entry(
502 pack_entry(
424 path.full_path(),
503 path.full_path(),
425 entry,
504 entry,
426 copy_source.as_ref(),
505 copy_source.as_ref(),
427 &mut packed,
506 &mut packed,
428 );
507 );
429 }
508 }
430 }
509 }
431 self.dirty_parents = false;
510 self.dirty_parents = false;
432 Ok(packed)
511 Ok(packed)
433 }
512 }
434
513
435 fn build_file_fold_map(&mut self) -> &FastHashMap<HgPathBuf, HgPathBuf> {
514 fn build_file_fold_map(&mut self) -> &FastHashMap<HgPathBuf, HgPathBuf> {
436 todo!()
515 todo!()
437 }
516 }
438
517
439 fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> {
518 fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> {
440 todo!()
519 // Do nothing, this `DirstateMap` does not a separate `all_dirs` that
520 // needs to be recomputed
521 Ok(())
441 }
522 }
442
523
443 fn set_dirs(&mut self) -> Result<(), DirstateMapError> {
524 fn set_dirs(&mut self) -> Result<(), DirstateMapError> {
444 todo!()
525 // Do nothing, this `DirstateMap` does not a separate `dirs` that needs
526 // to be recomputed
527 Ok(())
445 }
528 }
446
529
447 fn status<'a>(
530 fn status<'a>(
448 &'a self,
531 &'a self,
449 _matcher: &'a (dyn Matcher + Sync),
532 _matcher: &'a (dyn Matcher + Sync),
450 _root_dir: PathBuf,
533 _root_dir: PathBuf,
451 _ignore_files: Vec<PathBuf>,
534 _ignore_files: Vec<PathBuf>,
452 _options: StatusOptions,
535 _options: StatusOptions,
453 ) -> Result<
536 ) -> Result<
454 (
537 (
455 (Vec<HgPathCow<'a>>, DirstateStatus<'a>),
538 (Vec<HgPathCow<'a>>, DirstateStatus<'a>),
456 Vec<PatternFileWarning>,
539 Vec<PatternFileWarning>,
457 ),
540 ),
458 StatusError,
541 StatusError,
459 > {
542 > {
460 todo!()
543 todo!()
461 }
544 }
462
545
463 fn copy_map_len(&self) -> usize {
546 fn copy_map_len(&self) -> usize {
464 self.nodes_with_copy_source_count
547 self.nodes_with_copy_source_count
465 }
548 }
466
549
467 fn copy_map_iter(&self) -> CopyMapIter<'_> {
550 fn copy_map_iter(&self) -> CopyMapIter<'_> {
468 Box::new(self.iter_nodes().filter_map(|(path, node)| {
551 Box::new(self.iter_nodes().filter_map(|(path, node)| {
469 node.copy_source
552 node.copy_source
470 .as_ref()
553 .as_ref()
471 .map(|copy_source| (path.full_path(), copy_source))
554 .map(|copy_source| (path.full_path(), copy_source))
472 }))
555 }))
473 }
556 }
474
557
475 fn copy_map_contains_key(&self, key: &HgPath) -> bool {
558 fn copy_map_contains_key(&self, key: &HgPath) -> bool {
476 if let Some(node) = self.get_node(key) {
559 if let Some(node) = self.get_node(key) {
477 node.copy_source.is_some()
560 node.copy_source.is_some()
478 } else {
561 } else {
479 false
562 false
480 }
563 }
481 }
564 }
482
565
483 fn copy_map_get(&self, key: &HgPath) -> Option<&HgPathBuf> {
566 fn copy_map_get(&self, key: &HgPath) -> Option<&HgPathBuf> {
484 self.get_node(key)?.copy_source.as_ref()
567 self.get_node(key)?.copy_source.as_ref()
485 }
568 }
486
569
487 fn copy_map_remove(&mut self, key: &HgPath) -> Option<HgPathBuf> {
570 fn copy_map_remove(&mut self, key: &HgPath) -> Option<HgPathBuf> {
488 let count = &mut self.nodes_with_copy_source_count;
571 let count = &mut self.nodes_with_copy_source_count;
489 Self::get_node_mut(&mut self.root, key).and_then(|node| {
572 Self::get_node_mut(&mut self.root, key).and_then(|node| {
490 if node.copy_source.is_some() {
573 if node.copy_source.is_some() {
491 *count -= 1
574 *count -= 1
492 }
575 }
493 node.copy_source.take()
576 node.copy_source.take()
494 })
577 })
495 }
578 }
496
579
497 fn copy_map_insert(
580 fn copy_map_insert(
498 &mut self,
581 &mut self,
499 key: HgPathBuf,
582 key: HgPathBuf,
500 value: HgPathBuf,
583 value: HgPathBuf,
501 ) -> Option<HgPathBuf> {
584 ) -> Option<HgPathBuf> {
502 let node = Self::get_or_insert_node(&mut self.root, &key);
585 let node = Self::get_or_insert_node(&mut self.root, &key);
503 if node.copy_source.is_none() {
586 if node.copy_source.is_none() {
504 self.nodes_with_copy_source_count += 1
587 self.nodes_with_copy_source_count += 1
505 }
588 }
506 node.copy_source.replace(value)
589 node.copy_source.replace(value)
507 }
590 }
508
591
509 fn len(&self) -> usize {
592 fn len(&self) -> usize {
510 self.nodes_with_entry_count
593 self.nodes_with_entry_count
511 }
594 }
512
595
513 fn contains_key(&self, key: &HgPath) -> bool {
596 fn contains_key(&self, key: &HgPath) -> bool {
514 self.get(key).is_some()
597 self.get(key).is_some()
515 }
598 }
516
599
517 fn get(&self, key: &HgPath) -> Option<&DirstateEntry> {
600 fn get(&self, key: &HgPath) -> Option<&DirstateEntry> {
518 self.get_node(key)?.entry.as_ref()
601 self.get_node(key)?.entry.as_ref()
519 }
602 }
520
603
521 fn iter(&self) -> StateMapIter<'_> {
604 fn iter(&self) -> StateMapIter<'_> {
522 Box::new(self.iter_nodes().filter_map(|(path, node)| {
605 Box::new(self.iter_nodes().filter_map(|(path, node)| {
523 node.entry.as_ref().map(|entry| (path.full_path(), entry))
606 node.entry.as_ref().map(|entry| (path.full_path(), entry))
524 }))
607 }))
525 }
608 }
526 }
609 }
General Comments 0
You need to be logged in to leave comments. Login now