##// END OF EJS Templates
rust-dirstatemap: expand the wrapping code a bit...
marmoute -
r48307:f6f25ab6 default
parent child Browse files
Show More
@@ -1,562 +1,570 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::{RefCell, RefMut};
11 use std::cell::{RefCell, RefMut};
12 use std::convert::TryInto;
12 use std::convert::TryInto;
13
13
14 use cpython::{
14 use cpython::{
15 exc, ObjectProtocol, PyBool, PyBytes, PyClone, PyDict, PyErr, PyList,
15 exc, ObjectProtocol, PyBool, PyBytes, PyClone, PyDict, PyErr, PyList,
16 PyObject, PyResult, PySet, PyString, Python, PythonObject, ToPyObject,
16 PyObject, PyResult, PySet, PyString, Python, PythonObject, ToPyObject,
17 UnsafePyLeaked,
17 UnsafePyLeaked,
18 };
18 };
19
19
20 use crate::{
20 use crate::{
21 dirstate::copymap::{CopyMap, CopyMapItemsIterator, CopyMapKeysIterator},
21 dirstate::copymap::{CopyMap, CopyMapItemsIterator, CopyMapKeysIterator},
22 dirstate::make_dirstate_tuple,
22 dirstate::make_dirstate_tuple,
23 dirstate::non_normal_entries::{
23 dirstate::non_normal_entries::{
24 NonNormalEntries, NonNormalEntriesIterator,
24 NonNormalEntries, NonNormalEntriesIterator,
25 },
25 },
26 dirstate::owning::OwningDirstateMap,
26 dirstate::owning::OwningDirstateMap,
27 parsers::dirstate_parents_to_pytuple,
27 parsers::dirstate_parents_to_pytuple,
28 };
28 };
29 use hg::{
29 use hg::{
30 dirstate::parsers::Timestamp,
30 dirstate::parsers::Timestamp,
31 dirstate_tree::dispatch::DirstateMapMethods,
31 dirstate_tree::dispatch::DirstateMapMethods,
32 dirstate_tree::on_disk::DirstateV2ParseError,
32 dirstate_tree::on_disk::DirstateV2ParseError,
33 errors::HgError,
33 errors::HgError,
34 revlog::Node,
34 revlog::Node,
35 utils::files::normalize_case,
35 utils::files::normalize_case,
36 utils::hg_path::{HgPath, HgPathBuf},
36 utils::hg_path::{HgPath, HgPathBuf},
37 DirstateEntry, DirstateError, DirstateMap as RustDirstateMap,
37 DirstateEntry, DirstateError, DirstateMap as RustDirstateMap,
38 DirstateParents, EntryState, StateMapIter,
38 DirstateParents, EntryState, StateMapIter,
39 };
39 };
40
40
41 // TODO
41 // TODO
42 // This object needs to share references to multiple members of its Rust
42 // This object needs to share references to multiple members of its Rust
43 // inner struct, namely `copy_map`, `dirs` and `all_dirs`.
43 // inner struct, namely `copy_map`, `dirs` and `all_dirs`.
44 // Right now `CopyMap` is done, but it needs to have an explicit reference
44 // Right now `CopyMap` is done, but it needs to have an explicit reference
45 // to `RustDirstateMap` which itself needs to have an encapsulation for
45 // to `RustDirstateMap` which itself needs to have an encapsulation for
46 // every method in `CopyMap` (copymapcopy, etc.).
46 // every method in `CopyMap` (copymapcopy, etc.).
47 // This is ugly and hard to maintain.
47 // This is ugly and hard to maintain.
48 // The same logic applies to `dirs` and `all_dirs`, however the `Dirs`
48 // The same logic applies to `dirs` and `all_dirs`, however the `Dirs`
49 // `py_class!` is already implemented and does not mention
49 // `py_class!` is already implemented and does not mention
50 // `RustDirstateMap`, rightfully so.
50 // `RustDirstateMap`, rightfully so.
51 // All attributes also have to have a separate refcount data attribute for
51 // All attributes also have to have a separate refcount data attribute for
52 // leaks, with all methods that go along for reference sharing.
52 // leaks, with all methods that go along for reference sharing.
53 py_class!(pub class DirstateMap |py| {
53 py_class!(pub class DirstateMap |py| {
54 @shared data inner: Box<dyn DirstateMapMethods + Send>;
54 @shared data inner: Box<dyn DirstateMapMethods + Send>;
55
55
56 /// Returns a `(dirstate_map, parents)` tuple
56 /// Returns a `(dirstate_map, parents)` tuple
57 @staticmethod
57 @staticmethod
58 def new(
58 def new(
59 use_dirstate_tree: bool,
59 use_dirstate_tree: bool,
60 use_dirstate_v2: bool,
60 use_dirstate_v2: bool,
61 on_disk: PyBytes,
61 on_disk: PyBytes,
62 ) -> PyResult<PyObject> {
62 ) -> PyResult<PyObject> {
63 let dirstate_error = |e: DirstateError| {
63 let dirstate_error = |e: DirstateError| {
64 PyErr::new::<exc::OSError, _>(py, format!("Dirstate error: {:?}", e))
64 PyErr::new::<exc::OSError, _>(py, format!("Dirstate error: {:?}", e))
65 };
65 };
66 let (inner, parents) = if use_dirstate_tree || use_dirstate_v2 {
66 let (inner, parents) = if use_dirstate_tree || use_dirstate_v2 {
67 let (map, parents) =
67 let (map, parents) =
68 OwningDirstateMap::new(py, on_disk, use_dirstate_v2)
68 OwningDirstateMap::new(py, on_disk, use_dirstate_v2)
69 .map_err(dirstate_error)?;
69 .map_err(dirstate_error)?;
70 (Box::new(map) as _, parents)
70 (Box::new(map) as _, parents)
71 } else {
71 } else {
72 let bytes = on_disk.data(py);
72 let bytes = on_disk.data(py);
73 let mut map = RustDirstateMap::default();
73 let mut map = RustDirstateMap::default();
74 let parents = map.read(bytes).map_err(dirstate_error)?;
74 let parents = map.read(bytes).map_err(dirstate_error)?;
75 (Box::new(map) as _, parents)
75 (Box::new(map) as _, parents)
76 };
76 };
77 let map = Self::create_instance(py, inner)?;
77 let map = Self::create_instance(py, inner)?;
78 let parents = parents.map(|p| dirstate_parents_to_pytuple(py, &p));
78 let parents = parents.map(|p| dirstate_parents_to_pytuple(py, &p));
79 Ok((map, parents).to_py_object(py).into_object())
79 Ok((map, parents).to_py_object(py).into_object())
80 }
80 }
81
81
82 def clear(&self) -> PyResult<PyObject> {
82 def clear(&self) -> PyResult<PyObject> {
83 self.inner(py).borrow_mut().clear();
83 self.inner(py).borrow_mut().clear();
84 Ok(py.None())
84 Ok(py.None())
85 }
85 }
86
86
87 def get(
87 def get(
88 &self,
88 &self,
89 key: PyObject,
89 key: PyObject,
90 default: Option<PyObject> = None
90 default: Option<PyObject> = None
91 ) -> PyResult<Option<PyObject>> {
91 ) -> PyResult<Option<PyObject>> {
92 let key = key.extract::<PyBytes>(py)?;
92 let key = key.extract::<PyBytes>(py)?;
93 match self
93 match self
94 .inner(py)
94 .inner(py)
95 .borrow()
95 .borrow()
96 .get(HgPath::new(key.data(py)))
96 .get(HgPath::new(key.data(py)))
97 .map_err(|e| v2_error(py, e))?
97 .map_err(|e| v2_error(py, e))?
98 {
98 {
99 Some(entry) => {
99 Some(entry) => {
100 Ok(Some(make_dirstate_tuple(py, &entry)?))
100 Ok(Some(make_dirstate_tuple(py, &entry)?))
101 },
101 },
102 None => Ok(default)
102 None => Ok(default)
103 }
103 }
104 }
104 }
105
105
106 def addfile(
106 def addfile(
107 &self,
107 &self,
108 f: PyObject,
108 f: PyObject,
109 oldstate: PyObject,
109 oldstate: PyObject,
110 state: PyObject,
110 state: PyObject,
111 mode: PyObject,
111 mode: PyObject,
112 size: PyObject,
112 size: PyObject,
113 mtime: PyObject
113 mtime: PyObject
114 ) -> PyResult<PyObject> {
114 ) -> PyResult<PyObject> {
115 let f = f.extract::<PyBytes>(py)?;
116 let filename = HgPath::new(f.data(py));
117 let oldstate = oldstate.extract::<PyBytes>(py)?.data(py)[0]
118 .try_into()
119 .map_err(|e: HgError| {
120 PyErr::new::<exc::ValueError, _>(py, e.to_string())
121 })?;
122 let state = state.extract::<PyBytes>(py)?.data(py)[0]
123 .try_into()
124 .map_err(|e: HgError| {
125 PyErr::new::<exc::ValueError, _>(py, e.to_string())
126 })?;
127 let mode = mode.extract(py)?;
128 let size = size.extract(py)?;
129 let mtime = mtime.extract(py)?;
130 let entry = DirstateEntry {
131 state: state,
132 mode: mode,
133 size: size,
134 mtime: mtime,
135 };
115 self.inner(py).borrow_mut().add_file(
136 self.inner(py).borrow_mut().add_file(
116 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
137 filename,
117 oldstate.extract::<PyBytes>(py)?.data(py)[0]
138 oldstate,
118 .try_into()
139 entry,
119 .map_err(|e: HgError| {
120 PyErr::new::<exc::ValueError, _>(py, e.to_string())
121 })?,
122 DirstateEntry {
123 state: state.extract::<PyBytes>(py)?.data(py)[0]
124 .try_into()
125 .map_err(|e: HgError| {
126 PyErr::new::<exc::ValueError, _>(py, e.to_string())
127 })?,
128 mode: mode.extract(py)?,
129 size: size.extract(py)?,
130 mtime: mtime.extract(py)?,
131 },
132 ).and(Ok(py.None())).or_else(|e: DirstateError| {
140 ).and(Ok(py.None())).or_else(|e: DirstateError| {
133 Err(PyErr::new::<exc::ValueError, _>(py, e.to_string()))
141 Err(PyErr::new::<exc::ValueError, _>(py, e.to_string()))
134 })
142 })
135 }
143 }
136
144
137 def removefile(
145 def removefile(
138 &self,
146 &self,
139 f: PyObject,
147 f: PyObject,
140 in_merge: PyObject
148 in_merge: PyObject
141 ) -> PyResult<PyObject> {
149 ) -> PyResult<PyObject> {
142 self.inner(py).borrow_mut()
150 self.inner(py).borrow_mut()
143 .remove_file(
151 .remove_file(
144 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
152 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
145 in_merge.extract::<PyBool>(py)?.is_true(),
153 in_merge.extract::<PyBool>(py)?.is_true(),
146 )
154 )
147 .or_else(|_| {
155 .or_else(|_| {
148 Err(PyErr::new::<exc::OSError, _>(
156 Err(PyErr::new::<exc::OSError, _>(
149 py,
157 py,
150 "Dirstate error".to_string(),
158 "Dirstate error".to_string(),
151 ))
159 ))
152 })?;
160 })?;
153 Ok(py.None())
161 Ok(py.None())
154 }
162 }
155
163
156 def dropfile(
164 def dropfile(
157 &self,
165 &self,
158 f: PyObject,
166 f: PyObject,
159 oldstate: PyObject
167 oldstate: PyObject
160 ) -> PyResult<PyBool> {
168 ) -> PyResult<PyBool> {
161 self.inner(py).borrow_mut()
169 self.inner(py).borrow_mut()
162 .drop_file(
170 .drop_file(
163 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
171 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
164 oldstate.extract::<PyBytes>(py)?.data(py)[0]
172 oldstate.extract::<PyBytes>(py)?.data(py)[0]
165 .try_into()
173 .try_into()
166 .map_err(|e: HgError| {
174 .map_err(|e: HgError| {
167 PyErr::new::<exc::ValueError, _>(py, e.to_string())
175 PyErr::new::<exc::ValueError, _>(py, e.to_string())
168 })?,
176 })?,
169 )
177 )
170 .and_then(|b| Ok(b.to_py_object(py)))
178 .and_then(|b| Ok(b.to_py_object(py)))
171 .or_else(|e| {
179 .or_else(|e| {
172 Err(PyErr::new::<exc::OSError, _>(
180 Err(PyErr::new::<exc::OSError, _>(
173 py,
181 py,
174 format!("Dirstate error: {}", e.to_string()),
182 format!("Dirstate error: {}", e.to_string()),
175 ))
183 ))
176 })
184 })
177 }
185 }
178
186
179 def clearambiguoustimes(
187 def clearambiguoustimes(
180 &self,
188 &self,
181 files: PyObject,
189 files: PyObject,
182 now: PyObject
190 now: PyObject
183 ) -> PyResult<PyObject> {
191 ) -> PyResult<PyObject> {
184 let files: PyResult<Vec<HgPathBuf>> = files
192 let files: PyResult<Vec<HgPathBuf>> = files
185 .iter(py)?
193 .iter(py)?
186 .map(|filename| {
194 .map(|filename| {
187 Ok(HgPathBuf::from_bytes(
195 Ok(HgPathBuf::from_bytes(
188 filename?.extract::<PyBytes>(py)?.data(py),
196 filename?.extract::<PyBytes>(py)?.data(py),
189 ))
197 ))
190 })
198 })
191 .collect();
199 .collect();
192 self.inner(py)
200 self.inner(py)
193 .borrow_mut()
201 .borrow_mut()
194 .clear_ambiguous_times(files?, now.extract(py)?)
202 .clear_ambiguous_times(files?, now.extract(py)?)
195 .map_err(|e| v2_error(py, e))?;
203 .map_err(|e| v2_error(py, e))?;
196 Ok(py.None())
204 Ok(py.None())
197 }
205 }
198
206
199 def other_parent_entries(&self) -> PyResult<PyObject> {
207 def other_parent_entries(&self) -> PyResult<PyObject> {
200 let mut inner_shared = self.inner(py).borrow_mut();
208 let mut inner_shared = self.inner(py).borrow_mut();
201 let set = PySet::empty(py)?;
209 let set = PySet::empty(py)?;
202 for path in inner_shared.iter_other_parent_paths() {
210 for path in inner_shared.iter_other_parent_paths() {
203 let path = path.map_err(|e| v2_error(py, e))?;
211 let path = path.map_err(|e| v2_error(py, e))?;
204 set.add(py, PyBytes::new(py, path.as_bytes()))?;
212 set.add(py, PyBytes::new(py, path.as_bytes()))?;
205 }
213 }
206 Ok(set.into_object())
214 Ok(set.into_object())
207 }
215 }
208
216
209 def non_normal_entries(&self) -> PyResult<NonNormalEntries> {
217 def non_normal_entries(&self) -> PyResult<NonNormalEntries> {
210 NonNormalEntries::from_inner(py, self.clone_ref(py))
218 NonNormalEntries::from_inner(py, self.clone_ref(py))
211 }
219 }
212
220
213 def non_normal_entries_contains(&self, key: PyObject) -> PyResult<bool> {
221 def non_normal_entries_contains(&self, key: PyObject) -> PyResult<bool> {
214 let key = key.extract::<PyBytes>(py)?;
222 let key = key.extract::<PyBytes>(py)?;
215 self.inner(py)
223 self.inner(py)
216 .borrow_mut()
224 .borrow_mut()
217 .non_normal_entries_contains(HgPath::new(key.data(py)))
225 .non_normal_entries_contains(HgPath::new(key.data(py)))
218 .map_err(|e| v2_error(py, e))
226 .map_err(|e| v2_error(py, e))
219 }
227 }
220
228
221 def non_normal_entries_display(&self) -> PyResult<PyString> {
229 def non_normal_entries_display(&self) -> PyResult<PyString> {
222 let mut inner = self.inner(py).borrow_mut();
230 let mut inner = self.inner(py).borrow_mut();
223 let paths = inner
231 let paths = inner
224 .iter_non_normal_paths()
232 .iter_non_normal_paths()
225 .collect::<Result<Vec<_>, _>>()
233 .collect::<Result<Vec<_>, _>>()
226 .map_err(|e| v2_error(py, e))?;
234 .map_err(|e| v2_error(py, e))?;
227 let formatted = format!("NonNormalEntries: {}", hg::utils::join_display(paths, ", "));
235 let formatted = format!("NonNormalEntries: {}", hg::utils::join_display(paths, ", "));
228 Ok(PyString::new(py, &formatted))
236 Ok(PyString::new(py, &formatted))
229 }
237 }
230
238
231 def non_normal_entries_remove(&self, key: PyObject) -> PyResult<PyObject> {
239 def non_normal_entries_remove(&self, key: PyObject) -> PyResult<PyObject> {
232 let key = key.extract::<PyBytes>(py)?;
240 let key = key.extract::<PyBytes>(py)?;
233 self
241 self
234 .inner(py)
242 .inner(py)
235 .borrow_mut()
243 .borrow_mut()
236 .non_normal_entries_remove(HgPath::new(key.data(py)));
244 .non_normal_entries_remove(HgPath::new(key.data(py)));
237 Ok(py.None())
245 Ok(py.None())
238 }
246 }
239
247
240 def non_normal_or_other_parent_paths(&self) -> PyResult<PyList> {
248 def non_normal_or_other_parent_paths(&self) -> PyResult<PyList> {
241 let mut inner = self.inner(py).borrow_mut();
249 let mut inner = self.inner(py).borrow_mut();
242
250
243 let ret = PyList::new(py, &[]);
251 let ret = PyList::new(py, &[]);
244 for filename in inner.non_normal_or_other_parent_paths() {
252 for filename in inner.non_normal_or_other_parent_paths() {
245 let filename = filename.map_err(|e| v2_error(py, e))?;
253 let filename = filename.map_err(|e| v2_error(py, e))?;
246 let as_pystring = PyBytes::new(py, filename.as_bytes());
254 let as_pystring = PyBytes::new(py, filename.as_bytes());
247 ret.append(py, as_pystring.into_object());
255 ret.append(py, as_pystring.into_object());
248 }
256 }
249 Ok(ret)
257 Ok(ret)
250 }
258 }
251
259
252 def non_normal_entries_iter(&self) -> PyResult<NonNormalEntriesIterator> {
260 def non_normal_entries_iter(&self) -> PyResult<NonNormalEntriesIterator> {
253 // Make sure the sets are defined before we no longer have a mutable
261 // Make sure the sets are defined before we no longer have a mutable
254 // reference to the dmap.
262 // reference to the dmap.
255 self.inner(py)
263 self.inner(py)
256 .borrow_mut()
264 .borrow_mut()
257 .set_non_normal_other_parent_entries(false);
265 .set_non_normal_other_parent_entries(false);
258
266
259 let leaked_ref = self.inner(py).leak_immutable();
267 let leaked_ref = self.inner(py).leak_immutable();
260
268
261 NonNormalEntriesIterator::from_inner(py, unsafe {
269 NonNormalEntriesIterator::from_inner(py, unsafe {
262 leaked_ref.map(py, |o| {
270 leaked_ref.map(py, |o| {
263 o.iter_non_normal_paths_panic()
271 o.iter_non_normal_paths_panic()
264 })
272 })
265 })
273 })
266 }
274 }
267
275
268 def hastrackeddir(&self, d: PyObject) -> PyResult<PyBool> {
276 def hastrackeddir(&self, d: PyObject) -> PyResult<PyBool> {
269 let d = d.extract::<PyBytes>(py)?;
277 let d = d.extract::<PyBytes>(py)?;
270 Ok(self.inner(py).borrow_mut()
278 Ok(self.inner(py).borrow_mut()
271 .has_tracked_dir(HgPath::new(d.data(py)))
279 .has_tracked_dir(HgPath::new(d.data(py)))
272 .map_err(|e| {
280 .map_err(|e| {
273 PyErr::new::<exc::ValueError, _>(py, e.to_string())
281 PyErr::new::<exc::ValueError, _>(py, e.to_string())
274 })?
282 })?
275 .to_py_object(py))
283 .to_py_object(py))
276 }
284 }
277
285
278 def hasdir(&self, d: PyObject) -> PyResult<PyBool> {
286 def hasdir(&self, d: PyObject) -> PyResult<PyBool> {
279 let d = d.extract::<PyBytes>(py)?;
287 let d = d.extract::<PyBytes>(py)?;
280 Ok(self.inner(py).borrow_mut()
288 Ok(self.inner(py).borrow_mut()
281 .has_dir(HgPath::new(d.data(py)))
289 .has_dir(HgPath::new(d.data(py)))
282 .map_err(|e| {
290 .map_err(|e| {
283 PyErr::new::<exc::ValueError, _>(py, e.to_string())
291 PyErr::new::<exc::ValueError, _>(py, e.to_string())
284 })?
292 })?
285 .to_py_object(py))
293 .to_py_object(py))
286 }
294 }
287
295
288 def write(
296 def write(
289 &self,
297 &self,
290 use_dirstate_v2: bool,
298 use_dirstate_v2: bool,
291 p1: PyObject,
299 p1: PyObject,
292 p2: PyObject,
300 p2: PyObject,
293 now: PyObject
301 now: PyObject
294 ) -> PyResult<PyBytes> {
302 ) -> PyResult<PyBytes> {
295 let now = Timestamp(now.extract(py)?);
303 let now = Timestamp(now.extract(py)?);
296 let parents = DirstateParents {
304 let parents = DirstateParents {
297 p1: extract_node_id(py, &p1)?,
305 p1: extract_node_id(py, &p1)?,
298 p2: extract_node_id(py, &p2)?,
306 p2: extract_node_id(py, &p2)?,
299 };
307 };
300
308
301 let mut inner = self.inner(py).borrow_mut();
309 let mut inner = self.inner(py).borrow_mut();
302 let result = if use_dirstate_v2 {
310 let result = if use_dirstate_v2 {
303 inner.pack_v2(parents, now)
311 inner.pack_v2(parents, now)
304 } else {
312 } else {
305 inner.pack_v1(parents, now)
313 inner.pack_v1(parents, now)
306 };
314 };
307 match result {
315 match result {
308 Ok(packed) => Ok(PyBytes::new(py, &packed)),
316 Ok(packed) => Ok(PyBytes::new(py, &packed)),
309 Err(_) => Err(PyErr::new::<exc::OSError, _>(
317 Err(_) => Err(PyErr::new::<exc::OSError, _>(
310 py,
318 py,
311 "Dirstate error".to_string(),
319 "Dirstate error".to_string(),
312 )),
320 )),
313 }
321 }
314 }
322 }
315
323
316 def filefoldmapasdict(&self) -> PyResult<PyDict> {
324 def filefoldmapasdict(&self) -> PyResult<PyDict> {
317 let dict = PyDict::new(py);
325 let dict = PyDict::new(py);
318 for item in self.inner(py).borrow_mut().iter() {
326 for item in self.inner(py).borrow_mut().iter() {
319 let (path, entry) = item.map_err(|e| v2_error(py, e))?;
327 let (path, entry) = item.map_err(|e| v2_error(py, e))?;
320 if entry.state != EntryState::Removed {
328 if entry.state != EntryState::Removed {
321 let key = normalize_case(path);
329 let key = normalize_case(path);
322 let value = path;
330 let value = path;
323 dict.set_item(
331 dict.set_item(
324 py,
332 py,
325 PyBytes::new(py, key.as_bytes()).into_object(),
333 PyBytes::new(py, key.as_bytes()).into_object(),
326 PyBytes::new(py, value.as_bytes()).into_object(),
334 PyBytes::new(py, value.as_bytes()).into_object(),
327 )?;
335 )?;
328 }
336 }
329 }
337 }
330 Ok(dict)
338 Ok(dict)
331 }
339 }
332
340
333 def __len__(&self) -> PyResult<usize> {
341 def __len__(&self) -> PyResult<usize> {
334 Ok(self.inner(py).borrow().len())
342 Ok(self.inner(py).borrow().len())
335 }
343 }
336
344
337 def __contains__(&self, key: PyObject) -> PyResult<bool> {
345 def __contains__(&self, key: PyObject) -> PyResult<bool> {
338 let key = key.extract::<PyBytes>(py)?;
346 let key = key.extract::<PyBytes>(py)?;
339 self.inner(py)
347 self.inner(py)
340 .borrow()
348 .borrow()
341 .contains_key(HgPath::new(key.data(py)))
349 .contains_key(HgPath::new(key.data(py)))
342 .map_err(|e| v2_error(py, e))
350 .map_err(|e| v2_error(py, e))
343 }
351 }
344
352
345 def __getitem__(&self, key: PyObject) -> PyResult<PyObject> {
353 def __getitem__(&self, key: PyObject) -> PyResult<PyObject> {
346 let key = key.extract::<PyBytes>(py)?;
354 let key = key.extract::<PyBytes>(py)?;
347 let key = HgPath::new(key.data(py));
355 let key = HgPath::new(key.data(py));
348 match self
356 match self
349 .inner(py)
357 .inner(py)
350 .borrow()
358 .borrow()
351 .get(key)
359 .get(key)
352 .map_err(|e| v2_error(py, e))?
360 .map_err(|e| v2_error(py, e))?
353 {
361 {
354 Some(entry) => {
362 Some(entry) => {
355 Ok(make_dirstate_tuple(py, &entry)?)
363 Ok(make_dirstate_tuple(py, &entry)?)
356 },
364 },
357 None => Err(PyErr::new::<exc::KeyError, _>(
365 None => Err(PyErr::new::<exc::KeyError, _>(
358 py,
366 py,
359 String::from_utf8_lossy(key.as_bytes()),
367 String::from_utf8_lossy(key.as_bytes()),
360 )),
368 )),
361 }
369 }
362 }
370 }
363
371
364 def keys(&self) -> PyResult<DirstateMapKeysIterator> {
372 def keys(&self) -> PyResult<DirstateMapKeysIterator> {
365 let leaked_ref = self.inner(py).leak_immutable();
373 let leaked_ref = self.inner(py).leak_immutable();
366 DirstateMapKeysIterator::from_inner(
374 DirstateMapKeysIterator::from_inner(
367 py,
375 py,
368 unsafe { leaked_ref.map(py, |o| o.iter()) },
376 unsafe { leaked_ref.map(py, |o| o.iter()) },
369 )
377 )
370 }
378 }
371
379
372 def items(&self) -> PyResult<DirstateMapItemsIterator> {
380 def items(&self) -> PyResult<DirstateMapItemsIterator> {
373 let leaked_ref = self.inner(py).leak_immutable();
381 let leaked_ref = self.inner(py).leak_immutable();
374 DirstateMapItemsIterator::from_inner(
382 DirstateMapItemsIterator::from_inner(
375 py,
383 py,
376 unsafe { leaked_ref.map(py, |o| o.iter()) },
384 unsafe { leaked_ref.map(py, |o| o.iter()) },
377 )
385 )
378 }
386 }
379
387
380 def __iter__(&self) -> PyResult<DirstateMapKeysIterator> {
388 def __iter__(&self) -> PyResult<DirstateMapKeysIterator> {
381 let leaked_ref = self.inner(py).leak_immutable();
389 let leaked_ref = self.inner(py).leak_immutable();
382 DirstateMapKeysIterator::from_inner(
390 DirstateMapKeysIterator::from_inner(
383 py,
391 py,
384 unsafe { leaked_ref.map(py, |o| o.iter()) },
392 unsafe { leaked_ref.map(py, |o| o.iter()) },
385 )
393 )
386 }
394 }
387
395
388 // TODO all copymap* methods, see docstring above
396 // TODO all copymap* methods, see docstring above
389 def copymapcopy(&self) -> PyResult<PyDict> {
397 def copymapcopy(&self) -> PyResult<PyDict> {
390 let dict = PyDict::new(py);
398 let dict = PyDict::new(py);
391 for item in self.inner(py).borrow().copy_map_iter() {
399 for item in self.inner(py).borrow().copy_map_iter() {
392 let (key, value) = item.map_err(|e| v2_error(py, e))?;
400 let (key, value) = item.map_err(|e| v2_error(py, e))?;
393 dict.set_item(
401 dict.set_item(
394 py,
402 py,
395 PyBytes::new(py, key.as_bytes()),
403 PyBytes::new(py, key.as_bytes()),
396 PyBytes::new(py, value.as_bytes()),
404 PyBytes::new(py, value.as_bytes()),
397 )?;
405 )?;
398 }
406 }
399 Ok(dict)
407 Ok(dict)
400 }
408 }
401
409
402 def copymapgetitem(&self, key: PyObject) -> PyResult<PyBytes> {
410 def copymapgetitem(&self, key: PyObject) -> PyResult<PyBytes> {
403 let key = key.extract::<PyBytes>(py)?;
411 let key = key.extract::<PyBytes>(py)?;
404 match self
412 match self
405 .inner(py)
413 .inner(py)
406 .borrow()
414 .borrow()
407 .copy_map_get(HgPath::new(key.data(py)))
415 .copy_map_get(HgPath::new(key.data(py)))
408 .map_err(|e| v2_error(py, e))?
416 .map_err(|e| v2_error(py, e))?
409 {
417 {
410 Some(copy) => Ok(PyBytes::new(py, copy.as_bytes())),
418 Some(copy) => Ok(PyBytes::new(py, copy.as_bytes())),
411 None => Err(PyErr::new::<exc::KeyError, _>(
419 None => Err(PyErr::new::<exc::KeyError, _>(
412 py,
420 py,
413 String::from_utf8_lossy(key.data(py)),
421 String::from_utf8_lossy(key.data(py)),
414 )),
422 )),
415 }
423 }
416 }
424 }
417 def copymap(&self) -> PyResult<CopyMap> {
425 def copymap(&self) -> PyResult<CopyMap> {
418 CopyMap::from_inner(py, self.clone_ref(py))
426 CopyMap::from_inner(py, self.clone_ref(py))
419 }
427 }
420
428
421 def copymaplen(&self) -> PyResult<usize> {
429 def copymaplen(&self) -> PyResult<usize> {
422 Ok(self.inner(py).borrow().copy_map_len())
430 Ok(self.inner(py).borrow().copy_map_len())
423 }
431 }
424 def copymapcontains(&self, key: PyObject) -> PyResult<bool> {
432 def copymapcontains(&self, key: PyObject) -> PyResult<bool> {
425 let key = key.extract::<PyBytes>(py)?;
433 let key = key.extract::<PyBytes>(py)?;
426 self.inner(py)
434 self.inner(py)
427 .borrow()
435 .borrow()
428 .copy_map_contains_key(HgPath::new(key.data(py)))
436 .copy_map_contains_key(HgPath::new(key.data(py)))
429 .map_err(|e| v2_error(py, e))
437 .map_err(|e| v2_error(py, e))
430 }
438 }
431 def copymapget(
439 def copymapget(
432 &self,
440 &self,
433 key: PyObject,
441 key: PyObject,
434 default: Option<PyObject>
442 default: Option<PyObject>
435 ) -> PyResult<Option<PyObject>> {
443 ) -> PyResult<Option<PyObject>> {
436 let key = key.extract::<PyBytes>(py)?;
444 let key = key.extract::<PyBytes>(py)?;
437 match self
445 match self
438 .inner(py)
446 .inner(py)
439 .borrow()
447 .borrow()
440 .copy_map_get(HgPath::new(key.data(py)))
448 .copy_map_get(HgPath::new(key.data(py)))
441 .map_err(|e| v2_error(py, e))?
449 .map_err(|e| v2_error(py, e))?
442 {
450 {
443 Some(copy) => Ok(Some(
451 Some(copy) => Ok(Some(
444 PyBytes::new(py, copy.as_bytes()).into_object(),
452 PyBytes::new(py, copy.as_bytes()).into_object(),
445 )),
453 )),
446 None => Ok(default),
454 None => Ok(default),
447 }
455 }
448 }
456 }
449 def copymapsetitem(
457 def copymapsetitem(
450 &self,
458 &self,
451 key: PyObject,
459 key: PyObject,
452 value: PyObject
460 value: PyObject
453 ) -> PyResult<PyObject> {
461 ) -> PyResult<PyObject> {
454 let key = key.extract::<PyBytes>(py)?;
462 let key = key.extract::<PyBytes>(py)?;
455 let value = value.extract::<PyBytes>(py)?;
463 let value = value.extract::<PyBytes>(py)?;
456 self.inner(py)
464 self.inner(py)
457 .borrow_mut()
465 .borrow_mut()
458 .copy_map_insert(
466 .copy_map_insert(
459 HgPathBuf::from_bytes(key.data(py)),
467 HgPathBuf::from_bytes(key.data(py)),
460 HgPathBuf::from_bytes(value.data(py)),
468 HgPathBuf::from_bytes(value.data(py)),
461 )
469 )
462 .map_err(|e| v2_error(py, e))?;
470 .map_err(|e| v2_error(py, e))?;
463 Ok(py.None())
471 Ok(py.None())
464 }
472 }
465 def copymappop(
473 def copymappop(
466 &self,
474 &self,
467 key: PyObject,
475 key: PyObject,
468 default: Option<PyObject>
476 default: Option<PyObject>
469 ) -> PyResult<Option<PyObject>> {
477 ) -> PyResult<Option<PyObject>> {
470 let key = key.extract::<PyBytes>(py)?;
478 let key = key.extract::<PyBytes>(py)?;
471 match self
479 match self
472 .inner(py)
480 .inner(py)
473 .borrow_mut()
481 .borrow_mut()
474 .copy_map_remove(HgPath::new(key.data(py)))
482 .copy_map_remove(HgPath::new(key.data(py)))
475 .map_err(|e| v2_error(py, e))?
483 .map_err(|e| v2_error(py, e))?
476 {
484 {
477 Some(_) => Ok(None),
485 Some(_) => Ok(None),
478 None => Ok(default),
486 None => Ok(default),
479 }
487 }
480 }
488 }
481
489
482 def copymapiter(&self) -> PyResult<CopyMapKeysIterator> {
490 def copymapiter(&self) -> PyResult<CopyMapKeysIterator> {
483 let leaked_ref = self.inner(py).leak_immutable();
491 let leaked_ref = self.inner(py).leak_immutable();
484 CopyMapKeysIterator::from_inner(
492 CopyMapKeysIterator::from_inner(
485 py,
493 py,
486 unsafe { leaked_ref.map(py, |o| o.copy_map_iter()) },
494 unsafe { leaked_ref.map(py, |o| o.copy_map_iter()) },
487 )
495 )
488 }
496 }
489
497
490 def copymapitemsiter(&self) -> PyResult<CopyMapItemsIterator> {
498 def copymapitemsiter(&self) -> PyResult<CopyMapItemsIterator> {
491 let leaked_ref = self.inner(py).leak_immutable();
499 let leaked_ref = self.inner(py).leak_immutable();
492 CopyMapItemsIterator::from_inner(
500 CopyMapItemsIterator::from_inner(
493 py,
501 py,
494 unsafe { leaked_ref.map(py, |o| o.copy_map_iter()) },
502 unsafe { leaked_ref.map(py, |o| o.copy_map_iter()) },
495 )
503 )
496 }
504 }
497
505
498 def directories(&self) -> PyResult<PyList> {
506 def directories(&self) -> PyResult<PyList> {
499 let dirs = PyList::new(py, &[]);
507 let dirs = PyList::new(py, &[]);
500 for item in self.inner(py).borrow().iter_directories() {
508 for item in self.inner(py).borrow().iter_directories() {
501 let (path, mtime) = item.map_err(|e| v2_error(py, e))?;
509 let (path, mtime) = item.map_err(|e| v2_error(py, e))?;
502 let path = PyBytes::new(py, path.as_bytes());
510 let path = PyBytes::new(py, path.as_bytes());
503 let mtime = mtime.map(|t| t.0).unwrap_or(-1);
511 let mtime = mtime.map(|t| t.0).unwrap_or(-1);
504 let tuple = (path, (b'd', 0, 0, mtime));
512 let tuple = (path, (b'd', 0, 0, mtime));
505 dirs.append(py, tuple.to_py_object(py).into_object())
513 dirs.append(py, tuple.to_py_object(py).into_object())
506 }
514 }
507 Ok(dirs)
515 Ok(dirs)
508 }
516 }
509
517
510 });
518 });
511
519
512 impl DirstateMap {
520 impl DirstateMap {
513 pub fn get_inner_mut<'a>(
521 pub fn get_inner_mut<'a>(
514 &'a self,
522 &'a self,
515 py: Python<'a>,
523 py: Python<'a>,
516 ) -> RefMut<'a, Box<dyn DirstateMapMethods + Send>> {
524 ) -> RefMut<'a, Box<dyn DirstateMapMethods + Send>> {
517 self.inner(py).borrow_mut()
525 self.inner(py).borrow_mut()
518 }
526 }
519 fn translate_key(
527 fn translate_key(
520 py: Python,
528 py: Python,
521 res: Result<(&HgPath, DirstateEntry), DirstateV2ParseError>,
529 res: Result<(&HgPath, DirstateEntry), DirstateV2ParseError>,
522 ) -> PyResult<Option<PyBytes>> {
530 ) -> PyResult<Option<PyBytes>> {
523 let (f, _entry) = res.map_err(|e| v2_error(py, e))?;
531 let (f, _entry) = res.map_err(|e| v2_error(py, e))?;
524 Ok(Some(PyBytes::new(py, f.as_bytes())))
532 Ok(Some(PyBytes::new(py, f.as_bytes())))
525 }
533 }
526 fn translate_key_value(
534 fn translate_key_value(
527 py: Python,
535 py: Python,
528 res: Result<(&HgPath, DirstateEntry), DirstateV2ParseError>,
536 res: Result<(&HgPath, DirstateEntry), DirstateV2ParseError>,
529 ) -> PyResult<Option<(PyBytes, PyObject)>> {
537 ) -> PyResult<Option<(PyBytes, PyObject)>> {
530 let (f, entry) = res.map_err(|e| v2_error(py, e))?;
538 let (f, entry) = res.map_err(|e| v2_error(py, e))?;
531 Ok(Some((
539 Ok(Some((
532 PyBytes::new(py, f.as_bytes()),
540 PyBytes::new(py, f.as_bytes()),
533 make_dirstate_tuple(py, &entry)?,
541 make_dirstate_tuple(py, &entry)?,
534 )))
542 )))
535 }
543 }
536 }
544 }
537
545
538 py_shared_iterator!(
546 py_shared_iterator!(
539 DirstateMapKeysIterator,
547 DirstateMapKeysIterator,
540 UnsafePyLeaked<StateMapIter<'static>>,
548 UnsafePyLeaked<StateMapIter<'static>>,
541 DirstateMap::translate_key,
549 DirstateMap::translate_key,
542 Option<PyBytes>
550 Option<PyBytes>
543 );
551 );
544
552
545 py_shared_iterator!(
553 py_shared_iterator!(
546 DirstateMapItemsIterator,
554 DirstateMapItemsIterator,
547 UnsafePyLeaked<StateMapIter<'static>>,
555 UnsafePyLeaked<StateMapIter<'static>>,
548 DirstateMap::translate_key_value,
556 DirstateMap::translate_key_value,
549 Option<(PyBytes, PyObject)>
557 Option<(PyBytes, PyObject)>
550 );
558 );
551
559
552 fn extract_node_id(py: Python, obj: &PyObject) -> PyResult<Node> {
560 fn extract_node_id(py: Python, obj: &PyObject) -> PyResult<Node> {
553 let bytes = obj.extract::<PyBytes>(py)?;
561 let bytes = obj.extract::<PyBytes>(py)?;
554 match bytes.data(py).try_into() {
562 match bytes.data(py).try_into() {
555 Ok(s) => Ok(s),
563 Ok(s) => Ok(s),
556 Err(e) => Err(PyErr::new::<exc::ValueError, _>(py, e.to_string())),
564 Err(e) => Err(PyErr::new::<exc::ValueError, _>(py, e.to_string())),
557 }
565 }
558 }
566 }
559
567
560 pub(super) fn v2_error(py: Python<'_>, _: DirstateV2ParseError) -> PyErr {
568 pub(super) fn v2_error(py: Python<'_>, _: DirstateV2ParseError) -> PyErr {
561 PyErr::new::<exc::ValueError, _>(py, "corrupted dirstate-v2")
569 PyErr::new::<exc::ValueError, _>(py, "corrupted dirstate-v2")
562 }
570 }
General Comments 0
You need to be logged in to leave comments. Login now