##// END OF EJS Templates
rust-dirstate: improve API of `DirsMultiset`...
Raphaël Gomès -
r42977:4f9dff6f default draft
parent child Browse files
Show More
@@ -1,341 +1,341 b''
1 // dirs_multiset.rs
1 // dirs_multiset.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 //! A multiset of directory names.
8 //! A multiset of directory names.
9 //!
9 //!
10 //! Used to counts the references to directories in a manifest or dirstate.
10 //! Used to counts the references to directories in a manifest or dirstate.
11 use crate::{
11 use crate::{
12 dirstate::EntryState, utils::files, DirsIterable, DirstateEntry,
12 dirstate::EntryState, utils::files, DirsIterable, DirstateEntry,
13 DirstateMapError,
13 DirstateMapError,
14 };
14 };
15 use std::collections::hash_map::{Entry, Iter};
15 use std::collections::hash_map::Entry;
16 use std::collections::HashMap;
16 use std::collections::HashMap;
17
17
18 #[derive(PartialEq, Debug)]
18 #[derive(PartialEq, Debug)]
19 pub struct DirsMultiset {
19 pub struct DirsMultiset {
20 inner: HashMap<Vec<u8>, u32>,
20 inner: HashMap<Vec<u8>, u32>,
21 }
21 }
22
22
23 impl DirsMultiset {
23 impl DirsMultiset {
24 /// Initializes the multiset from a dirstate or a manifest.
24 /// Initializes the multiset from a dirstate or a manifest.
25 ///
25 ///
26 /// If `skip_state` is provided, skips dirstate entries with equal state.
26 /// If `skip_state` is provided, skips dirstate entries with equal state.
27 pub fn new(
27 pub fn new(
28 iterable: DirsIterable,
28 iterable: DirsIterable,
29 skip_state: Option<EntryState>,
29 skip_state: Option<EntryState>,
30 ) -> Self {
30 ) -> Self {
31 let mut multiset = DirsMultiset {
31 let mut multiset = DirsMultiset {
32 inner: HashMap::new(),
32 inner: HashMap::new(),
33 };
33 };
34
34
35 match iterable {
35 match iterable {
36 DirsIterable::Dirstate(vec) => {
36 DirsIterable::Dirstate(vec) => {
37 for (filename, DirstateEntry { state, .. }) in vec {
37 for (filename, DirstateEntry { state, .. }) in vec {
38 // This `if` is optimized out of the loop
38 // This `if` is optimized out of the loop
39 if let Some(skip) = skip_state {
39 if let Some(skip) = skip_state {
40 if skip != *state {
40 if skip != *state {
41 multiset.add_path(filename);
41 multiset.add_path(filename);
42 }
42 }
43 } else {
43 } else {
44 multiset.add_path(filename);
44 multiset.add_path(filename);
45 }
45 }
46 }
46 }
47 }
47 }
48 DirsIterable::Manifest(vec) => {
48 DirsIterable::Manifest(vec) => {
49 for filename in vec {
49 for filename in vec {
50 multiset.add_path(filename);
50 multiset.add_path(filename);
51 }
51 }
52 }
52 }
53 }
53 }
54
54
55 multiset
55 multiset
56 }
56 }
57
57
58 /// Increases the count of deepest directory contained in the path.
58 /// Increases the count of deepest directory contained in the path.
59 ///
59 ///
60 /// If the directory is not yet in the map, adds its parents.
60 /// If the directory is not yet in the map, adds its parents.
61 pub fn add_path(&mut self, path: &[u8]) {
61 pub fn add_path(&mut self, path: &[u8]) {
62 for subpath in files::find_dirs(path) {
62 for subpath in files::find_dirs(path) {
63 if let Some(val) = self.inner.get_mut(subpath) {
63 if let Some(val) = self.inner.get_mut(subpath) {
64 *val += 1;
64 *val += 1;
65 break;
65 break;
66 }
66 }
67 self.inner.insert(subpath.to_owned(), 1);
67 self.inner.insert(subpath.to_owned(), 1);
68 }
68 }
69 }
69 }
70
70
71 /// Decreases the count of deepest directory contained in the path.
71 /// Decreases the count of deepest directory contained in the path.
72 ///
72 ///
73 /// If it is the only reference, decreases all parents until one is
73 /// If it is the only reference, decreases all parents until one is
74 /// removed.
74 /// removed.
75 /// If the directory is not in the map, something horrible has happened.
75 /// If the directory is not in the map, something horrible has happened.
76 pub fn delete_path(
76 pub fn delete_path(
77 &mut self,
77 &mut self,
78 path: &[u8],
78 path: &[u8],
79 ) -> Result<(), DirstateMapError> {
79 ) -> Result<(), DirstateMapError> {
80 for subpath in files::find_dirs(path) {
80 for subpath in files::find_dirs(path) {
81 match self.inner.entry(subpath.to_owned()) {
81 match self.inner.entry(subpath.to_owned()) {
82 Entry::Occupied(mut entry) => {
82 Entry::Occupied(mut entry) => {
83 let val = entry.get().clone();
83 let val = entry.get().clone();
84 if val > 1 {
84 if val > 1 {
85 entry.insert(val - 1);
85 entry.insert(val - 1);
86 break;
86 break;
87 }
87 }
88 entry.remove();
88 entry.remove();
89 }
89 }
90 Entry::Vacant(_) => {
90 Entry::Vacant(_) => {
91 return Err(DirstateMapError::PathNotFound(
91 return Err(DirstateMapError::PathNotFound(
92 path.to_owned(),
92 path.to_owned(),
93 ))
93 ))
94 }
94 }
95 };
95 };
96 }
96 }
97
97
98 Ok(())
98 Ok(())
99 }
99 }
100
100
101 pub fn contains_key(&self, key: &[u8]) -> bool {
101 pub fn contains(&self, key: &[u8]) -> bool {
102 self.inner.contains_key(key)
102 self.inner.contains_key(key)
103 }
103 }
104
104
105 pub fn iter(&self) -> Iter<Vec<u8>, u32> {
105 pub fn iter(&self) -> impl Iterator<Item = &Vec<u8>> {
106 self.inner.iter()
106 self.inner.keys()
107 }
107 }
108
108
109 pub fn len(&self) -> usize {
109 pub fn len(&self) -> usize {
110 self.inner.len()
110 self.inner.len()
111 }
111 }
112 }
112 }
113
113
114 #[cfg(test)]
114 #[cfg(test)]
115 mod tests {
115 mod tests {
116 use super::*;
116 use super::*;
117 use std::collections::HashMap;
117 use std::collections::HashMap;
118
118
119 #[test]
119 #[test]
120 fn test_delete_path_path_not_found() {
120 fn test_delete_path_path_not_found() {
121 let mut map = DirsMultiset::new(DirsIterable::Manifest(&vec![]), None);
121 let mut map = DirsMultiset::new(DirsIterable::Manifest(&vec![]), None);
122 let path = b"doesnotexist/";
122 let path = b"doesnotexist/";
123 assert_eq!(
123 assert_eq!(
124 Err(DirstateMapError::PathNotFound(path.to_vec())),
124 Err(DirstateMapError::PathNotFound(path.to_vec())),
125 map.delete_path(path)
125 map.delete_path(path)
126 );
126 );
127 }
127 }
128
128
129 #[test]
129 #[test]
130 fn test_delete_path_empty_path() {
130 fn test_delete_path_empty_path() {
131 let mut map =
131 let mut map =
132 DirsMultiset::new(DirsIterable::Manifest(&vec![vec![]]), None);
132 DirsMultiset::new(DirsIterable::Manifest(&vec![vec![]]), None);
133 let path = b"";
133 let path = b"";
134 assert_eq!(Ok(()), map.delete_path(path));
134 assert_eq!(Ok(()), map.delete_path(path));
135 assert_eq!(
135 assert_eq!(
136 Err(DirstateMapError::PathNotFound(path.to_vec())),
136 Err(DirstateMapError::PathNotFound(path.to_vec())),
137 map.delete_path(path)
137 map.delete_path(path)
138 );
138 );
139 }
139 }
140
140
141 #[test]
141 #[test]
142 fn test_delete_path_successful() {
142 fn test_delete_path_successful() {
143 let mut map = DirsMultiset {
143 let mut map = DirsMultiset {
144 inner: [("", 5), ("a", 3), ("a/b", 2), ("a/c", 1)]
144 inner: [("", 5), ("a", 3), ("a/b", 2), ("a/c", 1)]
145 .iter()
145 .iter()
146 .map(|(k, v)| (k.as_bytes().to_vec(), *v))
146 .map(|(k, v)| (k.as_bytes().to_vec(), *v))
147 .collect(),
147 .collect(),
148 };
148 };
149
149
150 assert_eq!(Ok(()), map.delete_path(b"a/b/"));
150 assert_eq!(Ok(()), map.delete_path(b"a/b/"));
151 assert_eq!(Ok(()), map.delete_path(b"a/b/"));
151 assert_eq!(Ok(()), map.delete_path(b"a/b/"));
152 assert_eq!(
152 assert_eq!(
153 Err(DirstateMapError::PathNotFound(b"a/b/".to_vec())),
153 Err(DirstateMapError::PathNotFound(b"a/b/".to_vec())),
154 map.delete_path(b"a/b/")
154 map.delete_path(b"a/b/")
155 );
155 );
156
156
157 assert_eq!(2, *map.inner.get(&b"a".to_vec()).unwrap());
157 assert_eq!(2, *map.inner.get(&b"a".to_vec()).unwrap());
158 assert_eq!(1, *map.inner.get(&b"a/c".to_vec()).unwrap());
158 assert_eq!(1, *map.inner.get(&b"a/c".to_vec()).unwrap());
159 eprintln!("{:?}", map);
159 eprintln!("{:?}", map);
160 assert_eq!(Ok(()), map.delete_path(b"a/"));
160 assert_eq!(Ok(()), map.delete_path(b"a/"));
161 eprintln!("{:?}", map);
161 eprintln!("{:?}", map);
162
162
163 assert_eq!(Ok(()), map.delete_path(b"a/c/"));
163 assert_eq!(Ok(()), map.delete_path(b"a/c/"));
164 assert_eq!(
164 assert_eq!(
165 Err(DirstateMapError::PathNotFound(b"a/c/".to_vec())),
165 Err(DirstateMapError::PathNotFound(b"a/c/".to_vec())),
166 map.delete_path(b"a/c/")
166 map.delete_path(b"a/c/")
167 );
167 );
168 }
168 }
169
169
170 #[test]
170 #[test]
171 fn test_add_path_empty_path() {
171 fn test_add_path_empty_path() {
172 let mut map = DirsMultiset::new(DirsIterable::Manifest(&vec![]), None);
172 let mut map = DirsMultiset::new(DirsIterable::Manifest(&vec![]), None);
173 let path = b"";
173 let path = b"";
174 map.add_path(path);
174 map.add_path(path);
175
175
176 assert_eq!(1, map.len());
176 assert_eq!(1, map.len());
177 }
177 }
178
178
179 #[test]
179 #[test]
180 fn test_add_path_successful() {
180 fn test_add_path_successful() {
181 let mut map = DirsMultiset::new(DirsIterable::Manifest(&vec![]), None);
181 let mut map = DirsMultiset::new(DirsIterable::Manifest(&vec![]), None);
182
182
183 map.add_path(b"a/");
183 map.add_path(b"a/");
184 assert_eq!(1, *map.inner.get(&b"a".to_vec()).unwrap());
184 assert_eq!(1, *map.inner.get(&b"a".to_vec()).unwrap());
185 assert_eq!(1, *map.inner.get(&Vec::new()).unwrap());
185 assert_eq!(1, *map.inner.get(&Vec::new()).unwrap());
186 assert_eq!(2, map.len());
186 assert_eq!(2, map.len());
187
187
188 // Non directory should be ignored
188 // Non directory should be ignored
189 map.add_path(b"a");
189 map.add_path(b"a");
190 assert_eq!(1, *map.inner.get(&b"a".to_vec()).unwrap());
190 assert_eq!(1, *map.inner.get(&b"a".to_vec()).unwrap());
191 assert_eq!(2, map.len());
191 assert_eq!(2, map.len());
192
192
193 // Non directory will still add its base
193 // Non directory will still add its base
194 map.add_path(b"a/b");
194 map.add_path(b"a/b");
195 assert_eq!(2, *map.inner.get(&b"a".to_vec()).unwrap());
195 assert_eq!(2, *map.inner.get(&b"a".to_vec()).unwrap());
196 assert_eq!(2, map.len());
196 assert_eq!(2, map.len());
197
197
198 // Duplicate path works
198 // Duplicate path works
199 map.add_path(b"a/");
199 map.add_path(b"a/");
200 assert_eq!(3, *map.inner.get(&b"a".to_vec()).unwrap());
200 assert_eq!(3, *map.inner.get(&b"a".to_vec()).unwrap());
201
201
202 // Nested dir adds to its base
202 // Nested dir adds to its base
203 map.add_path(b"a/b/");
203 map.add_path(b"a/b/");
204 assert_eq!(4, *map.inner.get(&b"a".to_vec()).unwrap());
204 assert_eq!(4, *map.inner.get(&b"a".to_vec()).unwrap());
205 assert_eq!(1, *map.inner.get(&b"a/b".to_vec()).unwrap());
205 assert_eq!(1, *map.inner.get(&b"a/b".to_vec()).unwrap());
206
206
207 // but not its base's base, because it already existed
207 // but not its base's base, because it already existed
208 map.add_path(b"a/b/c/");
208 map.add_path(b"a/b/c/");
209 assert_eq!(4, *map.inner.get(&b"a".to_vec()).unwrap());
209 assert_eq!(4, *map.inner.get(&b"a".to_vec()).unwrap());
210 assert_eq!(2, *map.inner.get(&b"a/b".to_vec()).unwrap());
210 assert_eq!(2, *map.inner.get(&b"a/b".to_vec()).unwrap());
211
211
212 map.add_path(b"a/c/");
212 map.add_path(b"a/c/");
213 assert_eq!(1, *map.inner.get(&b"a/c".to_vec()).unwrap());
213 assert_eq!(1, *map.inner.get(&b"a/c".to_vec()).unwrap());
214
214
215 let expected = DirsMultiset {
215 let expected = DirsMultiset {
216 inner: [("", 2), ("a", 5), ("a/b", 2), ("a/b/c", 1), ("a/c", 1)]
216 inner: [("", 2), ("a", 5), ("a/b", 2), ("a/b/c", 1), ("a/c", 1)]
217 .iter()
217 .iter()
218 .map(|(k, v)| (k.as_bytes().to_vec(), *v))
218 .map(|(k, v)| (k.as_bytes().to_vec(), *v))
219 .collect(),
219 .collect(),
220 };
220 };
221 assert_eq!(map, expected);
221 assert_eq!(map, expected);
222 }
222 }
223
223
224 #[test]
224 #[test]
225 fn test_dirsmultiset_new_empty() {
225 fn test_dirsmultiset_new_empty() {
226 use DirsIterable::{Dirstate, Manifest};
226 use DirsIterable::{Dirstate, Manifest};
227
227
228 let new = DirsMultiset::new(Manifest(&vec![]), None);
228 let new = DirsMultiset::new(Manifest(&vec![]), None);
229 let expected = DirsMultiset {
229 let expected = DirsMultiset {
230 inner: HashMap::new(),
230 inner: HashMap::new(),
231 };
231 };
232 assert_eq!(expected, new);
232 assert_eq!(expected, new);
233
233
234 let new = DirsMultiset::new(Dirstate(&HashMap::new()), None);
234 let new = DirsMultiset::new(Dirstate(&HashMap::new()), None);
235 let expected = DirsMultiset {
235 let expected = DirsMultiset {
236 inner: HashMap::new(),
236 inner: HashMap::new(),
237 };
237 };
238 assert_eq!(expected, new);
238 assert_eq!(expected, new);
239 }
239 }
240
240
241 #[test]
241 #[test]
242 fn test_dirsmultiset_new_no_skip() {
242 fn test_dirsmultiset_new_no_skip() {
243 use DirsIterable::{Dirstate, Manifest};
243 use DirsIterable::{Dirstate, Manifest};
244
244
245 let input_vec = ["a/", "b/", "a/c", "a/d/"]
245 let input_vec = ["a/", "b/", "a/c", "a/d/"]
246 .iter()
246 .iter()
247 .map(|e| e.as_bytes().to_vec())
247 .map(|e| e.as_bytes().to_vec())
248 .collect();
248 .collect();
249 let expected_inner = [("", 2), ("a", 3), ("b", 1), ("a/d", 1)]
249 let expected_inner = [("", 2), ("a", 3), ("b", 1), ("a/d", 1)]
250 .iter()
250 .iter()
251 .map(|(k, v)| (k.as_bytes().to_vec(), *v))
251 .map(|(k, v)| (k.as_bytes().to_vec(), *v))
252 .collect();
252 .collect();
253
253
254 let new = DirsMultiset::new(Manifest(&input_vec), None);
254 let new = DirsMultiset::new(Manifest(&input_vec), None);
255 let expected = DirsMultiset {
255 let expected = DirsMultiset {
256 inner: expected_inner,
256 inner: expected_inner,
257 };
257 };
258 assert_eq!(expected, new);
258 assert_eq!(expected, new);
259
259
260 let input_map = ["a/", "b/", "a/c", "a/d/"]
260 let input_map = ["a/", "b/", "a/c", "a/d/"]
261 .iter()
261 .iter()
262 .map(|f| {
262 .map(|f| {
263 (
263 (
264 f.as_bytes().to_vec(),
264 f.as_bytes().to_vec(),
265 DirstateEntry {
265 DirstateEntry {
266 state: EntryState::Normal,
266 state: EntryState::Normal,
267 mode: 0,
267 mode: 0,
268 mtime: 0,
268 mtime: 0,
269 size: 0,
269 size: 0,
270 },
270 },
271 )
271 )
272 })
272 })
273 .collect();
273 .collect();
274 let expected_inner = [("", 2), ("a", 3), ("b", 1), ("a/d", 1)]
274 let expected_inner = [("", 2), ("a", 3), ("b", 1), ("a/d", 1)]
275 .iter()
275 .iter()
276 .map(|(k, v)| (k.as_bytes().to_vec(), *v))
276 .map(|(k, v)| (k.as_bytes().to_vec(), *v))
277 .collect();
277 .collect();
278
278
279 let new = DirsMultiset::new(Dirstate(&input_map), None);
279 let new = DirsMultiset::new(Dirstate(&input_map), None);
280 let expected = DirsMultiset {
280 let expected = DirsMultiset {
281 inner: expected_inner,
281 inner: expected_inner,
282 };
282 };
283 assert_eq!(expected, new);
283 assert_eq!(expected, new);
284 }
284 }
285
285
286 #[test]
286 #[test]
287 fn test_dirsmultiset_new_skip() {
287 fn test_dirsmultiset_new_skip() {
288 use DirsIterable::{Dirstate, Manifest};
288 use DirsIterable::{Dirstate, Manifest};
289
289
290 let input_vec = ["a/", "b/", "a/c", "a/d/"]
290 let input_vec = ["a/", "b/", "a/c", "a/d/"]
291 .iter()
291 .iter()
292 .map(|e| e.as_bytes().to_vec())
292 .map(|e| e.as_bytes().to_vec())
293 .collect();
293 .collect();
294 let expected_inner = [("", 2), ("a", 3), ("b", 1), ("a/d", 1)]
294 let expected_inner = [("", 2), ("a", 3), ("b", 1), ("a/d", 1)]
295 .iter()
295 .iter()
296 .map(|(k, v)| (k.as_bytes().to_vec(), *v))
296 .map(|(k, v)| (k.as_bytes().to_vec(), *v))
297 .collect();
297 .collect();
298
298
299 let new =
299 let new =
300 DirsMultiset::new(Manifest(&input_vec), Some(EntryState::Normal));
300 DirsMultiset::new(Manifest(&input_vec), Some(EntryState::Normal));
301 let expected = DirsMultiset {
301 let expected = DirsMultiset {
302 inner: expected_inner,
302 inner: expected_inner,
303 };
303 };
304 // Skip does not affect a manifest
304 // Skip does not affect a manifest
305 assert_eq!(expected, new);
305 assert_eq!(expected, new);
306
306
307 let input_map = [
307 let input_map = [
308 ("a/", EntryState::Normal),
308 ("a/", EntryState::Normal),
309 ("a/b/", EntryState::Normal),
309 ("a/b/", EntryState::Normal),
310 ("a/c", EntryState::Removed),
310 ("a/c", EntryState::Removed),
311 ("a/d/", EntryState::Merged),
311 ("a/d/", EntryState::Merged),
312 ]
312 ]
313 .iter()
313 .iter()
314 .map(|(f, state)| {
314 .map(|(f, state)| {
315 (
315 (
316 f.as_bytes().to_vec(),
316 f.as_bytes().to_vec(),
317 DirstateEntry {
317 DirstateEntry {
318 state: *state,
318 state: *state,
319 mode: 0,
319 mode: 0,
320 mtime: 0,
320 mtime: 0,
321 size: 0,
321 size: 0,
322 },
322 },
323 )
323 )
324 })
324 })
325 .collect();
325 .collect();
326
326
327 // "a" incremented with "a/c" and "a/d/"
327 // "a" incremented with "a/c" and "a/d/"
328 let expected_inner = [("", 1), ("a", 2), ("a/d", 1)]
328 let expected_inner = [("", 1), ("a", 2), ("a/d", 1)]
329 .iter()
329 .iter()
330 .map(|(k, v)| (k.as_bytes().to_vec(), *v))
330 .map(|(k, v)| (k.as_bytes().to_vec(), *v))
331 .collect();
331 .collect();
332
332
333 let new =
333 let new =
334 DirsMultiset::new(Dirstate(&input_map), Some(EntryState::Normal));
334 DirsMultiset::new(Dirstate(&input_map), Some(EntryState::Normal));
335 let expected = DirsMultiset {
335 let expected = DirsMultiset {
336 inner: expected_inner,
336 inner: expected_inner,
337 };
337 };
338 assert_eq!(expected, new);
338 assert_eq!(expected, new);
339 }
339 }
340
340
341 }
341 }
@@ -1,118 +1,113 b''
1 // dirs_multiset.rs
1 // dirs_multiset.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::dirs_multiset` file provided by the
8 //! Bindings for the `hg::dirstate::dirs_multiset` file provided by the
9 //! `hg-core` package.
9 //! `hg-core` package.
10
10
11 use std::cell::RefCell;
11 use std::cell::RefCell;
12
12
13 use cpython::{
13 use cpython::{
14 exc, ObjectProtocol, PyBytes, PyDict, PyErr, PyObject, PyResult,
14 exc, ObjectProtocol, PyBytes, PyDict, PyErr, PyObject, PyResult,
15 ToPyObject,
15 PythonObject, ToPyObject,
16 };
16 };
17
17
18 use crate::dirstate::extract_dirstate;
18 use crate::dirstate::extract_dirstate;
19 use hg::{
19 use hg::{
20 DirsIterable, DirsMultiset, DirstateMapError, DirstateParseError,
20 DirsIterable, DirsMultiset, DirstateMapError, DirstateParseError,
21 EntryState,
21 EntryState,
22 };
22 };
23 use std::convert::TryInto;
23 use std::convert::TryInto;
24
24
25 py_class!(pub class Dirs |py| {
25 py_class!(pub class Dirs |py| {
26 data dirs_map: RefCell<DirsMultiset>;
26 data dirs_map: RefCell<DirsMultiset>;
27
27
28 // `map` is either a `dict` or a flat iterator (usually a `set`, sometimes
28 // `map` is either a `dict` or a flat iterator (usually a `set`, sometimes
29 // a `list`)
29 // a `list`)
30 def __new__(
30 def __new__(
31 _cls,
31 _cls,
32 map: PyObject,
32 map: PyObject,
33 skip: Option<PyObject> = None
33 skip: Option<PyObject> = None
34 ) -> PyResult<Self> {
34 ) -> PyResult<Self> {
35 let mut skip_state: Option<EntryState> = None;
35 let mut skip_state: Option<EntryState> = None;
36 if let Some(skip) = skip {
36 if let Some(skip) = skip {
37 skip_state = Some(
37 skip_state = Some(
38 skip.extract::<PyBytes>(py)?.data(py)[0]
38 skip.extract::<PyBytes>(py)?.data(py)[0]
39 .try_into()
39 .try_into()
40 .map_err(|e: DirstateParseError| {
40 .map_err(|e: DirstateParseError| {
41 PyErr::new::<exc::ValueError, _>(py, e.to_string())
41 PyErr::new::<exc::ValueError, _>(py, e.to_string())
42 })?,
42 })?,
43 );
43 );
44 }
44 }
45 let inner = if let Ok(map) = map.cast_as::<PyDict>(py) {
45 let inner = if let Ok(map) = map.cast_as::<PyDict>(py) {
46 let dirstate = extract_dirstate(py, &map)?;
46 let dirstate = extract_dirstate(py, &map)?;
47 DirsMultiset::new(
47 DirsMultiset::new(
48 DirsIterable::Dirstate(&dirstate),
48 DirsIterable::Dirstate(&dirstate),
49 skip_state,
49 skip_state,
50 )
50 )
51 } else {
51 } else {
52 let map: Result<Vec<Vec<u8>>, PyErr> = map
52 let map: Result<Vec<Vec<u8>>, PyErr> = map
53 .iter(py)?
53 .iter(py)?
54 .map(|o| Ok(o?.extract::<PyBytes>(py)?.data(py).to_owned()))
54 .map(|o| Ok(o?.extract::<PyBytes>(py)?.data(py).to_owned()))
55 .collect();
55 .collect();
56 DirsMultiset::new(
56 DirsMultiset::new(
57 DirsIterable::Manifest(&map?),
57 DirsIterable::Manifest(&map?),
58 skip_state,
58 skip_state,
59 )
59 )
60 };
60 };
61
61
62 Self::create_instance(py, RefCell::new(inner))
62 Self::create_instance(py, RefCell::new(inner))
63 }
63 }
64
64
65 def addpath(&self, path: PyObject) -> PyResult<PyObject> {
65 def addpath(&self, path: PyObject) -> PyResult<PyObject> {
66 self.dirs_map(py).borrow_mut().add_path(
66 self.dirs_map(py).borrow_mut().add_path(
67 path.extract::<PyBytes>(py)?.data(py),
67 path.extract::<PyBytes>(py)?.data(py),
68 );
68 );
69 Ok(py.None())
69 Ok(py.None())
70 }
70 }
71
71
72 def delpath(&self, path: PyObject) -> PyResult<PyObject> {
72 def delpath(&self, path: PyObject) -> PyResult<PyObject> {
73 self.dirs_map(py).borrow_mut().delete_path(
73 self.dirs_map(py).borrow_mut().delete_path(
74 path.extract::<PyBytes>(py)?.data(py),
74 path.extract::<PyBytes>(py)?.data(py),
75 )
75 )
76 .and(Ok(py.None()))
76 .and(Ok(py.None()))
77 .or_else(|e| {
77 .or_else(|e| {
78 match e {
78 match e {
79 DirstateMapError::PathNotFound(_p) => {
79 DirstateMapError::PathNotFound(_p) => {
80 Err(PyErr::new::<exc::ValueError, _>(
80 Err(PyErr::new::<exc::ValueError, _>(
81 py,
81 py,
82 "expected a value, found none".to_string(),
82 "expected a value, found none".to_string(),
83 ))
83 ))
84 }
84 }
85 DirstateMapError::EmptyPath => {
85 DirstateMapError::EmptyPath => {
86 Ok(py.None())
86 Ok(py.None())
87 }
87 }
88 }
88 }
89 })
89 })
90 }
90 }
91
91
92 // This is really inefficient on top of being ugly, but it's an easy way
92 // This is really inefficient on top of being ugly, but it's an easy way
93 // of having it work to continue working on the rest of the module
93 // of having it work to continue working on the rest of the module
94 // hopefully bypassing Python entirely pretty soon.
94 // hopefully bypassing Python entirely pretty soon.
95 def __iter__(&self) -> PyResult<PyObject> {
95 def __iter__(&self) -> PyResult<PyObject> {
96 let dict = PyDict::new(py);
96 let dirs = self.dirs_map(py).borrow();
97
97 let dirs: Vec<_> = dirs
98 for (key, value) in self.dirs_map(py).borrow().iter() {
98 .iter()
99 dict.set_item(
99 .map(|d| PyBytes::new(py, d))
100 py,
100 .collect();
101 PyBytes::new(py, &key[..]),
101 dirs.to_py_object(py)
102 value.to_py_object(py),
102 .into_object()
103 )?;
103 .iter(py)
104 }
104 .map(|o| o.into_object())
105
106 let locals = PyDict::new(py);
107 locals.set_item(py, "obj", dict)?;
108
109 py.eval("iter(obj)", None, Some(&locals))
110 }
105 }
111
106
112 def __contains__(&self, item: PyObject) -> PyResult<bool> {
107 def __contains__(&self, item: PyObject) -> PyResult<bool> {
113 Ok(self
108 Ok(self
114 .dirs_map(py)
109 .dirs_map(py)
115 .borrow()
110 .borrow()
116 .contains_key(item.extract::<PyBytes>(py)?.data(py).as_ref()))
111 .contains(item.extract::<PyBytes>(py)?.data(py).as_ref()))
117 }
112 }
118 });
113 });
General Comments 0
You need to be logged in to leave comments. Login now