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