##// END OF EJS Templates
rust-dirstate: remove too abstracted way of getting &[u8]
Yuya Nishihara -
r43063:8d2d5dfa default
parent child Browse files
Show More
@@ -1,435 +1,429 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::{
8 use crate::{
9 dirstate::{parsers::PARENT_SIZE, EntryState},
9 dirstate::{parsers::PARENT_SIZE, EntryState},
10 pack_dirstate, parse_dirstate,
10 pack_dirstate, parse_dirstate,
11 utils::copy_into_array,
11 utils::copy_into_array,
12 CopyMap, DirsIterable, DirsMultiset, DirstateEntry, DirstateError,
12 CopyMap, DirsIterable, DirsMultiset, DirstateEntry, DirstateError,
13 DirstateMapError, DirstateParents, DirstateParseError, StateMap,
13 DirstateMapError, DirstateParents, DirstateParseError, StateMap,
14 };
14 };
15 use core::borrow::Borrow;
15 use core::borrow::Borrow;
16 use std::collections::{HashMap, HashSet};
16 use std::collections::{HashMap, HashSet};
17 use std::iter::FromIterator;
17 use std::iter::FromIterator;
18 use std::ops::Deref;
18 use std::ops::Deref;
19 use std::time::Duration;
19 use std::time::Duration;
20
20
21 pub type FileFoldMap = HashMap<Vec<u8>, Vec<u8>>;
21 pub type FileFoldMap = HashMap<Vec<u8>, Vec<u8>>;
22
22
23 const NULL_REVISION: [u8; 20] = [
23 const NULL_REVISION: [u8; 20] = [
24 b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0',
24 b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0',
25 b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0',
25 b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0',
26 ];
26 ];
27 const MTIME_UNSET: i32 = -1;
27 const MTIME_UNSET: i32 = -1;
28 const SIZE_DIRTY: i32 = -2;
28 const SIZE_DIRTY: i32 = -2;
29
29
30 #[derive(Default)]
30 #[derive(Default)]
31 pub struct DirstateMap {
31 pub struct DirstateMap {
32 state_map: StateMap,
32 state_map: StateMap,
33 pub copy_map: CopyMap,
33 pub copy_map: CopyMap,
34 file_fold_map: Option<FileFoldMap>,
34 file_fold_map: Option<FileFoldMap>,
35 pub dirs: Option<DirsMultiset>,
35 pub dirs: Option<DirsMultiset>,
36 pub all_dirs: Option<DirsMultiset>,
36 pub all_dirs: Option<DirsMultiset>,
37 non_normal_set: HashSet<Vec<u8>>,
37 non_normal_set: HashSet<Vec<u8>>,
38 other_parent_set: HashSet<Vec<u8>>,
38 other_parent_set: HashSet<Vec<u8>>,
39 parents: Option<DirstateParents>,
39 parents: Option<DirstateParents>,
40 dirty_parents: bool,
40 dirty_parents: bool,
41 }
41 }
42
42
43 /// Should only really be used in python interface code, for clarity
43 /// Should only really be used in python interface code, for clarity
44 impl Deref for DirstateMap {
44 impl Deref for DirstateMap {
45 type Target = StateMap;
45 type Target = StateMap;
46
46
47 fn deref(&self) -> &Self::Target {
47 fn deref(&self) -> &Self::Target {
48 &self.state_map
48 &self.state_map
49 }
49 }
50 }
50 }
51
51
52 impl FromIterator<(Vec<u8>, DirstateEntry)> for DirstateMap {
52 impl FromIterator<(Vec<u8>, DirstateEntry)> for DirstateMap {
53 fn from_iter<I: IntoIterator<Item = (Vec<u8>, DirstateEntry)>>(
53 fn from_iter<I: IntoIterator<Item = (Vec<u8>, DirstateEntry)>>(
54 iter: I,
54 iter: I,
55 ) -> Self {
55 ) -> Self {
56 Self {
56 Self {
57 state_map: iter.into_iter().collect(),
57 state_map: iter.into_iter().collect(),
58 ..Self::default()
58 ..Self::default()
59 }
59 }
60 }
60 }
61 }
61 }
62
62
63 impl DirstateMap {
63 impl DirstateMap {
64 pub fn new() -> Self {
64 pub fn new() -> Self {
65 Self::default()
65 Self::default()
66 }
66 }
67
67
68 pub fn clear(&mut self) {
68 pub fn clear(&mut self) {
69 self.state_map.clear();
69 self.state_map.clear();
70 self.copy_map.clear();
70 self.copy_map.clear();
71 self.file_fold_map = None;
71 self.file_fold_map = None;
72 self.non_normal_set.clear();
72 self.non_normal_set.clear();
73 self.other_parent_set.clear();
73 self.other_parent_set.clear();
74 self.set_parents(DirstateParents {
74 self.set_parents(DirstateParents {
75 p1: NULL_REVISION,
75 p1: NULL_REVISION,
76 p2: NULL_REVISION,
76 p2: NULL_REVISION,
77 })
77 })
78 }
78 }
79
79
80 /// Add a tracked file to the dirstate
80 /// Add a tracked file to the dirstate
81 pub fn add_file(
81 pub fn add_file(
82 &mut self,
82 &mut self,
83 filename: &[u8],
83 filename: &[u8],
84 old_state: EntryState,
84 old_state: EntryState,
85 entry: DirstateEntry,
85 entry: DirstateEntry,
86 ) {
86 ) {
87 if old_state == EntryState::Unknown || old_state == EntryState::Removed
87 if old_state == EntryState::Unknown || old_state == EntryState::Removed
88 {
88 {
89 if let Some(ref mut dirs) = self.dirs {
89 if let Some(ref mut dirs) = self.dirs {
90 dirs.add_path(filename)
90 dirs.add_path(filename)
91 }
91 }
92 }
92 }
93 if old_state == EntryState::Unknown {
93 if old_state == EntryState::Unknown {
94 if let Some(ref mut all_dirs) = self.all_dirs {
94 if let Some(ref mut all_dirs) = self.all_dirs {
95 all_dirs.add_path(filename)
95 all_dirs.add_path(filename)
96 }
96 }
97 }
97 }
98 self.state_map.insert(filename.to_owned(), entry.to_owned());
98 self.state_map.insert(filename.to_owned(), entry.to_owned());
99
99
100 if entry.state != EntryState::Normal || entry.mtime == MTIME_UNSET {
100 if entry.state != EntryState::Normal || entry.mtime == MTIME_UNSET {
101 self.non_normal_set.insert(filename.to_owned());
101 self.non_normal_set.insert(filename.to_owned());
102 }
102 }
103
103
104 if entry.size == SIZE_DIRTY {
104 if entry.size == SIZE_DIRTY {
105 self.other_parent_set.insert(filename.to_owned());
105 self.other_parent_set.insert(filename.to_owned());
106 }
106 }
107 }
107 }
108
108
109 /// Mark a file as removed in the dirstate.
109 /// Mark a file as removed in the dirstate.
110 ///
110 ///
111 /// The `size` parameter is used to store sentinel values that indicate
111 /// The `size` parameter is used to store sentinel values that indicate
112 /// the file's previous state. In the future, we should refactor this
112 /// the file's previous state. In the future, we should refactor this
113 /// to be more explicit about what that state is.
113 /// to be more explicit about what that state is.
114 pub fn remove_file(
114 pub fn remove_file(
115 &mut self,
115 &mut self,
116 filename: &[u8],
116 filename: &[u8],
117 old_state: EntryState,
117 old_state: EntryState,
118 size: i32,
118 size: i32,
119 ) -> Result<(), DirstateMapError> {
119 ) -> Result<(), DirstateMapError> {
120 if old_state != EntryState::Unknown && old_state != EntryState::Removed
120 if old_state != EntryState::Unknown && old_state != EntryState::Removed
121 {
121 {
122 if let Some(ref mut dirs) = self.dirs {
122 if let Some(ref mut dirs) = self.dirs {
123 dirs.delete_path(filename)?;
123 dirs.delete_path(filename)?;
124 }
124 }
125 }
125 }
126 if old_state == EntryState::Unknown {
126 if old_state == EntryState::Unknown {
127 if let Some(ref mut all_dirs) = self.all_dirs {
127 if let Some(ref mut all_dirs) = self.all_dirs {
128 all_dirs.add_path(filename);
128 all_dirs.add_path(filename);
129 }
129 }
130 }
130 }
131
131
132 if let Some(ref mut file_fold_map) = self.file_fold_map {
132 if let Some(ref mut file_fold_map) = self.file_fold_map {
133 file_fold_map
133 file_fold_map.remove(&filename.to_ascii_uppercase());
134 .remove::<Vec<u8>>(filename.to_ascii_uppercase().as_ref());
135 }
134 }
136 self.state_map.insert(
135 self.state_map.insert(
137 filename.to_owned(),
136 filename.to_owned(),
138 DirstateEntry {
137 DirstateEntry {
139 state: EntryState::Removed,
138 state: EntryState::Removed,
140 mode: 0,
139 mode: 0,
141 size,
140 size,
142 mtime: 0,
141 mtime: 0,
143 },
142 },
144 );
143 );
145 self.non_normal_set.insert(filename.to_owned());
144 self.non_normal_set.insert(filename.to_owned());
146 Ok(())
145 Ok(())
147 }
146 }
148
147
149 /// Remove a file from the dirstate.
148 /// Remove a file from the dirstate.
150 /// Returns `true` if the file was previously recorded.
149 /// Returns `true` if the file was previously recorded.
151 pub fn drop_file(
150 pub fn drop_file(
152 &mut self,
151 &mut self,
153 filename: &[u8],
152 filename: &[u8],
154 old_state: EntryState,
153 old_state: EntryState,
155 ) -> Result<bool, DirstateMapError> {
154 ) -> Result<bool, DirstateMapError> {
156 let exists = self
155 let exists = self.state_map.remove(filename).is_some();
157 .state_map
158 .remove::<Vec<u8>>(filename.to_owned().as_ref())
159 .is_some();
160
156
161 if exists {
157 if exists {
162 if old_state != EntryState::Removed {
158 if old_state != EntryState::Removed {
163 if let Some(ref mut dirs) = self.dirs {
159 if let Some(ref mut dirs) = self.dirs {
164 dirs.delete_path(filename)?;
160 dirs.delete_path(filename)?;
165 }
161 }
166 }
162 }
167 if let Some(ref mut all_dirs) = self.all_dirs {
163 if let Some(ref mut all_dirs) = self.all_dirs {
168 all_dirs.delete_path(filename)?;
164 all_dirs.delete_path(filename)?;
169 }
165 }
170 }
166 }
171 if let Some(ref mut file_fold_map) = self.file_fold_map {
167 if let Some(ref mut file_fold_map) = self.file_fold_map {
172 file_fold_map
168 file_fold_map.remove(&filename.to_ascii_uppercase());
173 .remove::<Vec<u8>>(filename.to_ascii_uppercase().as_ref());
174 }
169 }
175 self.non_normal_set
170 self.non_normal_set.remove(filename);
176 .remove::<Vec<u8>>(filename.to_owned().as_ref());
177
171
178 Ok(exists)
172 Ok(exists)
179 }
173 }
180
174
181 pub fn clear_ambiguous_times(
175 pub fn clear_ambiguous_times(
182 &mut self,
176 &mut self,
183 filenames: Vec<Vec<u8>>,
177 filenames: Vec<Vec<u8>>,
184 now: i32,
178 now: i32,
185 ) {
179 ) {
186 for filename in filenames {
180 for filename in filenames {
187 let mut changed = false;
181 let mut changed = false;
188 self.state_map
182 self.state_map
189 .entry(filename.to_owned())
183 .entry(filename.to_owned())
190 .and_modify(|entry| {
184 .and_modify(|entry| {
191 if entry.state == EntryState::Normal && entry.mtime == now
185 if entry.state == EntryState::Normal && entry.mtime == now
192 {
186 {
193 changed = true;
187 changed = true;
194 *entry = DirstateEntry {
188 *entry = DirstateEntry {
195 mtime: MTIME_UNSET,
189 mtime: MTIME_UNSET,
196 ..*entry
190 ..*entry
197 };
191 };
198 }
192 }
199 });
193 });
200 if changed {
194 if changed {
201 self.non_normal_set.insert(filename.to_owned());
195 self.non_normal_set.insert(filename.to_owned());
202 }
196 }
203 }
197 }
204 }
198 }
205
199
206 pub fn non_normal_other_parent_entries(
200 pub fn non_normal_other_parent_entries(
207 &self,
201 &self,
208 ) -> (HashSet<Vec<u8>>, HashSet<Vec<u8>>) {
202 ) -> (HashSet<Vec<u8>>, HashSet<Vec<u8>>) {
209 let mut non_normal = HashSet::new();
203 let mut non_normal = HashSet::new();
210 let mut other_parent = HashSet::new();
204 let mut other_parent = HashSet::new();
211
205
212 for (
206 for (
213 filename,
207 filename,
214 DirstateEntry {
208 DirstateEntry {
215 state, size, mtime, ..
209 state, size, mtime, ..
216 },
210 },
217 ) in self.state_map.iter()
211 ) in self.state_map.iter()
218 {
212 {
219 if *state != EntryState::Normal || *mtime == MTIME_UNSET {
213 if *state != EntryState::Normal || *mtime == MTIME_UNSET {
220 non_normal.insert(filename.to_owned());
214 non_normal.insert(filename.to_owned());
221 }
215 }
222 if *state == EntryState::Normal && *size == SIZE_DIRTY {
216 if *state == EntryState::Normal && *size == SIZE_DIRTY {
223 other_parent.insert(filename.to_owned());
217 other_parent.insert(filename.to_owned());
224 }
218 }
225 }
219 }
226
220
227 (non_normal, other_parent)
221 (non_normal, other_parent)
228 }
222 }
229
223
230 /// Both of these setters and their uses appear to be the simplest way to
224 /// Both of these setters and their uses appear to be the simplest way to
231 /// emulate a Python lazy property, but it is ugly and unidiomatic.
225 /// emulate a Python lazy property, but it is ugly and unidiomatic.
232 /// TODO One day, rewriting this struct using the typestate might be a
226 /// TODO One day, rewriting this struct using the typestate might be a
233 /// good idea.
227 /// good idea.
234 pub fn set_all_dirs(&mut self) {
228 pub fn set_all_dirs(&mut self) {
235 if self.all_dirs.is_none() {
229 if self.all_dirs.is_none() {
236 self.all_dirs = Some(DirsMultiset::new(
230 self.all_dirs = Some(DirsMultiset::new(
237 DirsIterable::Dirstate(&self.state_map),
231 DirsIterable::Dirstate(&self.state_map),
238 None,
232 None,
239 ));
233 ));
240 }
234 }
241 }
235 }
242
236
243 pub fn set_dirs(&mut self) {
237 pub fn set_dirs(&mut self) {
244 if self.dirs.is_none() {
238 if self.dirs.is_none() {
245 self.dirs = Some(DirsMultiset::new(
239 self.dirs = Some(DirsMultiset::new(
246 DirsIterable::Dirstate(&self.state_map),
240 DirsIterable::Dirstate(&self.state_map),
247 Some(EntryState::Removed),
241 Some(EntryState::Removed),
248 ));
242 ));
249 }
243 }
250 }
244 }
251
245
252 pub fn has_tracked_dir(&mut self, directory: &[u8]) -> bool {
246 pub fn has_tracked_dir(&mut self, directory: &[u8]) -> bool {
253 self.set_dirs();
247 self.set_dirs();
254 self.dirs.as_ref().unwrap().contains(directory.as_ref())
248 self.dirs.as_ref().unwrap().contains(directory)
255 }
249 }
256
250
257 pub fn has_dir(&mut self, directory: &[u8]) -> bool {
251 pub fn has_dir(&mut self, directory: &[u8]) -> bool {
258 self.set_all_dirs();
252 self.set_all_dirs();
259 self.all_dirs.as_ref().unwrap().contains(directory.as_ref())
253 self.all_dirs.as_ref().unwrap().contains(directory)
260 }
254 }
261
255
262 pub fn parents(
256 pub fn parents(
263 &mut self,
257 &mut self,
264 file_contents: &[u8],
258 file_contents: &[u8],
265 ) -> Result<DirstateParents, DirstateError> {
259 ) -> Result<DirstateParents, DirstateError> {
266 if let Some(ref parents) = self.parents {
260 if let Some(ref parents) = self.parents {
267 return Ok(parents.clone());
261 return Ok(parents.clone());
268 }
262 }
269 let parents;
263 let parents;
270 if file_contents.len() == 40 {
264 if file_contents.len() == 40 {
271 parents = DirstateParents {
265 parents = DirstateParents {
272 p1: copy_into_array(&file_contents[..PARENT_SIZE]),
266 p1: copy_into_array(&file_contents[..PARENT_SIZE]),
273 p2: copy_into_array(
267 p2: copy_into_array(
274 &file_contents[PARENT_SIZE..PARENT_SIZE * 2],
268 &file_contents[PARENT_SIZE..PARENT_SIZE * 2],
275 ),
269 ),
276 };
270 };
277 } else if file_contents.is_empty() {
271 } else if file_contents.is_empty() {
278 parents = DirstateParents {
272 parents = DirstateParents {
279 p1: NULL_REVISION,
273 p1: NULL_REVISION,
280 p2: NULL_REVISION,
274 p2: NULL_REVISION,
281 };
275 };
282 } else {
276 } else {
283 return Err(DirstateError::Parse(DirstateParseError::Damaged));
277 return Err(DirstateError::Parse(DirstateParseError::Damaged));
284 }
278 }
285
279
286 self.parents = Some(parents.to_owned());
280 self.parents = Some(parents.to_owned());
287 Ok(parents.clone())
281 Ok(parents.clone())
288 }
282 }
289
283
290 pub fn set_parents(&mut self, parents: DirstateParents) {
284 pub fn set_parents(&mut self, parents: DirstateParents) {
291 self.parents = Some(parents.clone());
285 self.parents = Some(parents.clone());
292 self.dirty_parents = true;
286 self.dirty_parents = true;
293 }
287 }
294
288
295 pub fn read(
289 pub fn read(
296 &mut self,
290 &mut self,
297 file_contents: &[u8],
291 file_contents: &[u8],
298 ) -> Result<Option<DirstateParents>, DirstateError> {
292 ) -> Result<Option<DirstateParents>, DirstateError> {
299 if file_contents.is_empty() {
293 if file_contents.is_empty() {
300 return Ok(None);
294 return Ok(None);
301 }
295 }
302
296
303 let parents = parse_dirstate(
297 let parents = parse_dirstate(
304 &mut self.state_map,
298 &mut self.state_map,
305 &mut self.copy_map,
299 &mut self.copy_map,
306 file_contents,
300 file_contents,
307 )?;
301 )?;
308
302
309 if !self.dirty_parents {
303 if !self.dirty_parents {
310 self.set_parents(parents.to_owned());
304 self.set_parents(parents.to_owned());
311 }
305 }
312
306
313 Ok(Some(parents))
307 Ok(Some(parents))
314 }
308 }
315
309
316 pub fn pack(
310 pub fn pack(
317 &mut self,
311 &mut self,
318 parents: DirstateParents,
312 parents: DirstateParents,
319 now: Duration,
313 now: Duration,
320 ) -> Result<Vec<u8>, DirstateError> {
314 ) -> Result<Vec<u8>, DirstateError> {
321 let packed =
315 let packed =
322 pack_dirstate(&mut self.state_map, &self.copy_map, parents, now)?;
316 pack_dirstate(&mut self.state_map, &self.copy_map, parents, now)?;
323
317
324 self.dirty_parents = false;
318 self.dirty_parents = false;
325
319
326 let result = self.non_normal_other_parent_entries();
320 let result = self.non_normal_other_parent_entries();
327 self.non_normal_set = result.0;
321 self.non_normal_set = result.0;
328 self.other_parent_set = result.1;
322 self.other_parent_set = result.1;
329 Ok(packed)
323 Ok(packed)
330 }
324 }
331
325
332 pub fn build_file_fold_map(&mut self) -> FileFoldMap {
326 pub fn build_file_fold_map(&mut self) -> FileFoldMap {
333 if let Some(ref file_fold_map) = self.file_fold_map {
327 if let Some(ref file_fold_map) = self.file_fold_map {
334 return file_fold_map.to_owned();
328 return file_fold_map.to_owned();
335 }
329 }
336 let mut new_file_fold_map = FileFoldMap::new();
330 let mut new_file_fold_map = FileFoldMap::new();
337 for (filename, DirstateEntry { state, .. }) in self.state_map.borrow()
331 for (filename, DirstateEntry { state, .. }) in self.state_map.borrow()
338 {
332 {
339 if *state == EntryState::Removed {
333 if *state == EntryState::Removed {
340 new_file_fold_map.insert(
334 new_file_fold_map.insert(
341 filename.to_ascii_uppercase().to_owned(),
335 filename.to_ascii_uppercase().to_owned(),
342 filename.to_owned(),
336 filename.to_owned(),
343 );
337 );
344 }
338 }
345 }
339 }
346 self.file_fold_map = Some(new_file_fold_map);
340 self.file_fold_map = Some(new_file_fold_map);
347 self.file_fold_map.to_owned().unwrap()
341 self.file_fold_map.to_owned().unwrap()
348 }
342 }
349 }
343 }
350
344
351 #[cfg(test)]
345 #[cfg(test)]
352 mod tests {
346 mod tests {
353 use super::*;
347 use super::*;
354
348
355 #[test]
349 #[test]
356 fn test_dirs_multiset() {
350 fn test_dirs_multiset() {
357 let mut map = DirstateMap::new();
351 let mut map = DirstateMap::new();
358 assert!(map.dirs.is_none());
352 assert!(map.dirs.is_none());
359 assert!(map.all_dirs.is_none());
353 assert!(map.all_dirs.is_none());
360
354
361 assert_eq!(false, map.has_dir(b"nope"));
355 assert_eq!(false, map.has_dir(b"nope"));
362 assert!(map.all_dirs.is_some());
356 assert!(map.all_dirs.is_some());
363 assert!(map.dirs.is_none());
357 assert!(map.dirs.is_none());
364
358
365 assert_eq!(false, map.has_tracked_dir(b"nope"));
359 assert_eq!(false, map.has_tracked_dir(b"nope"));
366 assert!(map.dirs.is_some());
360 assert!(map.dirs.is_some());
367 }
361 }
368
362
369 #[test]
363 #[test]
370 fn test_add_file() {
364 fn test_add_file() {
371 let mut map = DirstateMap::new();
365 let mut map = DirstateMap::new();
372
366
373 assert_eq!(0, map.len());
367 assert_eq!(0, map.len());
374
368
375 map.add_file(
369 map.add_file(
376 b"meh",
370 b"meh",
377 EntryState::Normal,
371 EntryState::Normal,
378 DirstateEntry {
372 DirstateEntry {
379 state: EntryState::Normal,
373 state: EntryState::Normal,
380 mode: 1337,
374 mode: 1337,
381 mtime: 1337,
375 mtime: 1337,
382 size: 1337,
376 size: 1337,
383 },
377 },
384 );
378 );
385
379
386 assert_eq!(1, map.len());
380 assert_eq!(1, map.len());
387 assert_eq!(0, map.non_normal_set.len());
381 assert_eq!(0, map.non_normal_set.len());
388 assert_eq!(0, map.other_parent_set.len());
382 assert_eq!(0, map.other_parent_set.len());
389 }
383 }
390
384
391 #[test]
385 #[test]
392 fn test_non_normal_other_parent_entries() {
386 fn test_non_normal_other_parent_entries() {
393 let map: DirstateMap = [
387 let map: DirstateMap = [
394 (b"f1", (EntryState::Removed, 1337, 1337, 1337)),
388 (b"f1", (EntryState::Removed, 1337, 1337, 1337)),
395 (b"f2", (EntryState::Normal, 1337, 1337, -1)),
389 (b"f2", (EntryState::Normal, 1337, 1337, -1)),
396 (b"f3", (EntryState::Normal, 1337, 1337, 1337)),
390 (b"f3", (EntryState::Normal, 1337, 1337, 1337)),
397 (b"f4", (EntryState::Normal, 1337, -2, 1337)),
391 (b"f4", (EntryState::Normal, 1337, -2, 1337)),
398 (b"f5", (EntryState::Added, 1337, 1337, 1337)),
392 (b"f5", (EntryState::Added, 1337, 1337, 1337)),
399 (b"f6", (EntryState::Added, 1337, 1337, -1)),
393 (b"f6", (EntryState::Added, 1337, 1337, -1)),
400 (b"f7", (EntryState::Merged, 1337, 1337, -1)),
394 (b"f7", (EntryState::Merged, 1337, 1337, -1)),
401 (b"f8", (EntryState::Merged, 1337, 1337, 1337)),
395 (b"f8", (EntryState::Merged, 1337, 1337, 1337)),
402 (b"f9", (EntryState::Merged, 1337, -2, 1337)),
396 (b"f9", (EntryState::Merged, 1337, -2, 1337)),
403 (b"fa", (EntryState::Added, 1337, -2, 1337)),
397 (b"fa", (EntryState::Added, 1337, -2, 1337)),
404 (b"fb", (EntryState::Removed, 1337, -2, 1337)),
398 (b"fb", (EntryState::Removed, 1337, -2, 1337)),
405 ]
399 ]
406 .iter()
400 .iter()
407 .map(|(fname, (state, mode, size, mtime))| {
401 .map(|(fname, (state, mode, size, mtime))| {
408 (
402 (
409 fname.to_vec(),
403 fname.to_vec(),
410 DirstateEntry {
404 DirstateEntry {
411 state: *state,
405 state: *state,
412 mode: *mode,
406 mode: *mode,
413 size: *size,
407 size: *size,
414 mtime: *mtime,
408 mtime: *mtime,
415 },
409 },
416 )
410 )
417 })
411 })
418 .collect();
412 .collect();
419
413
420 let non_normal = [
414 let non_normal = [
421 b"f1", b"f2", b"f5", b"f6", b"f7", b"f8", b"f9", b"fa", b"fb",
415 b"f1", b"f2", b"f5", b"f6", b"f7", b"f8", b"f9", b"fa", b"fb",
422 ]
416 ]
423 .iter()
417 .iter()
424 .map(|x| x.to_vec())
418 .map(|x| x.to_vec())
425 .collect();
419 .collect();
426
420
427 let mut other_parent = HashSet::new();
421 let mut other_parent = HashSet::new();
428 other_parent.insert(b"f4".to_vec());
422 other_parent.insert(b"f4".to_vec());
429
423
430 assert_eq!(
424 assert_eq!(
431 (non_normal, other_parent),
425 (non_normal, other_parent),
432 map.non_normal_other_parent_entries()
426 map.non_normal_other_parent_entries()
433 );
427 );
434 }
428 }
435 }
429 }
General Comments 0
You need to be logged in to leave comments. Login now