##// END OF EJS Templates
rust: fix formatting...
Raphaël Gomès -
r46183:423f17f9 default
parent child Browse files
Show More
@@ -1,395 +1,393 b''
1 // node.rs
1 // node.rs
2 //
2 //
3 // Copyright 2020, Raphaël Gomès <rgomes@octobus.net>
3 // Copyright 2020, 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 super::iter::Iter;
8 use super::iter::Iter;
9 use crate::utils::hg_path::HgPathBuf;
9 use crate::utils::hg_path::HgPathBuf;
10 use crate::{DirstateEntry, EntryState, FastHashMap};
10 use crate::{DirstateEntry, EntryState, FastHashMap};
11
11
12 /// Represents a filesystem directory in the dirstate tree
12 /// Represents a filesystem directory in the dirstate tree
13 #[derive(Debug, Default, Clone, PartialEq)]
13 #[derive(Debug, Default, Clone, PartialEq)]
14 pub struct Directory {
14 pub struct Directory {
15 /// Contains the old file information if it existed between changesets.
15 /// Contains the old file information if it existed between changesets.
16 /// Happens if a file `foo` is marked as removed, removed from the
16 /// Happens if a file `foo` is marked as removed, removed from the
17 /// filesystem then a directory `foo` is created and at least one of its
17 /// filesystem then a directory `foo` is created and at least one of its
18 /// descendents is added to Mercurial.
18 /// descendents is added to Mercurial.
19 pub(super) was_file: Option<Box<File>>,
19 pub(super) was_file: Option<Box<File>>,
20 pub(super) children: FastHashMap<Vec<u8>, Node>,
20 pub(super) children: FastHashMap<Vec<u8>, Node>,
21 }
21 }
22
22
23 /// Represents a filesystem file (or symlink) in the dirstate tree
23 /// Represents a filesystem file (or symlink) in the dirstate tree
24 #[derive(Debug, Clone, PartialEq)]
24 #[derive(Debug, Clone, PartialEq)]
25 pub struct File {
25 pub struct File {
26 /// Contains the old structure if it existed between changesets.
26 /// Contains the old structure if it existed between changesets.
27 /// Happens all descendents of `foo` marked as removed and removed from
27 /// Happens all descendents of `foo` marked as removed and removed from
28 /// the filesystem, then a file `foo` is created and added to Mercurial.
28 /// the filesystem, then a file `foo` is created and added to Mercurial.
29 pub(super) was_directory: Option<Box<Directory>>,
29 pub(super) was_directory: Option<Box<Directory>>,
30 pub(super) entry: DirstateEntry,
30 pub(super) entry: DirstateEntry,
31 }
31 }
32
32
33 #[derive(Debug, Clone, PartialEq)]
33 #[derive(Debug, Clone, PartialEq)]
34 pub enum NodeKind {
34 pub enum NodeKind {
35 Directory(Directory),
35 Directory(Directory),
36 File(File),
36 File(File),
37 }
37 }
38
38
39 #[derive(Debug, Default, Clone, PartialEq)]
39 #[derive(Debug, Default, Clone, PartialEq)]
40 pub struct Node {
40 pub struct Node {
41 pub kind: NodeKind,
41 pub kind: NodeKind,
42 }
42 }
43
43
44 impl Default for NodeKind {
44 impl Default for NodeKind {
45 fn default() -> Self {
45 fn default() -> Self {
46 NodeKind::Directory(Default::default())
46 NodeKind::Directory(Default::default())
47 }
47 }
48 }
48 }
49
49
50 impl Node {
50 impl Node {
51 pub fn insert(
51 pub fn insert(
52 &mut self,
52 &mut self,
53 path: &[u8],
53 path: &[u8],
54 new_entry: DirstateEntry,
54 new_entry: DirstateEntry,
55 ) -> InsertResult {
55 ) -> InsertResult {
56 let mut split = path.splitn(2, |&c| c == b'/');
56 let mut split = path.splitn(2, |&c| c == b'/');
57 let head = split.next().unwrap_or(b"");
57 let head = split.next().unwrap_or(b"");
58 let tail = split.next().unwrap_or(b"");
58 let tail = split.next().unwrap_or(b"");
59
59
60 if let NodeKind::File(file) = &mut self.kind {
60 if let NodeKind::File(file) = &mut self.kind {
61 if tail.is_empty() && head.is_empty() {
61 if tail.is_empty() && head.is_empty() {
62 // We're modifying the current file
62 // We're modifying the current file
63 let new = Self {
63 let new = Self {
64 kind: NodeKind::File(File {
64 kind: NodeKind::File(File {
65 entry: new_entry,
65 entry: new_entry,
66 ..file.clone()
66 ..file.clone()
67 }),
67 }),
68 };
68 };
69 return InsertResult {
69 return InsertResult {
70 did_insert: false,
70 did_insert: false,
71 old_entry: Some(std::mem::replace(self, new)),
71 old_entry: Some(std::mem::replace(self, new)),
72 };
72 };
73 } else {
73 } else {
74 match file.entry.state {
74 match file.entry.state {
75 // Only replace the current file with a directory if it's
75 // Only replace the current file with a directory if it's
76 // marked as `Removed`
76 // marked as `Removed`
77 EntryState::Removed => {
77 EntryState::Removed => {
78 self.kind = NodeKind::Directory(Directory {
78 self.kind = NodeKind::Directory(Directory {
79 was_file: Some(Box::from(file.clone())),
79 was_file: Some(Box::from(file.clone())),
80 children: Default::default(),
80 children: Default::default(),
81 })
81 })
82 }
82 }
83 _ => {
83 _ => {
84 return Node::insert_in_file(
84 return Node::insert_in_file(
85 file, new_entry, head, tail,
85 file, new_entry, head, tail,
86 )
86 )
87 }
87 }
88 }
88 }
89 }
89 }
90 }
90 }
91
91
92 match &mut self.kind {
92 match &mut self.kind {
93 NodeKind::Directory(directory) => {
93 NodeKind::Directory(directory) => {
94 Node::insert_in_directory(
94 Node::insert_in_directory(directory, new_entry, head, tail)
95 directory, new_entry, head, tail,
96 )
97 }
95 }
98 NodeKind::File(_) => {
96 NodeKind::File(_) => {
99 unreachable!("The file case has already been handled")
97 unreachable!("The file case has already been handled")
100 }
98 }
101 }
99 }
102 }
100 }
103
101
104 /// The current file still exists and is not marked as `Removed`.
102 /// The current file still exists and is not marked as `Removed`.
105 /// Insert the entry in its `was_directory`.
103 /// Insert the entry in its `was_directory`.
106 fn insert_in_file(
104 fn insert_in_file(
107 file: &mut File,
105 file: &mut File,
108 new_entry: DirstateEntry,
106 new_entry: DirstateEntry,
109 head: &[u8],
107 head: &[u8],
110 tail: &[u8],
108 tail: &[u8],
111 ) -> InsertResult {
109 ) -> InsertResult {
112 if let Some(d) = &mut file.was_directory {
110 if let Some(d) = &mut file.was_directory {
113 Node::insert_in_directory(d, new_entry, head, tail)
111 Node::insert_in_directory(d, new_entry, head, tail)
114 } else {
112 } else {
115 let mut dir = Directory {
113 let mut dir = Directory {
116 was_file: None,
114 was_file: None,
117 children: FastHashMap::default(),
115 children: FastHashMap::default(),
118 };
116 };
119 let res =
117 let res =
120 Node::insert_in_directory(&mut dir, new_entry, head, tail);
118 Node::insert_in_directory(&mut dir, new_entry, head, tail);
121 file.was_directory = Some(Box::new(dir));
119 file.was_directory = Some(Box::new(dir));
122 res
120 res
123 }
121 }
124 }
122 }
125
123
126 /// Insert an entry in the subtree of `directory`
124 /// Insert an entry in the subtree of `directory`
127 fn insert_in_directory(
125 fn insert_in_directory(
128 directory: &mut Directory,
126 directory: &mut Directory,
129 new_entry: DirstateEntry,
127 new_entry: DirstateEntry,
130 head: &[u8],
128 head: &[u8],
131 tail: &[u8],
129 tail: &[u8],
132 ) -> InsertResult {
130 ) -> InsertResult {
133 let mut res = InsertResult::default();
131 let mut res = InsertResult::default();
134
132
135 if let Some(node) = directory.children.get_mut(head) {
133 if let Some(node) = directory.children.get_mut(head) {
136 // Node exists
134 // Node exists
137 match &mut node.kind {
135 match &mut node.kind {
138 NodeKind::Directory(subdir) => {
136 NodeKind::Directory(subdir) => {
139 if tail.is_empty() {
137 if tail.is_empty() {
140 let becomes_file = Self {
138 let becomes_file = Self {
141 kind: NodeKind::File(File {
139 kind: NodeKind::File(File {
142 was_directory: Some(Box::from(subdir.clone())),
140 was_directory: Some(Box::from(subdir.clone())),
143 entry: new_entry,
141 entry: new_entry,
144 }),
142 }),
145 };
143 };
146 let old_entry = directory
144 let old_entry = directory
147 .children
145 .children
148 .insert(head.to_owned(), becomes_file);
146 .insert(head.to_owned(), becomes_file);
149 return InsertResult {
147 return InsertResult {
150 did_insert: true,
148 did_insert: true,
151 old_entry,
149 old_entry,
152 };
150 };
153 } else {
151 } else {
154 res = node.insert(tail, new_entry);
152 res = node.insert(tail, new_entry);
155 }
153 }
156 }
154 }
157 NodeKind::File(_) => {
155 NodeKind::File(_) => {
158 res = node.insert(tail, new_entry);
156 res = node.insert(tail, new_entry);
159 }
157 }
160 }
158 }
161 } else if tail.is_empty() {
159 } else if tail.is_empty() {
162 // File does not already exist
160 // File does not already exist
163 directory.children.insert(
161 directory.children.insert(
164 head.to_owned(),
162 head.to_owned(),
165 Self {
163 Self {
166 kind: NodeKind::File(File {
164 kind: NodeKind::File(File {
167 was_directory: None,
165 was_directory: None,
168 entry: new_entry,
166 entry: new_entry,
169 }),
167 }),
170 },
168 },
171 );
169 );
172 res.did_insert = true;
170 res.did_insert = true;
173 } else {
171 } else {
174 // Directory does not already exist
172 // Directory does not already exist
175 let mut nested = Self {
173 let mut nested = Self {
176 kind: NodeKind::Directory(Directory {
174 kind: NodeKind::Directory(Directory {
177 was_file: None,
175 was_file: None,
178 children: Default::default(),
176 children: Default::default(),
179 }),
177 }),
180 };
178 };
181 res = nested.insert(tail, new_entry);
179 res = nested.insert(tail, new_entry);
182 directory.children.insert(head.to_owned(), nested);
180 directory.children.insert(head.to_owned(), nested);
183 }
181 }
184 res
182 res
185 }
183 }
186
184
187 /// Removes an entry from the tree, returns a `RemoveResult`.
185 /// Removes an entry from the tree, returns a `RemoveResult`.
188 pub fn remove(&mut self, path: &[u8]) -> RemoveResult {
186 pub fn remove(&mut self, path: &[u8]) -> RemoveResult {
189 let empty_result = RemoveResult::default();
187 let empty_result = RemoveResult::default();
190 if path.is_empty() {
188 if path.is_empty() {
191 return empty_result;
189 return empty_result;
192 }
190 }
193 let mut split = path.splitn(2, |&c| c == b'/');
191 let mut split = path.splitn(2, |&c| c == b'/');
194 let head = split.next();
192 let head = split.next();
195 let tail = split.next().unwrap_or(b"");
193 let tail = split.next().unwrap_or(b"");
196
194
197 let head = match head {
195 let head = match head {
198 None => {
196 None => {
199 return empty_result;
197 return empty_result;
200 }
198 }
201 Some(h) => h,
199 Some(h) => h,
202 };
200 };
203 if head == path {
201 if head == path {
204 match &mut self.kind {
202 match &mut self.kind {
205 NodeKind::Directory(d) => {
203 NodeKind::Directory(d) => {
206 return Node::remove_from_directory(head, d);
204 return Node::remove_from_directory(head, d);
207 }
205 }
208 NodeKind::File(f) => {
206 NodeKind::File(f) => {
209 if let Some(d) = &mut f.was_directory {
207 if let Some(d) = &mut f.was_directory {
210 let RemoveResult { old_entry, .. } =
208 let RemoveResult { old_entry, .. } =
211 Node::remove_from_directory(head, d);
209 Node::remove_from_directory(head, d);
212 return RemoveResult {
210 return RemoveResult {
213 cleanup: false,
211 cleanup: false,
214 old_entry,
212 old_entry,
215 };
213 };
216 }
214 }
217 }
215 }
218 }
216 }
219 empty_result
217 empty_result
220 } else {
218 } else {
221 // Look into the dirs
219 // Look into the dirs
222 match &mut self.kind {
220 match &mut self.kind {
223 NodeKind::Directory(d) => {
221 NodeKind::Directory(d) => {
224 if let Some(child) = d.children.get_mut(head) {
222 if let Some(child) = d.children.get_mut(head) {
225 let mut res = child.remove(tail);
223 let mut res = child.remove(tail);
226 if res.cleanup {
224 if res.cleanup {
227 d.children.remove(head);
225 d.children.remove(head);
228 }
226 }
229 res.cleanup =
227 res.cleanup =
230 d.children.is_empty() && d.was_file.is_none();
228 d.children.is_empty() && d.was_file.is_none();
231 res
229 res
232 } else {
230 } else {
233 empty_result
231 empty_result
234 }
232 }
235 }
233 }
236 NodeKind::File(f) => {
234 NodeKind::File(f) => {
237 if let Some(d) = &mut f.was_directory {
235 if let Some(d) = &mut f.was_directory {
238 if let Some(child) = d.children.get_mut(head) {
236 if let Some(child) = d.children.get_mut(head) {
239 let RemoveResult { cleanup, old_entry } =
237 let RemoveResult { cleanup, old_entry } =
240 child.remove(tail);
238 child.remove(tail);
241 if cleanup {
239 if cleanup {
242 d.children.remove(head);
240 d.children.remove(head);
243 }
241 }
244 if d.children.is_empty() && d.was_file.is_none() {
242 if d.children.is_empty() && d.was_file.is_none() {
245 f.was_directory = None;
243 f.was_directory = None;
246 }
244 }
247
245
248 return RemoveResult {
246 return RemoveResult {
249 cleanup: false,
247 cleanup: false,
250 old_entry,
248 old_entry,
251 };
249 };
252 }
250 }
253 }
251 }
254 empty_result
252 empty_result
255 }
253 }
256 }
254 }
257 }
255 }
258 }
256 }
259
257
260 fn remove_from_directory(head: &[u8], d: &mut Directory) -> RemoveResult {
258 fn remove_from_directory(head: &[u8], d: &mut Directory) -> RemoveResult {
261 if let Some(node) = d.children.get_mut(head) {
259 if let Some(node) = d.children.get_mut(head) {
262 return match &mut node.kind {
260 return match &mut node.kind {
263 NodeKind::Directory(d) => {
261 NodeKind::Directory(d) => {
264 if let Some(f) = &mut d.was_file {
262 if let Some(f) = &mut d.was_file {
265 let entry = f.entry;
263 let entry = f.entry;
266 d.was_file = None;
264 d.was_file = None;
267 RemoveResult {
265 RemoveResult {
268 cleanup: false,
266 cleanup: false,
269 old_entry: Some(entry),
267 old_entry: Some(entry),
270 }
268 }
271 } else {
269 } else {
272 RemoveResult::default()
270 RemoveResult::default()
273 }
271 }
274 }
272 }
275 NodeKind::File(f) => {
273 NodeKind::File(f) => {
276 let entry = f.entry;
274 let entry = f.entry;
277 let mut cleanup = false;
275 let mut cleanup = false;
278 match &f.was_directory {
276 match &f.was_directory {
279 None => {
277 None => {
280 if d.children.len() == 1 {
278 if d.children.len() == 1 {
281 cleanup = true;
279 cleanup = true;
282 }
280 }
283 d.children.remove(head);
281 d.children.remove(head);
284 }
282 }
285 Some(dir) => {
283 Some(dir) => {
286 node.kind = NodeKind::Directory(*dir.clone());
284 node.kind = NodeKind::Directory(*dir.clone());
287 }
285 }
288 }
286 }
289
287
290 RemoveResult {
288 RemoveResult {
291 cleanup,
289 cleanup,
292 old_entry: Some(entry),
290 old_entry: Some(entry),
293 }
291 }
294 }
292 }
295 };
293 };
296 }
294 }
297 RemoveResult::default()
295 RemoveResult::default()
298 }
296 }
299
297
300 pub fn get(&self, path: &[u8]) -> Option<&Node> {
298 pub fn get(&self, path: &[u8]) -> Option<&Node> {
301 if path.is_empty() {
299 if path.is_empty() {
302 return Some(&self);
300 return Some(&self);
303 }
301 }
304 let mut split = path.splitn(2, |&c| c == b'/');
302 let mut split = path.splitn(2, |&c| c == b'/');
305 let head = split.next();
303 let head = split.next();
306 let tail = split.next().unwrap_or(b"");
304 let tail = split.next().unwrap_or(b"");
307
305
308 let head = match head {
306 let head = match head {
309 None => {
307 None => {
310 return Some(&self);
308 return Some(&self);
311 }
309 }
312 Some(h) => h,
310 Some(h) => h,
313 };
311 };
314 match &self.kind {
312 match &self.kind {
315 NodeKind::Directory(d) => {
313 NodeKind::Directory(d) => {
316 if let Some(child) = d.children.get(head) {
314 if let Some(child) = d.children.get(head) {
317 return child.get(tail);
315 return child.get(tail);
318 }
316 }
319 }
317 }
320 NodeKind::File(f) => {
318 NodeKind::File(f) => {
321 if let Some(d) = &f.was_directory {
319 if let Some(d) = &f.was_directory {
322 if let Some(child) = d.children.get(head) {
320 if let Some(child) = d.children.get(head) {
323 return child.get(tail);
321 return child.get(tail);
324 }
322 }
325 }
323 }
326 }
324 }
327 }
325 }
328
326
329 None
327 None
330 }
328 }
331
329
332 pub fn get_mut(&mut self, path: &[u8]) -> Option<&mut NodeKind> {
330 pub fn get_mut(&mut self, path: &[u8]) -> Option<&mut NodeKind> {
333 if path.is_empty() {
331 if path.is_empty() {
334 return Some(&mut self.kind);
332 return Some(&mut self.kind);
335 }
333 }
336 let mut split = path.splitn(2, |&c| c == b'/');
334 let mut split = path.splitn(2, |&c| c == b'/');
337 let head = split.next();
335 let head = split.next();
338 let tail = split.next().unwrap_or(b"");
336 let tail = split.next().unwrap_or(b"");
339
337
340 let head = match head {
338 let head = match head {
341 None => {
339 None => {
342 return Some(&mut self.kind);
340 return Some(&mut self.kind);
343 }
341 }
344 Some(h) => h,
342 Some(h) => h,
345 };
343 };
346 match &mut self.kind {
344 match &mut self.kind {
347 NodeKind::Directory(d) => {
345 NodeKind::Directory(d) => {
348 if let Some(child) = d.children.get_mut(head) {
346 if let Some(child) = d.children.get_mut(head) {
349 return child.get_mut(tail);
347 return child.get_mut(tail);
350 }
348 }
351 }
349 }
352 NodeKind::File(f) => {
350 NodeKind::File(f) => {
353 if let Some(d) = &mut f.was_directory {
351 if let Some(d) = &mut f.was_directory {
354 if let Some(child) = d.children.get_mut(head) {
352 if let Some(child) = d.children.get_mut(head) {
355 return child.get_mut(tail);
353 return child.get_mut(tail);
356 }
354 }
357 }
355 }
358 }
356 }
359 }
357 }
360
358
361 None
359 None
362 }
360 }
363
361
364 pub fn iter(&self) -> Iter {
362 pub fn iter(&self) -> Iter {
365 Iter::new(self)
363 Iter::new(self)
366 }
364 }
367 }
365 }
368
366
369 /// Information returned to the caller of an `insert` operation for integrity.
367 /// Information returned to the caller of an `insert` operation for integrity.
370 #[derive(Debug, Default)]
368 #[derive(Debug, Default)]
371 pub struct InsertResult {
369 pub struct InsertResult {
372 /// Whether the insertion resulted in an actual insertion and not an
370 /// Whether the insertion resulted in an actual insertion and not an
373 /// update
371 /// update
374 pub(super) did_insert: bool,
372 pub(super) did_insert: bool,
375 /// The entry that was replaced, if it exists
373 /// The entry that was replaced, if it exists
376 pub(super) old_entry: Option<Node>,
374 pub(super) old_entry: Option<Node>,
377 }
375 }
378
376
379 /// Information returned to the caller of a `remove` operation integrity.
377 /// Information returned to the caller of a `remove` operation integrity.
380 #[derive(Debug, Default)]
378 #[derive(Debug, Default)]
381 pub struct RemoveResult {
379 pub struct RemoveResult {
382 /// If the caller needs to remove the current node
380 /// If the caller needs to remove the current node
383 pub(super) cleanup: bool,
381 pub(super) cleanup: bool,
384 /// The entry that was replaced, if it exists
382 /// The entry that was replaced, if it exists
385 pub(super) old_entry: Option<DirstateEntry>,
383 pub(super) old_entry: Option<DirstateEntry>,
386 }
384 }
387
385
388 impl<'a> IntoIterator for &'a Node {
386 impl<'a> IntoIterator for &'a Node {
389 type Item = (HgPathBuf, DirstateEntry);
387 type Item = (HgPathBuf, DirstateEntry);
390 type IntoIter = Iter<'a>;
388 type IntoIter = Iter<'a>;
391
389
392 fn into_iter(self) -> Self::IntoIter {
390 fn into_iter(self) -> Self::IntoIter {
393 self.iter()
391 self.iter()
394 }
392 }
395 }
393 }
General Comments 0
You need to be logged in to leave comments. Login now