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