##// END OF EJS Templates
rust-dirstatemap: directly return `non_normal` and `other_entries`...
Raphaël Gomès -
r44842:c089a094 default
parent child Browse files
Show More
@@ -1,506 +1,478 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, SIZE_FROM_OTHER_PARENT},
9 dirstate::{parsers::PARENT_SIZE, EntryState, SIZE_FROM_OTHER_PARENT},
10 pack_dirstate, parse_dirstate,
10 pack_dirstate, parse_dirstate,
11 utils::{
11 utils::{
12 files::normalize_case,
12 files::normalize_case,
13 hg_path::{HgPath, HgPathBuf},
13 hg_path::{HgPath, HgPathBuf},
14 },
14 },
15 CopyMap, DirsMultiset, DirstateEntry, DirstateError, DirstateMapError,
15 CopyMap, DirsMultiset, DirstateEntry, DirstateError, DirstateMapError,
16 DirstateParents, DirstateParseError, FastHashMap, StateMap,
16 DirstateParents, DirstateParseError, FastHashMap, StateMap,
17 };
17 };
18 use core::borrow::Borrow;
18 use core::borrow::Borrow;
19 use std::collections::HashSet;
19 use std::collections::HashSet;
20 use std::convert::TryInto;
20 use std::convert::TryInto;
21 use std::iter::FromIterator;
21 use std::iter::FromIterator;
22 use std::ops::Deref;
22 use std::ops::Deref;
23 use std::time::Duration;
23 use std::time::Duration;
24
24
25 pub type FileFoldMap = FastHashMap<HgPathBuf, HgPathBuf>;
25 pub type FileFoldMap = FastHashMap<HgPathBuf, HgPathBuf>;
26
26
27 const NULL_ID: [u8; 20] = [0; 20];
27 const NULL_ID: [u8; 20] = [0; 20];
28 const MTIME_UNSET: i32 = -1;
28 const MTIME_UNSET: i32 = -1;
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: Option<HashSet<HgPathBuf>>,
37 non_normal_set: Option<HashSet<HgPathBuf>>,
38 other_parent_set: Option<HashSet<HgPathBuf>>,
38 other_parent_set: Option<HashSet<HgPathBuf>>,
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<(HgPathBuf, DirstateEntry)> for DirstateMap {
52 impl FromIterator<(HgPathBuf, DirstateEntry)> for DirstateMap {
53 fn from_iter<I: IntoIterator<Item = (HgPathBuf, DirstateEntry)>>(
53 fn from_iter<I: IntoIterator<Item = (HgPathBuf, 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 = None;
72 self.non_normal_set = None;
73 self.other_parent_set = None;
73 self.other_parent_set = None;
74 self.set_parents(&DirstateParents {
74 self.set_parents(&DirstateParents {
75 p1: NULL_ID,
75 p1: NULL_ID,
76 p2: NULL_ID,
76 p2: NULL_ID,
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: &HgPath,
83 filename: &HgPath,
84 old_state: EntryState,
84 old_state: EntryState,
85 entry: DirstateEntry,
85 entry: DirstateEntry,
86 ) -> Result<(), DirstateMapError> {
86 ) -> Result<(), DirstateMapError> {
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.get_non_normal_other_parent_entries()
101 self.get_non_normal_other_parent_entries()
102 .0
102 .0
103 .as_mut()
104 .unwrap()
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.size == SIZE_FROM_OTHER_PARENT {
109 self.get_non_normal_other_parent_entries()
107 self.get_non_normal_other_parent_entries()
110 .1
108 .1
111 .as_mut()
112 .unwrap()
113 .insert(filename.to_owned());
109 .insert(filename.to_owned());
114 }
110 }
115 Ok(())
111 Ok(())
116 }
112 }
117
113
118 /// Mark a file as removed in the dirstate.
114 /// Mark a file as removed in the dirstate.
119 ///
115 ///
120 /// The `size` parameter is used to store sentinel values that indicate
116 /// The `size` parameter is used to store sentinel values that indicate
121 /// 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
122 /// to be more explicit about what that state is.
118 /// to be more explicit about what that state is.
123 pub fn remove_file(
119 pub fn remove_file(
124 &mut self,
120 &mut self,
125 filename: &HgPath,
121 filename: &HgPath,
126 old_state: EntryState,
122 old_state: EntryState,
127 size: i32,
123 size: i32,
128 ) -> Result<(), DirstateMapError> {
124 ) -> Result<(), DirstateMapError> {
129 if old_state != EntryState::Unknown && old_state != EntryState::Removed
125 if old_state != EntryState::Unknown && old_state != EntryState::Removed
130 {
126 {
131 if let Some(ref mut dirs) = self.dirs {
127 if let Some(ref mut dirs) = self.dirs {
132 dirs.delete_path(filename)?;
128 dirs.delete_path(filename)?;
133 }
129 }
134 }
130 }
135 if old_state == EntryState::Unknown {
131 if old_state == EntryState::Unknown {
136 if let Some(ref mut all_dirs) = self.all_dirs {
132 if let Some(ref mut all_dirs) = self.all_dirs {
137 all_dirs.add_path(filename)?;
133 all_dirs.add_path(filename)?;
138 }
134 }
139 }
135 }
140
136
141 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 {
142 file_fold_map.remove(&normalize_case(filename));
138 file_fold_map.remove(&normalize_case(filename));
143 }
139 }
144 self.state_map.insert(
140 self.state_map.insert(
145 filename.to_owned(),
141 filename.to_owned(),
146 DirstateEntry {
142 DirstateEntry {
147 state: EntryState::Removed,
143 state: EntryState::Removed,
148 mode: 0,
144 mode: 0,
149 size,
145 size,
150 mtime: 0,
146 mtime: 0,
151 },
147 },
152 );
148 );
153 self.get_non_normal_other_parent_entries()
149 self.get_non_normal_other_parent_entries()
154 .0
150 .0
155 .as_mut()
156 .unwrap()
157 .insert(filename.to_owned());
151 .insert(filename.to_owned());
158 Ok(())
152 Ok(())
159 }
153 }
160
154
161 /// Remove a file from the dirstate.
155 /// Remove a file from the dirstate.
162 /// Returns `true` if the file was previously recorded.
156 /// Returns `true` if the file was previously recorded.
163 pub fn drop_file(
157 pub fn drop_file(
164 &mut self,
158 &mut self,
165 filename: &HgPath,
159 filename: &HgPath,
166 old_state: EntryState,
160 old_state: EntryState,
167 ) -> Result<bool, DirstateMapError> {
161 ) -> Result<bool, DirstateMapError> {
168 let exists = self.state_map.remove(filename).is_some();
162 let exists = self.state_map.remove(filename).is_some();
169
163
170 if exists {
164 if exists {
171 if old_state != EntryState::Removed {
165 if old_state != EntryState::Removed {
172 if let Some(ref mut dirs) = self.dirs {
166 if let Some(ref mut dirs) = self.dirs {
173 dirs.delete_path(filename)?;
167 dirs.delete_path(filename)?;
174 }
168 }
175 }
169 }
176 if let Some(ref mut all_dirs) = self.all_dirs {
170 if let Some(ref mut all_dirs) = self.all_dirs {
177 all_dirs.delete_path(filename)?;
171 all_dirs.delete_path(filename)?;
178 }
172 }
179 }
173 }
180 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 {
181 file_fold_map.remove(&normalize_case(filename));
175 file_fold_map.remove(&normalize_case(filename));
182 }
176 }
183 self.get_non_normal_other_parent_entries()
177 self.get_non_normal_other_parent_entries()
184 .0
178 .0
185 .as_mut()
186 .unwrap()
187 .remove(filename);
179 .remove(filename);
188
180
189 Ok(exists)
181 Ok(exists)
190 }
182 }
191
183
192 pub fn clear_ambiguous_times(
184 pub fn clear_ambiguous_times(
193 &mut self,
185 &mut self,
194 filenames: Vec<HgPathBuf>,
186 filenames: Vec<HgPathBuf>,
195 now: i32,
187 now: i32,
196 ) {
188 ) {
197 for filename in filenames {
189 for filename in filenames {
198 let mut changed = false;
190 let mut changed = false;
199 self.state_map
191 self.state_map
200 .entry(filename.to_owned())
192 .entry(filename.to_owned())
201 .and_modify(|entry| {
193 .and_modify(|entry| {
202 if entry.state == EntryState::Normal && entry.mtime == now
194 if entry.state == EntryState::Normal && entry.mtime == now
203 {
195 {
204 changed = true;
196 changed = true;
205 *entry = DirstateEntry {
197 *entry = DirstateEntry {
206 mtime: MTIME_UNSET,
198 mtime: MTIME_UNSET,
207 ..*entry
199 ..*entry
208 };
200 };
209 }
201 }
210 });
202 });
211 if changed {
203 if changed {
212 self.get_non_normal_other_parent_entries()
204 self.get_non_normal_other_parent_entries()
213 .0
205 .0
214 .as_mut()
215 .unwrap()
216 .insert(filename.to_owned());
206 .insert(filename.to_owned());
217 }
207 }
218 }
208 }
219 }
209 }
220
210
221 pub fn non_normal_entries_remove(
211 pub fn non_normal_entries_remove(
222 &mut self,
212 &mut self,
223 key: impl AsRef<HgPath>,
213 key: impl AsRef<HgPath>,
224 ) -> bool {
214 ) -> bool {
225 self.get_non_normal_other_parent_entries()
215 self.get_non_normal_other_parent_entries()
226 .0
216 .0
227 .as_mut()
228 .unwrap()
229 .remove(key.as_ref())
217 .remove(key.as_ref())
230 }
218 }
231 pub fn non_normal_entries_union(
219 pub fn non_normal_entries_union(
232 &mut self,
220 &mut self,
233 other: HashSet<HgPathBuf>,
221 other: HashSet<HgPathBuf>,
234 ) -> Vec<HgPathBuf> {
222 ) -> Vec<HgPathBuf> {
235 self.get_non_normal_other_parent_entries()
223 self.get_non_normal_other_parent_entries()
236 .0
224 .0
237 .as_mut()
238 .unwrap()
239 .union(&other)
225 .union(&other)
240 .map(|e| e.to_owned())
226 .map(|e| e.to_owned())
241 .collect()
227 .collect()
242 }
228 }
243
229
244 pub fn get_non_normal_other_parent_entries(
230 pub fn get_non_normal_other_parent_entries(
245 &mut self,
231 &mut self,
246 ) -> (
232 ) -> (&mut HashSet<HgPathBuf>, &mut HashSet<HgPathBuf>) {
247 &mut Option<HashSet<HgPathBuf>>,
248 &mut Option<HashSet<HgPathBuf>>,
249 ) {
250 self.set_non_normal_other_parent_entries(false);
233 self.set_non_normal_other_parent_entries(false);
251 (&mut self.non_normal_set, &mut self.other_parent_set)
234 (
235 self.non_normal_set.as_mut().unwrap(),
236 self.other_parent_set.as_mut().unwrap(),
237 )
252 }
238 }
253
239
254 pub fn set_non_normal_other_parent_entries(&mut self, force: bool) {
240 pub fn set_non_normal_other_parent_entries(&mut self, force: bool) {
255 if !force
241 if !force
256 && self.non_normal_set.is_some()
242 && self.non_normal_set.is_some()
257 && self.other_parent_set.is_some()
243 && self.other_parent_set.is_some()
258 {
244 {
259 return;
245 return;
260 }
246 }
261 let mut non_normal = HashSet::new();
247 let mut non_normal = HashSet::new();
262 let mut other_parent = HashSet::new();
248 let mut other_parent = HashSet::new();
263
249
264 for (
250 for (
265 filename,
251 filename,
266 DirstateEntry {
252 DirstateEntry {
267 state, size, mtime, ..
253 state, size, mtime, ..
268 },
254 },
269 ) in self.state_map.iter()
255 ) in self.state_map.iter()
270 {
256 {
271 if *state != EntryState::Normal || *mtime == MTIME_UNSET {
257 if *state != EntryState::Normal || *mtime == MTIME_UNSET {
272 non_normal.insert(filename.to_owned());
258 non_normal.insert(filename.to_owned());
273 }
259 }
274 if *state == EntryState::Normal && *size == SIZE_FROM_OTHER_PARENT
260 if *state == EntryState::Normal && *size == SIZE_FROM_OTHER_PARENT
275 {
261 {
276 other_parent.insert(filename.to_owned());
262 other_parent.insert(filename.to_owned());
277 }
263 }
278 }
264 }
279 self.non_normal_set = Some(non_normal);
265 self.non_normal_set = Some(non_normal);
280 self.other_parent_set = Some(other_parent);
266 self.other_parent_set = Some(other_parent);
281 }
267 }
282
268
283 /// Both of these setters and their uses appear to be the simplest way to
269 /// Both of these setters and their uses appear to be the simplest way to
284 /// emulate a Python lazy property, but it is ugly and unidiomatic.
270 /// emulate a Python lazy property, but it is ugly and unidiomatic.
285 /// TODO One day, rewriting this struct using the typestate might be a
271 /// TODO One day, rewriting this struct using the typestate might be a
286 /// good idea.
272 /// good idea.
287 pub fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> {
273 pub fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> {
288 if self.all_dirs.is_none() {
274 if self.all_dirs.is_none() {
289 self.all_dirs =
275 self.all_dirs =
290 Some(DirsMultiset::from_dirstate(&self.state_map, None)?);
276 Some(DirsMultiset::from_dirstate(&self.state_map, None)?);
291 }
277 }
292 Ok(())
278 Ok(())
293 }
279 }
294
280
295 pub fn set_dirs(&mut self) -> Result<(), DirstateMapError> {
281 pub fn set_dirs(&mut self) -> Result<(), DirstateMapError> {
296 if self.dirs.is_none() {
282 if self.dirs.is_none() {
297 self.dirs = Some(DirsMultiset::from_dirstate(
283 self.dirs = Some(DirsMultiset::from_dirstate(
298 &self.state_map,
284 &self.state_map,
299 Some(EntryState::Removed),
285 Some(EntryState::Removed),
300 )?);
286 )?);
301 }
287 }
302 Ok(())
288 Ok(())
303 }
289 }
304
290
305 pub fn has_tracked_dir(
291 pub fn has_tracked_dir(
306 &mut self,
292 &mut self,
307 directory: &HgPath,
293 directory: &HgPath,
308 ) -> Result<bool, DirstateMapError> {
294 ) -> Result<bool, DirstateMapError> {
309 self.set_dirs()?;
295 self.set_dirs()?;
310 Ok(self.dirs.as_ref().unwrap().contains(directory))
296 Ok(self.dirs.as_ref().unwrap().contains(directory))
311 }
297 }
312
298
313 pub fn has_dir(
299 pub fn has_dir(
314 &mut self,
300 &mut self,
315 directory: &HgPath,
301 directory: &HgPath,
316 ) -> Result<bool, DirstateMapError> {
302 ) -> Result<bool, DirstateMapError> {
317 self.set_all_dirs()?;
303 self.set_all_dirs()?;
318 Ok(self.all_dirs.as_ref().unwrap().contains(directory))
304 Ok(self.all_dirs.as_ref().unwrap().contains(directory))
319 }
305 }
320
306
321 pub fn parents(
307 pub fn parents(
322 &mut self,
308 &mut self,
323 file_contents: &[u8],
309 file_contents: &[u8],
324 ) -> Result<&DirstateParents, DirstateError> {
310 ) -> Result<&DirstateParents, DirstateError> {
325 if let Some(ref parents) = self.parents {
311 if let Some(ref parents) = self.parents {
326 return Ok(parents);
312 return Ok(parents);
327 }
313 }
328 let parents;
314 let parents;
329 if file_contents.len() == PARENT_SIZE * 2 {
315 if file_contents.len() == PARENT_SIZE * 2 {
330 parents = DirstateParents {
316 parents = DirstateParents {
331 p1: file_contents[..PARENT_SIZE].try_into().unwrap(),
317 p1: file_contents[..PARENT_SIZE].try_into().unwrap(),
332 p2: file_contents[PARENT_SIZE..PARENT_SIZE * 2]
318 p2: file_contents[PARENT_SIZE..PARENT_SIZE * 2]
333 .try_into()
319 .try_into()
334 .unwrap(),
320 .unwrap(),
335 };
321 };
336 } else if file_contents.is_empty() {
322 } else if file_contents.is_empty() {
337 parents = DirstateParents {
323 parents = DirstateParents {
338 p1: NULL_ID,
324 p1: NULL_ID,
339 p2: NULL_ID,
325 p2: NULL_ID,
340 };
326 };
341 } else {
327 } else {
342 return Err(DirstateError::Parse(DirstateParseError::Damaged));
328 return Err(DirstateError::Parse(DirstateParseError::Damaged));
343 }
329 }
344
330
345 self.parents = Some(parents);
331 self.parents = Some(parents);
346 Ok(self.parents.as_ref().unwrap())
332 Ok(self.parents.as_ref().unwrap())
347 }
333 }
348
334
349 pub fn set_parents(&mut self, parents: &DirstateParents) {
335 pub fn set_parents(&mut self, parents: &DirstateParents) {
350 self.parents = Some(parents.clone());
336 self.parents = Some(parents.clone());
351 self.dirty_parents = true;
337 self.dirty_parents = true;
352 }
338 }
353
339
354 pub fn read(
340 pub fn read(
355 &mut self,
341 &mut self,
356 file_contents: &[u8],
342 file_contents: &[u8],
357 ) -> Result<Option<DirstateParents>, DirstateError> {
343 ) -> Result<Option<DirstateParents>, DirstateError> {
358 if file_contents.is_empty() {
344 if file_contents.is_empty() {
359 return Ok(None);
345 return Ok(None);
360 }
346 }
361
347
362 let parents = parse_dirstate(
348 let parents = parse_dirstate(
363 &mut self.state_map,
349 &mut self.state_map,
364 &mut self.copy_map,
350 &mut self.copy_map,
365 file_contents,
351 file_contents,
366 )?;
352 )?;
367
353
368 if !self.dirty_parents {
354 if !self.dirty_parents {
369 self.set_parents(&parents);
355 self.set_parents(&parents);
370 }
356 }
371
357
372 Ok(Some(parents))
358 Ok(Some(parents))
373 }
359 }
374
360
375 pub fn pack(
361 pub fn pack(
376 &mut self,
362 &mut self,
377 parents: DirstateParents,
363 parents: DirstateParents,
378 now: Duration,
364 now: Duration,
379 ) -> Result<Vec<u8>, DirstateError> {
365 ) -> Result<Vec<u8>, DirstateError> {
380 let packed =
366 let packed =
381 pack_dirstate(&mut self.state_map, &self.copy_map, parents, now)?;
367 pack_dirstate(&mut self.state_map, &self.copy_map, parents, now)?;
382
368
383 self.dirty_parents = false;
369 self.dirty_parents = false;
384
370
385 self.set_non_normal_other_parent_entries(true);
371 self.set_non_normal_other_parent_entries(true);
386 Ok(packed)
372 Ok(packed)
387 }
373 }
388
374
389 pub fn build_file_fold_map(&mut self) -> &FileFoldMap {
375 pub fn build_file_fold_map(&mut self) -> &FileFoldMap {
390 if let Some(ref file_fold_map) = self.file_fold_map {
376 if let Some(ref file_fold_map) = self.file_fold_map {
391 return file_fold_map;
377 return file_fold_map;
392 }
378 }
393 let mut new_file_fold_map = FileFoldMap::default();
379 let mut new_file_fold_map = FileFoldMap::default();
394 for (filename, DirstateEntry { state, .. }) in self.state_map.borrow()
380 for (filename, DirstateEntry { state, .. }) in self.state_map.borrow()
395 {
381 {
396 if *state == EntryState::Removed {
382 if *state == EntryState::Removed {
397 new_file_fold_map
383 new_file_fold_map
398 .insert(normalize_case(filename), filename.to_owned());
384 .insert(normalize_case(filename), filename.to_owned());
399 }
385 }
400 }
386 }
401 self.file_fold_map = Some(new_file_fold_map);
387 self.file_fold_map = Some(new_file_fold_map);
402 self.file_fold_map.as_ref().unwrap()
388 self.file_fold_map.as_ref().unwrap()
403 }
389 }
404 }
390 }
405
391
406 #[cfg(test)]
392 #[cfg(test)]
407 mod tests {
393 mod tests {
408 use super::*;
394 use super::*;
409
395
410 #[test]
396 #[test]
411 fn test_dirs_multiset() {
397 fn test_dirs_multiset() {
412 let mut map = DirstateMap::new();
398 let mut map = DirstateMap::new();
413 assert!(map.dirs.is_none());
399 assert!(map.dirs.is_none());
414 assert!(map.all_dirs.is_none());
400 assert!(map.all_dirs.is_none());
415
401
416 assert_eq!(map.has_dir(HgPath::new(b"nope")).unwrap(), false);
402 assert_eq!(map.has_dir(HgPath::new(b"nope")).unwrap(), false);
417 assert!(map.all_dirs.is_some());
403 assert!(map.all_dirs.is_some());
418 assert!(map.dirs.is_none());
404 assert!(map.dirs.is_none());
419
405
420 assert_eq!(map.has_tracked_dir(HgPath::new(b"nope")).unwrap(), false);
406 assert_eq!(map.has_tracked_dir(HgPath::new(b"nope")).unwrap(), false);
421 assert!(map.dirs.is_some());
407 assert!(map.dirs.is_some());
422 }
408 }
423
409
424 #[test]
410 #[test]
425 fn test_add_file() {
411 fn test_add_file() {
426 let mut map = DirstateMap::new();
412 let mut map = DirstateMap::new();
427
413
428 assert_eq!(0, map.len());
414 assert_eq!(0, map.len());
429
415
430 map.add_file(
416 map.add_file(
431 HgPath::new(b"meh"),
417 HgPath::new(b"meh"),
432 EntryState::Normal,
418 EntryState::Normal,
433 DirstateEntry {
419 DirstateEntry {
434 state: EntryState::Normal,
420 state: EntryState::Normal,
435 mode: 1337,
421 mode: 1337,
436 mtime: 1337,
422 mtime: 1337,
437 size: 1337,
423 size: 1337,
438 },
424 },
439 )
425 )
440 .unwrap();
426 .unwrap();
441
427
442 assert_eq!(1, map.len());
428 assert_eq!(1, map.len());
443 assert_eq!(
429 assert_eq!(0, map.get_non_normal_other_parent_entries().0.len());
444 0,
430 assert_eq!(0, map.get_non_normal_other_parent_entries().1.len());
445 map.get_non_normal_other_parent_entries()
446 .0
447 .as_ref()
448 .unwrap()
449 .len()
450 );
451 assert_eq!(
452 0,
453 map.get_non_normal_other_parent_entries()
454 .1
455 .as_ref()
456 .unwrap()
457 .len()
458 );
459 }
431 }
460
432
461 #[test]
433 #[test]
462 fn test_non_normal_other_parent_entries() {
434 fn test_non_normal_other_parent_entries() {
463 let mut map: DirstateMap = [
435 let mut map: DirstateMap = [
464 (b"f1", (EntryState::Removed, 1337, 1337, 1337)),
436 (b"f1", (EntryState::Removed, 1337, 1337, 1337)),
465 (b"f2", (EntryState::Normal, 1337, 1337, -1)),
437 (b"f2", (EntryState::Normal, 1337, 1337, -1)),
466 (b"f3", (EntryState::Normal, 1337, 1337, 1337)),
438 (b"f3", (EntryState::Normal, 1337, 1337, 1337)),
467 (b"f4", (EntryState::Normal, 1337, -2, 1337)),
439 (b"f4", (EntryState::Normal, 1337, -2, 1337)),
468 (b"f5", (EntryState::Added, 1337, 1337, 1337)),
440 (b"f5", (EntryState::Added, 1337, 1337, 1337)),
469 (b"f6", (EntryState::Added, 1337, 1337, -1)),
441 (b"f6", (EntryState::Added, 1337, 1337, -1)),
470 (b"f7", (EntryState::Merged, 1337, 1337, -1)),
442 (b"f7", (EntryState::Merged, 1337, 1337, -1)),
471 (b"f8", (EntryState::Merged, 1337, 1337, 1337)),
443 (b"f8", (EntryState::Merged, 1337, 1337, 1337)),
472 (b"f9", (EntryState::Merged, 1337, -2, 1337)),
444 (b"f9", (EntryState::Merged, 1337, -2, 1337)),
473 (b"fa", (EntryState::Added, 1337, -2, 1337)),
445 (b"fa", (EntryState::Added, 1337, -2, 1337)),
474 (b"fb", (EntryState::Removed, 1337, -2, 1337)),
446 (b"fb", (EntryState::Removed, 1337, -2, 1337)),
475 ]
447 ]
476 .iter()
448 .iter()
477 .map(|(fname, (state, mode, size, mtime))| {
449 .map(|(fname, (state, mode, size, mtime))| {
478 (
450 (
479 HgPathBuf::from_bytes(fname.as_ref()),
451 HgPathBuf::from_bytes(fname.as_ref()),
480 DirstateEntry {
452 DirstateEntry {
481 state: *state,
453 state: *state,
482 mode: *mode,
454 mode: *mode,
483 size: *size,
455 size: *size,
484 mtime: *mtime,
456 mtime: *mtime,
485 },
457 },
486 )
458 )
487 })
459 })
488 .collect();
460 .collect();
489
461
490 let non_normal = [
462 let mut non_normal = [
491 b"f1", b"f2", b"f5", b"f6", b"f7", b"f8", b"f9", b"fa", b"fb",
463 b"f1", b"f2", b"f5", b"f6", b"f7", b"f8", b"f9", b"fa", b"fb",
492 ]
464 ]
493 .iter()
465 .iter()
494 .map(|x| HgPathBuf::from_bytes(x.as_ref()))
466 .map(|x| HgPathBuf::from_bytes(x.as_ref()))
495 .collect();
467 .collect();
496
468
497 let mut other_parent = HashSet::new();
469 let mut other_parent = HashSet::new();
498 other_parent.insert(HgPathBuf::from_bytes(b"f4"));
470 other_parent.insert(HgPathBuf::from_bytes(b"f4"));
499 let entries = map.get_non_normal_other_parent_entries();
471 let entries = map.get_non_normal_other_parent_entries();
500
472
501 assert_eq!(
473 assert_eq!(
502 (Some(non_normal), Some(other_parent)),
474 (&mut non_normal, &mut other_parent),
503 (entries.0.to_owned(), entries.1.to_owned())
475 (entries.0, entries.1)
504 );
476 );
505 }
477 }
506 }
478 }
@@ -1,572 +1,568 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 //! Bindings for the `hg::dirstate::dirstate_map` file provided by the
8 //! Bindings for the `hg::dirstate::dirstate_map` file provided by the
9 //! `hg-core` package.
9 //! `hg-core` package.
10
10
11 use std::cell::{Ref, RefCell};
11 use std::cell::{Ref, RefCell};
12 use std::convert::TryInto;
12 use std::convert::TryInto;
13 use std::time::Duration;
13 use std::time::Duration;
14
14
15 use cpython::{
15 use cpython::{
16 exc, ObjectProtocol, PyBool, PyBytes, PyClone, PyDict, PyErr, PyList,
16 exc, ObjectProtocol, PyBool, PyBytes, PyClone, PyDict, PyErr, PyList,
17 PyObject, PyResult, PyString, PyTuple, Python, PythonObject, ToPyObject,
17 PyObject, PyResult, PyString, PyTuple, Python, PythonObject, ToPyObject,
18 UnsafePyLeaked,
18 UnsafePyLeaked,
19 };
19 };
20
20
21 use crate::{
21 use crate::{
22 dirstate::copymap::{CopyMap, CopyMapItemsIterator, CopyMapKeysIterator},
22 dirstate::copymap::{CopyMap, CopyMapItemsIterator, CopyMapKeysIterator},
23 dirstate::non_normal_entries::NonNormalEntries,
23 dirstate::non_normal_entries::NonNormalEntries,
24 dirstate::{dirs_multiset::Dirs, make_dirstate_tuple},
24 dirstate::{dirs_multiset::Dirs, make_dirstate_tuple},
25 };
25 };
26 use hg::{
26 use hg::{
27 utils::hg_path::{HgPath, HgPathBuf},
27 utils::hg_path::{HgPath, HgPathBuf},
28 DirsMultiset, DirstateEntry, DirstateMap as RustDirstateMap,
28 DirsMultiset, DirstateEntry, DirstateMap as RustDirstateMap,
29 DirstateMapError, DirstateParents, DirstateParseError, EntryState,
29 DirstateMapError, DirstateParents, DirstateParseError, EntryState,
30 StateMapIter, PARENT_SIZE,
30 StateMapIter, PARENT_SIZE,
31 };
31 };
32
32
33 // TODO
33 // TODO
34 // This object needs to share references to multiple members of its Rust
34 // This object needs to share references to multiple members of its Rust
35 // inner struct, namely `copy_map`, `dirs` and `all_dirs`.
35 // inner struct, namely `copy_map`, `dirs` and `all_dirs`.
36 // Right now `CopyMap` is done, but it needs to have an explicit reference
36 // Right now `CopyMap` is done, but it needs to have an explicit reference
37 // to `RustDirstateMap` which itself needs to have an encapsulation for
37 // to `RustDirstateMap` which itself needs to have an encapsulation for
38 // every method in `CopyMap` (copymapcopy, etc.).
38 // every method in `CopyMap` (copymapcopy, etc.).
39 // This is ugly and hard to maintain.
39 // This is ugly and hard to maintain.
40 // The same logic applies to `dirs` and `all_dirs`, however the `Dirs`
40 // The same logic applies to `dirs` and `all_dirs`, however the `Dirs`
41 // `py_class!` is already implemented and does not mention
41 // `py_class!` is already implemented and does not mention
42 // `RustDirstateMap`, rightfully so.
42 // `RustDirstateMap`, rightfully so.
43 // All attributes also have to have a separate refcount data attribute for
43 // All attributes also have to have a separate refcount data attribute for
44 // leaks, with all methods that go along for reference sharing.
44 // leaks, with all methods that go along for reference sharing.
45 py_class!(pub class DirstateMap |py| {
45 py_class!(pub class DirstateMap |py| {
46 @shared data inner: RustDirstateMap;
46 @shared data inner: RustDirstateMap;
47
47
48 def __new__(_cls, _root: PyObject) -> PyResult<Self> {
48 def __new__(_cls, _root: PyObject) -> PyResult<Self> {
49 let inner = RustDirstateMap::default();
49 let inner = RustDirstateMap::default();
50 Self::create_instance(py, inner)
50 Self::create_instance(py, inner)
51 }
51 }
52
52
53 def clear(&self) -> PyResult<PyObject> {
53 def clear(&self) -> PyResult<PyObject> {
54 self.inner(py).borrow_mut().clear();
54 self.inner(py).borrow_mut().clear();
55 Ok(py.None())
55 Ok(py.None())
56 }
56 }
57
57
58 def get(
58 def get(
59 &self,
59 &self,
60 key: PyObject,
60 key: PyObject,
61 default: Option<PyObject> = None
61 default: Option<PyObject> = None
62 ) -> PyResult<Option<PyObject>> {
62 ) -> PyResult<Option<PyObject>> {
63 let key = key.extract::<PyBytes>(py)?;
63 let key = key.extract::<PyBytes>(py)?;
64 match self.inner(py).borrow().get(HgPath::new(key.data(py))) {
64 match self.inner(py).borrow().get(HgPath::new(key.data(py))) {
65 Some(entry) => {
65 Some(entry) => {
66 Ok(Some(make_dirstate_tuple(py, entry)?))
66 Ok(Some(make_dirstate_tuple(py, entry)?))
67 },
67 },
68 None => Ok(default)
68 None => Ok(default)
69 }
69 }
70 }
70 }
71
71
72 def addfile(
72 def addfile(
73 &self,
73 &self,
74 f: PyObject,
74 f: PyObject,
75 oldstate: PyObject,
75 oldstate: PyObject,
76 state: PyObject,
76 state: PyObject,
77 mode: PyObject,
77 mode: PyObject,
78 size: PyObject,
78 size: PyObject,
79 mtime: PyObject
79 mtime: PyObject
80 ) -> PyResult<PyObject> {
80 ) -> PyResult<PyObject> {
81 self.inner(py).borrow_mut().add_file(
81 self.inner(py).borrow_mut().add_file(
82 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
82 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
83 oldstate.extract::<PyBytes>(py)?.data(py)[0]
83 oldstate.extract::<PyBytes>(py)?.data(py)[0]
84 .try_into()
84 .try_into()
85 .map_err(|e: DirstateParseError| {
85 .map_err(|e: DirstateParseError| {
86 PyErr::new::<exc::ValueError, _>(py, e.to_string())
86 PyErr::new::<exc::ValueError, _>(py, e.to_string())
87 })?,
87 })?,
88 DirstateEntry {
88 DirstateEntry {
89 state: state.extract::<PyBytes>(py)?.data(py)[0]
89 state: state.extract::<PyBytes>(py)?.data(py)[0]
90 .try_into()
90 .try_into()
91 .map_err(|e: DirstateParseError| {
91 .map_err(|e: DirstateParseError| {
92 PyErr::new::<exc::ValueError, _>(py, e.to_string())
92 PyErr::new::<exc::ValueError, _>(py, e.to_string())
93 })?,
93 })?,
94 mode: mode.extract(py)?,
94 mode: mode.extract(py)?,
95 size: size.extract(py)?,
95 size: size.extract(py)?,
96 mtime: mtime.extract(py)?,
96 mtime: mtime.extract(py)?,
97 },
97 },
98 ).and(Ok(py.None())).or_else(|e: DirstateMapError| {
98 ).and(Ok(py.None())).or_else(|e: DirstateMapError| {
99 Err(PyErr::new::<exc::ValueError, _>(py, e.to_string()))
99 Err(PyErr::new::<exc::ValueError, _>(py, e.to_string()))
100 })
100 })
101 }
101 }
102
102
103 def removefile(
103 def removefile(
104 &self,
104 &self,
105 f: PyObject,
105 f: PyObject,
106 oldstate: PyObject,
106 oldstate: PyObject,
107 size: PyObject
107 size: PyObject
108 ) -> PyResult<PyObject> {
108 ) -> PyResult<PyObject> {
109 self.inner(py).borrow_mut()
109 self.inner(py).borrow_mut()
110 .remove_file(
110 .remove_file(
111 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
111 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
112 oldstate.extract::<PyBytes>(py)?.data(py)[0]
112 oldstate.extract::<PyBytes>(py)?.data(py)[0]
113 .try_into()
113 .try_into()
114 .map_err(|e: DirstateParseError| {
114 .map_err(|e: DirstateParseError| {
115 PyErr::new::<exc::ValueError, _>(py, e.to_string())
115 PyErr::new::<exc::ValueError, _>(py, e.to_string())
116 })?,
116 })?,
117 size.extract(py)?,
117 size.extract(py)?,
118 )
118 )
119 .or_else(|_| {
119 .or_else(|_| {
120 Err(PyErr::new::<exc::OSError, _>(
120 Err(PyErr::new::<exc::OSError, _>(
121 py,
121 py,
122 "Dirstate error".to_string(),
122 "Dirstate error".to_string(),
123 ))
123 ))
124 })?;
124 })?;
125 Ok(py.None())
125 Ok(py.None())
126 }
126 }
127
127
128 def dropfile(
128 def dropfile(
129 &self,
129 &self,
130 f: PyObject,
130 f: PyObject,
131 oldstate: PyObject
131 oldstate: PyObject
132 ) -> PyResult<PyBool> {
132 ) -> PyResult<PyBool> {
133 self.inner(py).borrow_mut()
133 self.inner(py).borrow_mut()
134 .drop_file(
134 .drop_file(
135 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
135 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
136 oldstate.extract::<PyBytes>(py)?.data(py)[0]
136 oldstate.extract::<PyBytes>(py)?.data(py)[0]
137 .try_into()
137 .try_into()
138 .map_err(|e: DirstateParseError| {
138 .map_err(|e: DirstateParseError| {
139 PyErr::new::<exc::ValueError, _>(py, e.to_string())
139 PyErr::new::<exc::ValueError, _>(py, e.to_string())
140 })?,
140 })?,
141 )
141 )
142 .and_then(|b| Ok(b.to_py_object(py)))
142 .and_then(|b| Ok(b.to_py_object(py)))
143 .or_else(|_| {
143 .or_else(|_| {
144 Err(PyErr::new::<exc::OSError, _>(
144 Err(PyErr::new::<exc::OSError, _>(
145 py,
145 py,
146 "Dirstate error".to_string(),
146 "Dirstate error".to_string(),
147 ))
147 ))
148 })
148 })
149 }
149 }
150
150
151 def clearambiguoustimes(
151 def clearambiguoustimes(
152 &self,
152 &self,
153 files: PyObject,
153 files: PyObject,
154 now: PyObject
154 now: PyObject
155 ) -> PyResult<PyObject> {
155 ) -> PyResult<PyObject> {
156 let files: PyResult<Vec<HgPathBuf>> = files
156 let files: PyResult<Vec<HgPathBuf>> = files
157 .iter(py)?
157 .iter(py)?
158 .map(|filename| {
158 .map(|filename| {
159 Ok(HgPathBuf::from_bytes(
159 Ok(HgPathBuf::from_bytes(
160 filename?.extract::<PyBytes>(py)?.data(py),
160 filename?.extract::<PyBytes>(py)?.data(py),
161 ))
161 ))
162 })
162 })
163 .collect();
163 .collect();
164 self.inner(py).borrow_mut()
164 self.inner(py).borrow_mut()
165 .clear_ambiguous_times(files?, now.extract(py)?);
165 .clear_ambiguous_times(files?, now.extract(py)?);
166 Ok(py.None())
166 Ok(py.None())
167 }
167 }
168
168
169 def other_parent_entries(&self) -> PyResult<PyObject> {
169 def other_parent_entries(&self) -> PyResult<PyObject> {
170 let mut inner_shared = self.inner(py).borrow_mut();
170 let mut inner_shared = self.inner(py).borrow_mut();
171 let (_, other_parent) =
171 let (_, other_parent) =
172 inner_shared.get_non_normal_other_parent_entries();
172 inner_shared.get_non_normal_other_parent_entries();
173
173
174 let locals = PyDict::new(py);
174 let locals = PyDict::new(py);
175 locals.set_item(
175 locals.set_item(
176 py,
176 py,
177 "other_parent",
177 "other_parent",
178 other_parent.as_ref()
178 other_parent
179 .unwrap()
180 .iter()
179 .iter()
181 .map(|v| PyBytes::new(py, v.as_ref()))
180 .map(|v| PyBytes::new(py, v.as_ref()))
182 .collect::<Vec<PyBytes>>()
181 .collect::<Vec<PyBytes>>()
183 .to_py_object(py),
182 .to_py_object(py),
184 )?;
183 )?;
185
184
186 py.eval("set(other_parent)", None, Some(&locals))
185 py.eval("set(other_parent)", None, Some(&locals))
187 }
186 }
188
187
189 def non_normal_entries(&self) -> PyResult<NonNormalEntries> {
188 def non_normal_entries(&self) -> PyResult<NonNormalEntries> {
190 NonNormalEntries::from_inner(py, self.clone_ref(py))
189 NonNormalEntries::from_inner(py, self.clone_ref(py))
191 }
190 }
192
191
193 def non_normal_entries_contains(&self, key: PyObject) -> PyResult<bool> {
192 def non_normal_entries_contains(&self, key: PyObject) -> PyResult<bool> {
194 let key = key.extract::<PyBytes>(py)?;
193 let key = key.extract::<PyBytes>(py)?;
195 Ok(self
194 Ok(self
196 .inner(py)
195 .inner(py)
197 .borrow_mut()
196 .borrow_mut()
198 .get_non_normal_other_parent_entries().0
197 .get_non_normal_other_parent_entries().0
199 .as_ref()
200 .unwrap()
201 .contains(HgPath::new(key.data(py))))
198 .contains(HgPath::new(key.data(py))))
202 }
199 }
203
200
204 def non_normal_entries_display(&self) -> PyResult<PyString> {
201 def non_normal_entries_display(&self) -> PyResult<PyString> {
205 Ok(
202 Ok(
206 PyString::new(
203 PyString::new(
207 py,
204 py,
208 &format!(
205 &format!(
209 "NonNormalEntries: {:?}",
206 "NonNormalEntries: {:?}",
210 self
207 self
211 .inner(py)
208 .inner(py)
212 .borrow_mut()
209 .borrow_mut()
213 .get_non_normal_other_parent_entries().0
210 .get_non_normal_other_parent_entries().0
214 .as_ref()
211 .iter().map(|o| o))
215 .unwrap().iter().map(|o| o))
216 )
212 )
217 )
213 )
218 }
214 }
219
215
220 def non_normal_entries_remove(&self, key: PyObject) -> PyResult<PyObject> {
216 def non_normal_entries_remove(&self, key: PyObject) -> PyResult<PyObject> {
221 let key = key.extract::<PyBytes>(py)?;
217 let key = key.extract::<PyBytes>(py)?;
222 self
218 self
223 .inner(py)
219 .inner(py)
224 .borrow_mut()
220 .borrow_mut()
225 .non_normal_entries_remove(HgPath::new(key.data(py)));
221 .non_normal_entries_remove(HgPath::new(key.data(py)));
226 Ok(py.None())
222 Ok(py.None())
227 }
223 }
228
224
229 def non_normal_entries_union(&self, other: PyObject) -> PyResult<PyList> {
225 def non_normal_entries_union(&self, other: PyObject) -> PyResult<PyList> {
230 let other: PyResult<_> = other.iter(py)?
226 let other: PyResult<_> = other.iter(py)?
231 .map(|f| {
227 .map(|f| {
232 Ok(HgPathBuf::from_bytes(
228 Ok(HgPathBuf::from_bytes(
233 f?.extract::<PyBytes>(py)?.data(py),
229 f?.extract::<PyBytes>(py)?.data(py),
234 ))
230 ))
235 })
231 })
236 .collect();
232 .collect();
237
233
238 let res = self
234 let res = self
239 .inner(py)
235 .inner(py)
240 .borrow_mut()
236 .borrow_mut()
241 .non_normal_entries_union(other?);
237 .non_normal_entries_union(other?);
242
238
243 let ret = PyList::new(py, &[]);
239 let ret = PyList::new(py, &[]);
244 for filename in res.iter() {
240 for filename in res.iter() {
245 let as_pystring = PyBytes::new(py, filename.as_bytes());
241 let as_pystring = PyBytes::new(py, filename.as_bytes());
246 ret.append(py, as_pystring.into_object());
242 ret.append(py, as_pystring.into_object());
247 }
243 }
248 Ok(ret)
244 Ok(ret)
249 }
245 }
250
246
251 def hastrackeddir(&self, d: PyObject) -> PyResult<PyBool> {
247 def hastrackeddir(&self, d: PyObject) -> PyResult<PyBool> {
252 let d = d.extract::<PyBytes>(py)?;
248 let d = d.extract::<PyBytes>(py)?;
253 Ok(self.inner(py).borrow_mut()
249 Ok(self.inner(py).borrow_mut()
254 .has_tracked_dir(HgPath::new(d.data(py)))
250 .has_tracked_dir(HgPath::new(d.data(py)))
255 .map_err(|e| {
251 .map_err(|e| {
256 PyErr::new::<exc::ValueError, _>(py, e.to_string())
252 PyErr::new::<exc::ValueError, _>(py, e.to_string())
257 })?
253 })?
258 .to_py_object(py))
254 .to_py_object(py))
259 }
255 }
260
256
261 def hasdir(&self, d: PyObject) -> PyResult<PyBool> {
257 def hasdir(&self, d: PyObject) -> PyResult<PyBool> {
262 let d = d.extract::<PyBytes>(py)?;
258 let d = d.extract::<PyBytes>(py)?;
263 Ok(self.inner(py).borrow_mut()
259 Ok(self.inner(py).borrow_mut()
264 .has_dir(HgPath::new(d.data(py)))
260 .has_dir(HgPath::new(d.data(py)))
265 .map_err(|e| {
261 .map_err(|e| {
266 PyErr::new::<exc::ValueError, _>(py, e.to_string())
262 PyErr::new::<exc::ValueError, _>(py, e.to_string())
267 })?
263 })?
268 .to_py_object(py))
264 .to_py_object(py))
269 }
265 }
270
266
271 def parents(&self, st: PyObject) -> PyResult<PyTuple> {
267 def parents(&self, st: PyObject) -> PyResult<PyTuple> {
272 self.inner(py).borrow_mut()
268 self.inner(py).borrow_mut()
273 .parents(st.extract::<PyBytes>(py)?.data(py))
269 .parents(st.extract::<PyBytes>(py)?.data(py))
274 .and_then(|d| {
270 .and_then(|d| {
275 Ok((PyBytes::new(py, &d.p1), PyBytes::new(py, &d.p2))
271 Ok((PyBytes::new(py, &d.p1), PyBytes::new(py, &d.p2))
276 .to_py_object(py))
272 .to_py_object(py))
277 })
273 })
278 .or_else(|_| {
274 .or_else(|_| {
279 Err(PyErr::new::<exc::OSError, _>(
275 Err(PyErr::new::<exc::OSError, _>(
280 py,
276 py,
281 "Dirstate error".to_string(),
277 "Dirstate error".to_string(),
282 ))
278 ))
283 })
279 })
284 }
280 }
285
281
286 def setparents(&self, p1: PyObject, p2: PyObject) -> PyResult<PyObject> {
282 def setparents(&self, p1: PyObject, p2: PyObject) -> PyResult<PyObject> {
287 let p1 = extract_node_id(py, &p1)?;
283 let p1 = extract_node_id(py, &p1)?;
288 let p2 = extract_node_id(py, &p2)?;
284 let p2 = extract_node_id(py, &p2)?;
289
285
290 self.inner(py).borrow_mut()
286 self.inner(py).borrow_mut()
291 .set_parents(&DirstateParents { p1, p2 });
287 .set_parents(&DirstateParents { p1, p2 });
292 Ok(py.None())
288 Ok(py.None())
293 }
289 }
294
290
295 def read(&self, st: PyObject) -> PyResult<Option<PyObject>> {
291 def read(&self, st: PyObject) -> PyResult<Option<PyObject>> {
296 match self.inner(py).borrow_mut()
292 match self.inner(py).borrow_mut()
297 .read(st.extract::<PyBytes>(py)?.data(py))
293 .read(st.extract::<PyBytes>(py)?.data(py))
298 {
294 {
299 Ok(Some(parents)) => Ok(Some(
295 Ok(Some(parents)) => Ok(Some(
300 (PyBytes::new(py, &parents.p1), PyBytes::new(py, &parents.p2))
296 (PyBytes::new(py, &parents.p1), PyBytes::new(py, &parents.p2))
301 .to_py_object(py)
297 .to_py_object(py)
302 .into_object(),
298 .into_object(),
303 )),
299 )),
304 Ok(None) => Ok(Some(py.None())),
300 Ok(None) => Ok(Some(py.None())),
305 Err(_) => Err(PyErr::new::<exc::OSError, _>(
301 Err(_) => Err(PyErr::new::<exc::OSError, _>(
306 py,
302 py,
307 "Dirstate error".to_string(),
303 "Dirstate error".to_string(),
308 )),
304 )),
309 }
305 }
310 }
306 }
311 def write(
307 def write(
312 &self,
308 &self,
313 p1: PyObject,
309 p1: PyObject,
314 p2: PyObject,
310 p2: PyObject,
315 now: PyObject
311 now: PyObject
316 ) -> PyResult<PyBytes> {
312 ) -> PyResult<PyBytes> {
317 let now = Duration::new(now.extract(py)?, 0);
313 let now = Duration::new(now.extract(py)?, 0);
318 let parents = DirstateParents {
314 let parents = DirstateParents {
319 p1: extract_node_id(py, &p1)?,
315 p1: extract_node_id(py, &p1)?,
320 p2: extract_node_id(py, &p2)?,
316 p2: extract_node_id(py, &p2)?,
321 };
317 };
322
318
323 match self.inner(py).borrow_mut().pack(parents, now) {
319 match self.inner(py).borrow_mut().pack(parents, now) {
324 Ok(packed) => Ok(PyBytes::new(py, &packed)),
320 Ok(packed) => Ok(PyBytes::new(py, &packed)),
325 Err(_) => Err(PyErr::new::<exc::OSError, _>(
321 Err(_) => Err(PyErr::new::<exc::OSError, _>(
326 py,
322 py,
327 "Dirstate error".to_string(),
323 "Dirstate error".to_string(),
328 )),
324 )),
329 }
325 }
330 }
326 }
331
327
332 def filefoldmapasdict(&self) -> PyResult<PyDict> {
328 def filefoldmapasdict(&self) -> PyResult<PyDict> {
333 let dict = PyDict::new(py);
329 let dict = PyDict::new(py);
334 for (key, value) in
330 for (key, value) in
335 self.inner(py).borrow_mut().build_file_fold_map().iter()
331 self.inner(py).borrow_mut().build_file_fold_map().iter()
336 {
332 {
337 dict.set_item(py, key.as_ref().to_vec(), value.as_ref().to_vec())?;
333 dict.set_item(py, key.as_ref().to_vec(), value.as_ref().to_vec())?;
338 }
334 }
339 Ok(dict)
335 Ok(dict)
340 }
336 }
341
337
342 def __len__(&self) -> PyResult<usize> {
338 def __len__(&self) -> PyResult<usize> {
343 Ok(self.inner(py).borrow().len())
339 Ok(self.inner(py).borrow().len())
344 }
340 }
345
341
346 def __contains__(&self, key: PyObject) -> PyResult<bool> {
342 def __contains__(&self, key: PyObject) -> PyResult<bool> {
347 let key = key.extract::<PyBytes>(py)?;
343 let key = key.extract::<PyBytes>(py)?;
348 Ok(self.inner(py).borrow().contains_key(HgPath::new(key.data(py))))
344 Ok(self.inner(py).borrow().contains_key(HgPath::new(key.data(py))))
349 }
345 }
350
346
351 def __getitem__(&self, key: PyObject) -> PyResult<PyObject> {
347 def __getitem__(&self, key: PyObject) -> PyResult<PyObject> {
352 let key = key.extract::<PyBytes>(py)?;
348 let key = key.extract::<PyBytes>(py)?;
353 let key = HgPath::new(key.data(py));
349 let key = HgPath::new(key.data(py));
354 match self.inner(py).borrow().get(key) {
350 match self.inner(py).borrow().get(key) {
355 Some(entry) => {
351 Some(entry) => {
356 Ok(make_dirstate_tuple(py, entry)?)
352 Ok(make_dirstate_tuple(py, entry)?)
357 },
353 },
358 None => Err(PyErr::new::<exc::KeyError, _>(
354 None => Err(PyErr::new::<exc::KeyError, _>(
359 py,
355 py,
360 String::from_utf8_lossy(key.as_bytes()),
356 String::from_utf8_lossy(key.as_bytes()),
361 )),
357 )),
362 }
358 }
363 }
359 }
364
360
365 def keys(&self) -> PyResult<DirstateMapKeysIterator> {
361 def keys(&self) -> PyResult<DirstateMapKeysIterator> {
366 let leaked_ref = self.inner(py).leak_immutable();
362 let leaked_ref = self.inner(py).leak_immutable();
367 DirstateMapKeysIterator::from_inner(
363 DirstateMapKeysIterator::from_inner(
368 py,
364 py,
369 unsafe { leaked_ref.map(py, |o| o.iter()) },
365 unsafe { leaked_ref.map(py, |o| o.iter()) },
370 )
366 )
371 }
367 }
372
368
373 def items(&self) -> PyResult<DirstateMapItemsIterator> {
369 def items(&self) -> PyResult<DirstateMapItemsIterator> {
374 let leaked_ref = self.inner(py).leak_immutable();
370 let leaked_ref = self.inner(py).leak_immutable();
375 DirstateMapItemsIterator::from_inner(
371 DirstateMapItemsIterator::from_inner(
376 py,
372 py,
377 unsafe { leaked_ref.map(py, |o| o.iter()) },
373 unsafe { leaked_ref.map(py, |o| o.iter()) },
378 )
374 )
379 }
375 }
380
376
381 def __iter__(&self) -> PyResult<DirstateMapKeysIterator> {
377 def __iter__(&self) -> PyResult<DirstateMapKeysIterator> {
382 let leaked_ref = self.inner(py).leak_immutable();
378 let leaked_ref = self.inner(py).leak_immutable();
383 DirstateMapKeysIterator::from_inner(
379 DirstateMapKeysIterator::from_inner(
384 py,
380 py,
385 unsafe { leaked_ref.map(py, |o| o.iter()) },
381 unsafe { leaked_ref.map(py, |o| o.iter()) },
386 )
382 )
387 }
383 }
388
384
389 def getdirs(&self) -> PyResult<Dirs> {
385 def getdirs(&self) -> PyResult<Dirs> {
390 // TODO don't copy, share the reference
386 // TODO don't copy, share the reference
391 self.inner(py).borrow_mut().set_dirs()
387 self.inner(py).borrow_mut().set_dirs()
392 .map_err(|e| {
388 .map_err(|e| {
393 PyErr::new::<exc::ValueError, _>(py, e.to_string())
389 PyErr::new::<exc::ValueError, _>(py, e.to_string())
394 })?;
390 })?;
395 Dirs::from_inner(
391 Dirs::from_inner(
396 py,
392 py,
397 DirsMultiset::from_dirstate(
393 DirsMultiset::from_dirstate(
398 &self.inner(py).borrow(),
394 &self.inner(py).borrow(),
399 Some(EntryState::Removed),
395 Some(EntryState::Removed),
400 )
396 )
401 .map_err(|e| {
397 .map_err(|e| {
402 PyErr::new::<exc::ValueError, _>(py, e.to_string())
398 PyErr::new::<exc::ValueError, _>(py, e.to_string())
403 })?,
399 })?,
404 )
400 )
405 }
401 }
406 def getalldirs(&self) -> PyResult<Dirs> {
402 def getalldirs(&self) -> PyResult<Dirs> {
407 // TODO don't copy, share the reference
403 // TODO don't copy, share the reference
408 self.inner(py).borrow_mut().set_all_dirs()
404 self.inner(py).borrow_mut().set_all_dirs()
409 .map_err(|e| {
405 .map_err(|e| {
410 PyErr::new::<exc::ValueError, _>(py, e.to_string())
406 PyErr::new::<exc::ValueError, _>(py, e.to_string())
411 })?;
407 })?;
412 Dirs::from_inner(
408 Dirs::from_inner(
413 py,
409 py,
414 DirsMultiset::from_dirstate(
410 DirsMultiset::from_dirstate(
415 &self.inner(py).borrow(),
411 &self.inner(py).borrow(),
416 None,
412 None,
417 ).map_err(|e| {
413 ).map_err(|e| {
418 PyErr::new::<exc::ValueError, _>(py, e.to_string())
414 PyErr::new::<exc::ValueError, _>(py, e.to_string())
419 })?,
415 })?,
420 )
416 )
421 }
417 }
422
418
423 // TODO all copymap* methods, see docstring above
419 // TODO all copymap* methods, see docstring above
424 def copymapcopy(&self) -> PyResult<PyDict> {
420 def copymapcopy(&self) -> PyResult<PyDict> {
425 let dict = PyDict::new(py);
421 let dict = PyDict::new(py);
426 for (key, value) in self.inner(py).borrow().copy_map.iter() {
422 for (key, value) in self.inner(py).borrow().copy_map.iter() {
427 dict.set_item(
423 dict.set_item(
428 py,
424 py,
429 PyBytes::new(py, key.as_ref()),
425 PyBytes::new(py, key.as_ref()),
430 PyBytes::new(py, value.as_ref()),
426 PyBytes::new(py, value.as_ref()),
431 )?;
427 )?;
432 }
428 }
433 Ok(dict)
429 Ok(dict)
434 }
430 }
435
431
436 def copymapgetitem(&self, key: PyObject) -> PyResult<PyBytes> {
432 def copymapgetitem(&self, key: PyObject) -> PyResult<PyBytes> {
437 let key = key.extract::<PyBytes>(py)?;
433 let key = key.extract::<PyBytes>(py)?;
438 match self.inner(py).borrow().copy_map.get(HgPath::new(key.data(py))) {
434 match self.inner(py).borrow().copy_map.get(HgPath::new(key.data(py))) {
439 Some(copy) => Ok(PyBytes::new(py, copy.as_ref())),
435 Some(copy) => Ok(PyBytes::new(py, copy.as_ref())),
440 None => Err(PyErr::new::<exc::KeyError, _>(
436 None => Err(PyErr::new::<exc::KeyError, _>(
441 py,
437 py,
442 String::from_utf8_lossy(key.data(py)),
438 String::from_utf8_lossy(key.data(py)),
443 )),
439 )),
444 }
440 }
445 }
441 }
446 def copymap(&self) -> PyResult<CopyMap> {
442 def copymap(&self) -> PyResult<CopyMap> {
447 CopyMap::from_inner(py, self.clone_ref(py))
443 CopyMap::from_inner(py, self.clone_ref(py))
448 }
444 }
449
445
450 def copymaplen(&self) -> PyResult<usize> {
446 def copymaplen(&self) -> PyResult<usize> {
451 Ok(self.inner(py).borrow().copy_map.len())
447 Ok(self.inner(py).borrow().copy_map.len())
452 }
448 }
453 def copymapcontains(&self, key: PyObject) -> PyResult<bool> {
449 def copymapcontains(&self, key: PyObject) -> PyResult<bool> {
454 let key = key.extract::<PyBytes>(py)?;
450 let key = key.extract::<PyBytes>(py)?;
455 Ok(self
451 Ok(self
456 .inner(py)
452 .inner(py)
457 .borrow()
453 .borrow()
458 .copy_map
454 .copy_map
459 .contains_key(HgPath::new(key.data(py))))
455 .contains_key(HgPath::new(key.data(py))))
460 }
456 }
461 def copymapget(
457 def copymapget(
462 &self,
458 &self,
463 key: PyObject,
459 key: PyObject,
464 default: Option<PyObject>
460 default: Option<PyObject>
465 ) -> PyResult<Option<PyObject>> {
461 ) -> PyResult<Option<PyObject>> {
466 let key = key.extract::<PyBytes>(py)?;
462 let key = key.extract::<PyBytes>(py)?;
467 match self
463 match self
468 .inner(py)
464 .inner(py)
469 .borrow()
465 .borrow()
470 .copy_map
466 .copy_map
471 .get(HgPath::new(key.data(py)))
467 .get(HgPath::new(key.data(py)))
472 {
468 {
473 Some(copy) => Ok(Some(
469 Some(copy) => Ok(Some(
474 PyBytes::new(py, copy.as_ref()).into_object(),
470 PyBytes::new(py, copy.as_ref()).into_object(),
475 )),
471 )),
476 None => Ok(default),
472 None => Ok(default),
477 }
473 }
478 }
474 }
479 def copymapsetitem(
475 def copymapsetitem(
480 &self,
476 &self,
481 key: PyObject,
477 key: PyObject,
482 value: PyObject
478 value: PyObject
483 ) -> PyResult<PyObject> {
479 ) -> PyResult<PyObject> {
484 let key = key.extract::<PyBytes>(py)?;
480 let key = key.extract::<PyBytes>(py)?;
485 let value = value.extract::<PyBytes>(py)?;
481 let value = value.extract::<PyBytes>(py)?;
486 self.inner(py).borrow_mut().copy_map.insert(
482 self.inner(py).borrow_mut().copy_map.insert(
487 HgPathBuf::from_bytes(key.data(py)),
483 HgPathBuf::from_bytes(key.data(py)),
488 HgPathBuf::from_bytes(value.data(py)),
484 HgPathBuf::from_bytes(value.data(py)),
489 );
485 );
490 Ok(py.None())
486 Ok(py.None())
491 }
487 }
492 def copymappop(
488 def copymappop(
493 &self,
489 &self,
494 key: PyObject,
490 key: PyObject,
495 default: Option<PyObject>
491 default: Option<PyObject>
496 ) -> PyResult<Option<PyObject>> {
492 ) -> PyResult<Option<PyObject>> {
497 let key = key.extract::<PyBytes>(py)?;
493 let key = key.extract::<PyBytes>(py)?;
498 match self
494 match self
499 .inner(py)
495 .inner(py)
500 .borrow_mut()
496 .borrow_mut()
501 .copy_map
497 .copy_map
502 .remove(HgPath::new(key.data(py)))
498 .remove(HgPath::new(key.data(py)))
503 {
499 {
504 Some(_) => Ok(None),
500 Some(_) => Ok(None),
505 None => Ok(default),
501 None => Ok(default),
506 }
502 }
507 }
503 }
508
504
509 def copymapiter(&self) -> PyResult<CopyMapKeysIterator> {
505 def copymapiter(&self) -> PyResult<CopyMapKeysIterator> {
510 let leaked_ref = self.inner(py).leak_immutable();
506 let leaked_ref = self.inner(py).leak_immutable();
511 CopyMapKeysIterator::from_inner(
507 CopyMapKeysIterator::from_inner(
512 py,
508 py,
513 unsafe { leaked_ref.map(py, |o| o.copy_map.iter()) },
509 unsafe { leaked_ref.map(py, |o| o.copy_map.iter()) },
514 )
510 )
515 }
511 }
516
512
517 def copymapitemsiter(&self) -> PyResult<CopyMapItemsIterator> {
513 def copymapitemsiter(&self) -> PyResult<CopyMapItemsIterator> {
518 let leaked_ref = self.inner(py).leak_immutable();
514 let leaked_ref = self.inner(py).leak_immutable();
519 CopyMapItemsIterator::from_inner(
515 CopyMapItemsIterator::from_inner(
520 py,
516 py,
521 unsafe { leaked_ref.map(py, |o| o.copy_map.iter()) },
517 unsafe { leaked_ref.map(py, |o| o.copy_map.iter()) },
522 )
518 )
523 }
519 }
524
520
525 });
521 });
526
522
527 impl DirstateMap {
523 impl DirstateMap {
528 pub fn get_inner<'a>(
524 pub fn get_inner<'a>(
529 &'a self,
525 &'a self,
530 py: Python<'a>,
526 py: Python<'a>,
531 ) -> Ref<'a, RustDirstateMap> {
527 ) -> Ref<'a, RustDirstateMap> {
532 self.inner(py).borrow()
528 self.inner(py).borrow()
533 }
529 }
534 fn translate_key(
530 fn translate_key(
535 py: Python,
531 py: Python,
536 res: (&HgPathBuf, &DirstateEntry),
532 res: (&HgPathBuf, &DirstateEntry),
537 ) -> PyResult<Option<PyBytes>> {
533 ) -> PyResult<Option<PyBytes>> {
538 Ok(Some(PyBytes::new(py, res.0.as_ref())))
534 Ok(Some(PyBytes::new(py, res.0.as_ref())))
539 }
535 }
540 fn translate_key_value(
536 fn translate_key_value(
541 py: Python,
537 py: Python,
542 res: (&HgPathBuf, &DirstateEntry),
538 res: (&HgPathBuf, &DirstateEntry),
543 ) -> PyResult<Option<(PyBytes, PyObject)>> {
539 ) -> PyResult<Option<(PyBytes, PyObject)>> {
544 let (f, entry) = res;
540 let (f, entry) = res;
545 Ok(Some((
541 Ok(Some((
546 PyBytes::new(py, f.as_ref()),
542 PyBytes::new(py, f.as_ref()),
547 make_dirstate_tuple(py, entry)?,
543 make_dirstate_tuple(py, entry)?,
548 )))
544 )))
549 }
545 }
550 }
546 }
551
547
552 py_shared_iterator!(
548 py_shared_iterator!(
553 DirstateMapKeysIterator,
549 DirstateMapKeysIterator,
554 UnsafePyLeaked<StateMapIter<'static>>,
550 UnsafePyLeaked<StateMapIter<'static>>,
555 DirstateMap::translate_key,
551 DirstateMap::translate_key,
556 Option<PyBytes>
552 Option<PyBytes>
557 );
553 );
558
554
559 py_shared_iterator!(
555 py_shared_iterator!(
560 DirstateMapItemsIterator,
556 DirstateMapItemsIterator,
561 UnsafePyLeaked<StateMapIter<'static>>,
557 UnsafePyLeaked<StateMapIter<'static>>,
562 DirstateMap::translate_key_value,
558 DirstateMap::translate_key_value,
563 Option<(PyBytes, PyObject)>
559 Option<(PyBytes, PyObject)>
564 );
560 );
565
561
566 fn extract_node_id(py: Python, obj: &PyObject) -> PyResult<[u8; PARENT_SIZE]> {
562 fn extract_node_id(py: Python, obj: &PyObject) -> PyResult<[u8; PARENT_SIZE]> {
567 let bytes = obj.extract::<PyBytes>(py)?;
563 let bytes = obj.extract::<PyBytes>(py)?;
568 match bytes.data(py).try_into() {
564 match bytes.data(py).try_into() {
569 Ok(s) => Ok(s),
565 Ok(s) => Ok(s),
570 Err(e) => Err(PyErr::new::<exc::ValueError, _>(py, e.to_string())),
566 Err(e) => Err(PyErr::new::<exc::ValueError, _>(py, e.to_string())),
571 }
567 }
572 }
568 }
General Comments 0
You need to be logged in to leave comments. Login now