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