This change also showcases the limitations of the py_shared_ref! macro.
See the previous commit 'rust-dirstate: rust implementation of dirstatemap`
for an explanation for the TODOs in the code.
hg-reviewers |
This change also showcases the limitations of the py_shared_ref! macro.
See the previous commit 'rust-dirstate: rust implementation of dirstatemap`
for an explanation for the TODOs in the code.
Lint Skipped |
Unit Tests Skipped |
+ def getdirs(&self) -> PyResult<Dirs> {
+ TODO don't copy, share the reference
+ self.inner(py).borrow_mut().set_dirs();
+ Dirs::from_inner(
+ py,
+ DirsMultiset::new(
+ DirsIterable::Dirstate(&self.inner(py).borrow()),
+ Some(EntryState::Removed),
+ ),
+ )
+ }
+ def getalldirs(&self) -> PyResult<Dirs> {
+ TODO don't copy, share the reference
+ self.inner(py).borrow_mut().set_all_dirs();
+ Dirs::from_inner(
+ py,
+ DirsMultiset::new(
+ DirsIterable::Dirstate(&self.inner(py).borrow()),
+ None,
+ ),
+ )
+ }
How do these set_dirs/set_all_dirs work? IIUC, the return value is built
from state_map.
Path | Packages | |||
---|---|---|---|---|
A | M | rust/hg-cpython/src/dirstate/copymap.rs (119 lines) | ||
A | M | rust/hg-cpython/src/dirstate/dirstate_map.rs (505 lines) | ||
M | rust/hg-cpython/src/dirstate/mod.rs (6 lines) |
Commit | Parents | Author | Summary | Date |
---|---|---|---|---|
Raphaël Gomès | Jul 10 2019, 3:56 AM |
// copymap.rs | |||||
// | |||||
// Copyright 2019 Raphaël Gomès <rgomes@octobus.net> | |||||
// | |||||
// This software may be used and distributed according to the terms of the | |||||
// GNU General Public License version 2 or any later version. | |||||
//! Bindings for `hg::dirstate::dirstate_map::CopyMap` provided by the | |||||
//! `hg-core` package. | |||||
use cpython::{PyBytes, PyClone, PyDict, PyObject, PyResult, Python}; | |||||
use std::cell::RefCell; | |||||
use std::collections::hash_map::Iter; | |||||
use dirstate::dirstate_map::{DirstateMap, DirstateMapLeakedRef}; | |||||
py_class!(pub class CopyMap |py| { | |||||
data dirstate_map: DirstateMap; | |||||
def __getitem__(&self, key: PyObject) -> PyResult<PyBytes> { | |||||
(*self.dirstate_map(py)).copymapgetitem(py, key) | |||||
} | |||||
def __len__(&self) -> PyResult<usize> { | |||||
self.dirstate_map(py).copymaplen(py) | |||||
} | |||||
def __contains__(&self, key: PyObject) -> PyResult<bool> { | |||||
self.dirstate_map(py).copymapcontains(py, key) | |||||
} | |||||
def get( | |||||
&self, | |||||
key: PyObject, | |||||
default: Option<PyObject> = None | |||||
) -> PyResult<Option<PyObject>> { | |||||
self.dirstate_map(py).copymapget(py, key, default) | |||||
} | |||||
def pop( | |||||
&self, | |||||
key: PyObject, | |||||
default: Option<PyObject> = None | |||||
) -> PyResult<Option<PyObject>> { | |||||
self.dirstate_map(py).copymappop(py, key, default) | |||||
} | |||||
def __iter__(&self) -> PyResult<CopyMapKeysIterator> { | |||||
self.dirstate_map(py).copymapiter(py) | |||||
} | |||||
// Python's `dict()` builtin works with either a subclass of dict | |||||
// or an abstract mapping. Said mapping needs to implement `__getitem__` | |||||
// and `keys`. | |||||
def keys(&self) -> PyResult<CopyMapKeysIterator> { | |||||
self.dirstate_map(py).copymapiter(py) | |||||
} | |||||
def items(&self) -> PyResult<CopyMapItemsIterator> { | |||||
self.dirstate_map(py).copymapitemsiter(py) | |||||
} | |||||
def iteritems(&self) -> PyResult<CopyMapItemsIterator> { | |||||
self.dirstate_map(py).copymapitemsiter(py) | |||||
} | |||||
def __setitem__( | |||||
&self, | |||||
key: PyObject, | |||||
item: PyObject | |||||
) -> PyResult<()> { | |||||
self.dirstate_map(py).copymapsetitem(py, key, item)?; | |||||
Ok(()) | |||||
} | |||||
def copy(&self) -> PyResult<PyDict> { | |||||
self.dirstate_map(py).copymapcopy(py) | |||||
} | |||||
}); | |||||
impl CopyMap { | |||||
pub fn from_inner(py: Python, dm: DirstateMap) -> PyResult<Self> { | |||||
Self::create_instance(py, dm) | |||||
} | |||||
fn translate_key( | |||||
py: Python, | |||||
res: (&Vec<u8>, &Vec<u8>), | |||||
) -> PyResult<Option<PyBytes>> { | |||||
Ok(Some(PyBytes::new(py, res.0))) | |||||
} | |||||
fn translate_key_value( | |||||
py: Python, | |||||
res: (&Vec<u8>, &Vec<u8>), | |||||
) -> PyResult<Option<(PyBytes, PyBytes)>> { | |||||
let (k, v) = res; | |||||
Ok(Some((PyBytes::new(py, k), PyBytes::new(py, v)))) | |||||
} | |||||
} | |||||
py_shared_mapping_iterator!( | |||||
CopyMapKeysIterator, | |||||
DirstateMapLeakedRef, | |||||
Iter, | |||||
Vec<u8>, | |||||
Vec<u8>, | |||||
CopyMap::translate_key, | |||||
Option<PyBytes> | |||||
); | |||||
py_shared_mapping_iterator!( | |||||
CopyMapItemsIterator, | |||||
DirstateMapLeakedRef, | |||||
Iter, | |||||
Vec<u8>, | |||||
Vec<u8>, | |||||
CopyMap::translate_key_value, | |||||
Option<(PyBytes, PyBytes)> | |||||
); |
// dirstate_map.rs | |||||
// | |||||
// Copyright 2019 Raphaël Gomès <rgomes@octobus.net> | |||||
// | |||||
// This software may be used and distributed according to the terms of the | |||||
// GNU General Public License version 2 or any later version. | |||||
//! Bindings for the `hg::dirstate::dirstate_map` file provided by the | |||||
//! `hg-core` package. | |||||
use std::cell::{RefCell, RefMut}; | |||||
use std::collections::hash_map::Iter; | |||||
use std::convert::TryInto; | |||||
use std::time::Duration; | |||||
use cpython::{ | |||||
exc, ObjectProtocol, PyBool, PyBytes, PyClone, PyDict, PyErr, PyObject, | |||||
PyResult, PyTuple, Python, PythonObject, ToPyObject, | |||||
}; | |||||
use libc::c_char; | |||||
use dirstate::copymap::{CopyMap, CopyMapItemsIterator, CopyMapKeysIterator}; | |||||
use dirstate::decapsule_make_dirstate_tuple; | |||||
use dirstate::dirs_multiset::Dirs; | |||||
use exceptions::AlreadyBorrowed; | |||||
use hg::{ | |||||
DirsIterable, DirsMultiset, DirstateEntry, DirstateMap as RustDirstateMap, | |||||
DirstateParents, DirstateParseError, EntryState, | |||||
}; | |||||
/// TODO | |||||
/// This object needs to share references to multiple members of its Rust | |||||
/// inner struct, namely `copy_map`, `dirs` and `all_dirs`. | |||||
/// Right now `CopyMap` is done, but it needs to have an explicit reference | |||||
/// to `RustDirstateMap` which itself needs to have an encapsulation for | |||||
/// every method in `CopyMap` (copymapcopy, etc.). | |||||
/// This is ugly and hard to maintain. | |||||
/// The same logic applies to `dirs` and `all_dirs`, however the `Dirs` | |||||
/// `py_class!` is already implemented and does not mention | |||||
/// `RustDirstateMap`, rightfully so. | |||||
/// All attributes also have to have a separate refcount data attribute for | |||||
/// leaks, with all methods that go along for reference sharing. | |||||
py_class!(pub class DirstateMap |py| { | |||||
data inner: RefCell<RustDirstateMap>; | |||||
data leak_count: RefCell<usize>; | |||||
def __new__(_cls, _root: PyObject) -> PyResult<Self> { | |||||
let inner = RustDirstateMap::default(); | |||||
Self::create_instance(py, RefCell::new(inner), RefCell::new(0)) | |||||
} | |||||
def clear(&self) -> PyResult<PyObject> { | |||||
self.borrow_mut(py)?.clear(); | |||||
Ok(py.None()) | |||||
} | |||||
def get( | |||||
&self, | |||||
key: PyObject, | |||||
default: Option<PyObject> = None | |||||
) -> PyResult<Option<PyObject>> { | |||||
let key = key.extract::<PyBytes>(py)?; | |||||
match self.inner(py).borrow().get(key.data(py)) { | |||||
Some(entry) => { | |||||
// Explicitly go through u8 first, then cast to | |||||
// platform-specific `c_char`. | |||||
let state: u8 = entry.state.into(); | |||||
Ok(Some(decapsule_make_dirstate_tuple(py)?( | |||||
state as c_char, | |||||
entry.mode, | |||||
entry.size, | |||||
entry.mtime, | |||||
))) | |||||
}, | |||||
None => Ok(default) | |||||
} | |||||
} | |||||
def addfile( | |||||
&self, | |||||
f: PyObject, | |||||
oldstate: PyObject, | |||||
state: PyObject, | |||||
mode: PyObject, | |||||
size: PyObject, | |||||
mtime: PyObject | |||||
) -> PyResult<PyObject> { | |||||
self.borrow_mut(py)?.add_file( | |||||
f.extract::<PyBytes>(py)?.data(py), | |||||
oldstate.extract::<PyBytes>(py)?.data(py)[0] | |||||
.try_into() | |||||
.map_err(|e: DirstateParseError| { | |||||
PyErr::new::<exc::ValueError, _>(py, e.to_string()) | |||||
})?, | |||||
DirstateEntry { | |||||
state: state.extract::<PyBytes>(py)?.data(py)[0] | |||||
.try_into() | |||||
.map_err(|e: DirstateParseError| { | |||||
PyErr::new::<exc::ValueError, _>(py, e.to_string()) | |||||
})?, | |||||
mode: mode.extract(py)?, | |||||
size: size.extract(py)?, | |||||
mtime: mtime.extract(py)?, | |||||
}, | |||||
); | |||||
Ok(py.None()) | |||||
} | |||||
def removefile( | |||||
&self, | |||||
f: PyObject, | |||||
oldstate: PyObject, | |||||
size: PyObject | |||||
) -> PyResult<PyObject> { | |||||
self.borrow_mut(py)? | |||||
.remove_file( | |||||
f.extract::<PyBytes>(py)?.data(py), | |||||
oldstate.extract::<PyBytes>(py)?.data(py)[0] | |||||
.try_into() | |||||
.map_err(|e: DirstateParseError| { | |||||
PyErr::new::<exc::ValueError, _>(py, e.to_string()) | |||||
})?, | |||||
size.extract(py)?, | |||||
) | |||||
.or_else(|_| { | |||||
Err(PyErr::new::<exc::OSError, _>( | |||||
py, | |||||
"Dirstate error".to_string(), | |||||
)) | |||||
})?; | |||||
Ok(py.None()) | |||||
} | |||||
def dropfile( | |||||
&self, | |||||
f: PyObject, | |||||
oldstate: PyObject | |||||
) -> PyResult<PyBool> { | |||||
self.borrow_mut(py)? | |||||
.drop_file( | |||||
f.extract::<PyBytes>(py)?.data(py), | |||||
oldstate.extract::<PyBytes>(py)?.data(py)[0] | |||||
.try_into() | |||||
.map_err(|e: DirstateParseError| { | |||||
PyErr::new::<exc::ValueError, _>(py, e.to_string()) | |||||
})?, | |||||
) | |||||
.and_then(|b| Ok(b.to_py_object(py))) | |||||
.or_else(|_| { | |||||
Err(PyErr::new::<exc::OSError, _>( | |||||
py, | |||||
"Dirstate error".to_string(), | |||||
)) | |||||
}) | |||||
} | |||||
def clearambiguoustimes( | |||||
&self, | |||||
files: PyObject, | |||||
now: PyObject | |||||
) -> PyResult<PyObject> { | |||||
let files: PyResult<Vec<Vec<u8>>> = files | |||||
.iter(py)? | |||||
.map(|filename| { | |||||
Ok(filename?.extract::<PyBytes>(py)?.data(py).to_owned()) | |||||
}) | |||||
.collect(); | |||||
self.inner(py) | |||||
.borrow_mut() | |||||
.clear_ambiguous_times(files?, now.extract(py)?); | |||||
Ok(py.None()) | |||||
} | |||||
// TODO share the reference | |||||
def nonnormalentries(&self) -> PyResult<PyObject> { | |||||
let (non_normal, other_parent) = | |||||
self.inner(py).borrow().non_normal_other_parent_entries(); | |||||
let locals = PyDict::new(py); | |||||
locals.set_item( | |||||
py, | |||||
"non_normal", | |||||
non_normal | |||||
.iter() | |||||
.map(|v| PyBytes::new(py, &v)) | |||||
.collect::<Vec<PyBytes>>() | |||||
.to_py_object(py), | |||||
)?; | |||||
locals.set_item( | |||||
py, | |||||
"other_parent", | |||||
other_parent | |||||
.iter() | |||||
.map(|v| PyBytes::new(py, &v)) | |||||
.collect::<Vec<PyBytes>>() | |||||
.to_py_object(py), | |||||
)?; | |||||
py.eval("set(non_normal), set(other_parent)", None, Some(&locals)) | |||||
} | |||||
def hastrackeddir(&self, d: PyObject) -> PyResult<PyBool> { | |||||
let d = d.extract::<PyBytes>(py)?; | |||||
Ok(self | |||||
.inner(py) | |||||
.borrow_mut() | |||||
.has_tracked_dir(d.data(py)) | |||||
.to_py_object(py)) | |||||
} | |||||
def hasdir(&self, d: PyObject) -> PyResult<PyBool> { | |||||
let d = d.extract::<PyBytes>(py)?; | |||||
Ok(self | |||||
.inner(py) | |||||
.borrow_mut() | |||||
.has_dir(d.data(py)) | |||||
.to_py_object(py)) | |||||
} | |||||
def parents(&self, st: PyObject) -> PyResult<PyTuple> { | |||||
self.inner(py) | |||||
.borrow_mut() | |||||
.parents(st.extract::<PyBytes>(py)?.data(py)) | |||||
.and_then(|d| { | |||||
Ok((PyBytes::new(py, &d.p1), PyBytes::new(py, &d.p2)) | |||||
.to_py_object(py)) | |||||
}) | |||||
.or_else(|_| { | |||||
Err(PyErr::new::<exc::OSError, _>( | |||||
py, | |||||
"Dirstate error".to_string(), | |||||
)) | |||||
}) | |||||
} | |||||
def setparents(&self, p1: PyObject, p2: PyObject) -> PyResult<PyObject> { | |||||
let p1 = p1.extract::<PyBytes>(py)?.data(py).to_vec(); | |||||
let p2 = p2.extract::<PyBytes>(py)?.data(py).to_vec(); | |||||
self.inner(py) | |||||
.borrow_mut() | |||||
.set_parents(DirstateParents { p1, p2 }); | |||||
Ok(py.None()) | |||||
} | |||||
def read(&self, st: PyObject) -> PyResult<Option<PyObject>> { | |||||
match self | |||||
.inner(py) | |||||
.borrow_mut() | |||||
.read(st.extract::<PyBytes>(py)?.data(py)) | |||||
{ | |||||
Ok(Some(parents)) => Ok(Some( | |||||
(PyBytes::new(py, &parents.p1), PyBytes::new(py, &parents.p2)) | |||||
.to_py_object(py) | |||||
.into_object(), | |||||
)), | |||||
Ok(None) => Ok(Some(py.None())), | |||||
Err(_) => Err(PyErr::new::<exc::OSError, _>( | |||||
py, | |||||
"Dirstate error".to_string(), | |||||
)), | |||||
} | |||||
} | |||||
def write( | |||||
&self, | |||||
p1: PyObject, | |||||
p2: PyObject, | |||||
now: PyObject | |||||
) -> PyResult<PyBytes> { | |||||
let now = Duration::new(now.extract(py)?, 0); | |||||
let parents = DirstateParents { | |||||
p1: p1.extract::<PyBytes>(py)?.data(py).to_owned(), | |||||
p2: p2.extract::<PyBytes>(py)?.data(py).to_owned(), | |||||
}; | |||||
match self.borrow_mut(py)?.pack(parents, now) { | |||||
Ok(packed) => Ok(PyBytes::new(py, &packed)), | |||||
Err(_) => Err(PyErr::new::<exc::OSError, _>( | |||||
py, | |||||
"Dirstate error".to_string(), | |||||
)), | |||||
} | |||||
} | |||||
def filefoldmapasdict(&self) -> PyResult<PyDict> { | |||||
let dict = PyDict::new(py); | |||||
for (key, value) in | |||||
self.borrow_mut(py)?.build_file_fold_map().iter() | |||||
{ | |||||
dict.set_item(py, key, value)?; | |||||
} | |||||
Ok(dict) | |||||
} | |||||
def __len__(&self) -> PyResult<usize> { | |||||
Ok(self.inner(py).borrow().len()) | |||||
} | |||||
def __contains__(&self, key: PyObject) -> PyResult<bool> { | |||||
let key = key.extract::<PyBytes>(py)?; | |||||
Ok(self.inner(py).borrow().contains_key(key.data(py))) | |||||
} | |||||
def __getitem__(&self, key: PyObject) -> PyResult<PyObject> { | |||||
let key = key.extract::<PyBytes>(py)?; | |||||
let key = key.data(py); | |||||
match self.inner(py).borrow().get(key) { | |||||
Some(entry) => { | |||||
// Explicitly go through u8 first, then cast to | |||||
// platform-specific `c_char`. | |||||
let state: u8 = entry.state.into(); | |||||
Ok(decapsule_make_dirstate_tuple(py)?( | |||||
state as c_char, | |||||
entry.mode, | |||||
entry.size, | |||||
entry.mtime, | |||||
)) | |||||
}, | |||||
None => Err(PyErr::new::<exc::KeyError, _>( | |||||
py, | |||||
String::from_utf8_lossy(key), | |||||
)), | |||||
} | |||||
} | |||||
def keys(&self) -> PyResult<DirstateMapKeysIterator> { | |||||
DirstateMapKeysIterator::create_instance( | |||||
py, | |||||
RefCell::new(Some(DirstateMapLeakedRef::new(py, &self))), | |||||
RefCell::new(self.leak_immutable(py).iter()), | |||||
) | |||||
} | |||||
def items(&self) -> PyResult<DirstateMapItemsIterator> { | |||||
DirstateMapItemsIterator::create_instance( | |||||
py, | |||||
RefCell::new(Some(DirstateMapLeakedRef::new(py, &self))), | |||||
RefCell::new(self.leak_immutable(py).iter()), | |||||
) | |||||
} | |||||
def __iter__(&self) -> PyResult<DirstateMapKeysIterator> { | |||||
DirstateMapKeysIterator::create_instance( | |||||
py, | |||||
RefCell::new(Some(DirstateMapLeakedRef::new(py, &self))), | |||||
RefCell::new(self.leak_immutable(py).iter()), | |||||
) | |||||
} | |||||
def getdirs(&self) -> PyResult<Dirs> { | |||||
// TODO don't copy, share the reference | |||||
self.inner(py).borrow_mut().set_dirs(); | |||||
Dirs::from_inner( | |||||
py, | |||||
DirsMultiset::new( | |||||
DirsIterable::Dirstate(&self.inner(py).borrow()), | |||||
Some(EntryState::Removed), | |||||
), | |||||
) | |||||
} | |||||
def getalldirs(&self) -> PyResult<Dirs> { | |||||
// TODO don't copy, share the reference | |||||
self.inner(py).borrow_mut().set_all_dirs(); | |||||
Dirs::from_inner( | |||||
py, | |||||
DirsMultiset::new( | |||||
DirsIterable::Dirstate(&self.inner(py).borrow()), | |||||
None, | |||||
), | |||||
) | |||||
} | |||||
// TODO all copymap* methods, see docstring above | |||||
def copymapcopy(&self) -> PyResult<PyDict> { | |||||
let dict = PyDict::new(py); | |||||
for (key, value) in self.inner(py).borrow().copy_map.iter() { | |||||
dict.set_item(py, PyBytes::new(py, key), PyBytes::new(py, value))?; | |||||
} | |||||
Ok(dict) | |||||
} | |||||
def copymapgetitem(&self, key: PyObject) -> PyResult<PyBytes> { | |||||
let key = key.extract::<PyBytes>(py)?; | |||||
match self.inner(py).borrow().copy_map.get(key.data(py)) { | |||||
Some(copy) => Ok(PyBytes::new(py, copy)), | |||||
None => Err(PyErr::new::<exc::KeyError, _>( | |||||
py, | |||||
String::from_utf8_lossy(key.data(py)), | |||||
)), | |||||
} | |||||
} | |||||
def copymap(&self) -> PyResult<CopyMap> { | |||||
CopyMap::from_inner(py, self.clone_ref(py)) | |||||
} | |||||
def copymaplen(&self) -> PyResult<usize> { | |||||
Ok(self.inner(py).borrow().copy_map.len()) | |||||
} | |||||
def copymapcontains(&self, key: PyObject) -> PyResult<bool> { | |||||
let key = key.extract::<PyBytes>(py)?; | |||||
Ok(self.inner(py).borrow().copy_map.contains_key(key.data(py))) | |||||
} | |||||
def copymapget( | |||||
&self, | |||||
key: PyObject, | |||||
default: Option<PyObject> | |||||
) -> PyResult<Option<PyObject>> { | |||||
let key = key.extract::<PyBytes>(py)?; | |||||
match self.inner(py).borrow().copy_map.get(key.data(py)) { | |||||
Some(copy) => Ok(Some(PyBytes::new(py, copy).into_object())), | |||||
None => Ok(default), | |||||
} | |||||
} | |||||
def copymapsetitem( | |||||
&self, | |||||
key: PyObject, | |||||
value: PyObject | |||||
) -> PyResult<PyObject> { | |||||
let key = key.extract::<PyBytes>(py)?; | |||||
let value = value.extract::<PyBytes>(py)?; | |||||
self.inner(py) | |||||
.borrow_mut() | |||||
.copy_map | |||||
.insert(key.data(py).to_vec(), value.data(py).to_vec()); | |||||
Ok(py.None()) | |||||
} | |||||
def copymappop( | |||||
&self, | |||||
key: PyObject, | |||||
default: Option<PyObject> | |||||
) -> PyResult<Option<PyObject>> { | |||||
let key = key.extract::<PyBytes>(py)?; | |||||
match self.inner(py).borrow_mut().copy_map.remove(key.data(py)) { | |||||
Some(_) => Ok(None), | |||||
None => Ok(default), | |||||
} | |||||
} | |||||
def copymapiter(&self) -> PyResult<CopyMapKeysIterator> { | |||||
CopyMapKeysIterator::from_inner( | |||||
py, | |||||
Some(DirstateMapLeakedRef::new(py, &self)), | |||||
self.leak_immutable(py).copy_map.iter(), | |||||
) | |||||
} | |||||
def copymapitemsiter(&self) -> PyResult<CopyMapItemsIterator> { | |||||
CopyMapItemsIterator::from_inner( | |||||
py, | |||||
Some(DirstateMapLeakedRef::new(py, &self)), | |||||
self.leak_immutable(py).copy_map.iter(), | |||||
) | |||||
} | |||||
}); | |||||
impl DirstateMap { | |||||
fn translate_key( | |||||
py: Python, | |||||
res: (&Vec<u8>, &DirstateEntry), | |||||
) -> PyResult<Option<PyBytes>> { | |||||
Ok(Some(PyBytes::new(py, res.0))) | |||||
} | |||||
fn translate_key_value( | |||||
py: Python, | |||||
res: (&Vec<u8>, &DirstateEntry), | |||||
) -> PyResult<Option<(PyBytes, PyObject)>> { | |||||
let (f, entry) = res; | |||||
// Explicitly go through u8 first, then cast to | |||||
// platform-specific `c_char`. | |||||
let state: u8 = entry.state.into(); | |||||
Ok(Some(( | |||||
PyBytes::new(py, f), | |||||
decapsule_make_dirstate_tuple(py)?( | |||||
state as c_char, | |||||
entry.mode, | |||||
entry.size, | |||||
entry.mtime, | |||||
), | |||||
))) | |||||
} | |||||
} | |||||
py_shared_ref!(DirstateMap, RustDirstateMap, inner, DirstateMapLeakedRef); | |||||
py_shared_mapping_iterator!( | |||||
DirstateMapKeysIterator, | |||||
DirstateMapLeakedRef, | |||||
Iter, | |||||
Vec<u8>, | |||||
DirstateEntry, | |||||
DirstateMap::translate_key, | |||||
Option<PyBytes> | |||||
); | |||||
py_shared_mapping_iterator!( | |||||
DirstateMapItemsIterator, | |||||
DirstateMapLeakedRef, | |||||
Iter, | |||||
Vec<u8>, | |||||
DirstateEntry, | |||||
DirstateMap::translate_key_value, | |||||
Option<(PyBytes, PyObject)> | |||||
); |
extern crate python27_sys as python_sys; | extern crate python27_sys as python_sys; | ||||
#[cfg(feature = "python3")] | #[cfg(feature = "python3")] | ||||
extern crate python3_sys as python_sys; | extern crate python3_sys as python_sys; | ||||
use self::python_sys::PyCapsule_Import; | use self::python_sys::PyCapsule_Import; | ||||
use libc::{c_char, c_int}; | use libc::{c_char, c_int}; | ||||
use std::mem::transmute; | use std::mem::transmute; | ||||
mod copymap; | |||||
mod dirs_multiset; | mod dirs_multiset; | ||||
mod dirstate_map; | |||||
use dirstate::dirs_multiset::Dirs; | use dirstate::dirs_multiset::Dirs; | ||||
use std::convert::TryFrom; | use dirstate::dirstate_map::DirstateMap; | ||||
use exceptions::AlreadyBorrowed; | use exceptions::AlreadyBorrowed; | ||||
use std::convert::TryFrom; | |||||
/// C code uses a custom `dirstate_tuple` type, checks in multiple instances | /// C code uses a custom `dirstate_tuple` type, checks in multiple instances | ||||
/// for this type, and raises a Python `Exception` if the check does not pass. | /// for this type, and raises a Python `Exception` if the check does not pass. | ||||
/// Because this type differs only in name from the regular Python tuple, it | /// Because this type differs only in name from the regular Python tuple, it | ||||
/// would be a good idea in the near future to remove it entirely to allow | /// would be a good idea in the near future to remove it entirely to allow | ||||
/// for a pure Python tuple of the same effective structure to be used, | /// for a pure Python tuple of the same effective structure to be used, | ||||
/// rendering this type and the capsule below useless. | /// rendering this type and the capsule below useless. | ||||
type MakeDirstateTupleFn = extern "C" fn( | type MakeDirstateTupleFn = extern "C" fn( | ||||
pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> { | pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> { | ||||
let dotted_name = &format!("{}.dirstate", package); | let dotted_name = &format!("{}.dirstate", package); | ||||
let m = PyModule::new(py, dotted_name)?; | let m = PyModule::new(py, dotted_name)?; | ||||
m.add(py, "__package__", package)?; | m.add(py, "__package__", package)?; | ||||
m.add(py, "__doc__", "Dirstate - Rust implementation")?; | m.add(py, "__doc__", "Dirstate - Rust implementation")?; | ||||
m.add_class::<Dirs>(py)?; | m.add_class::<Dirs>(py)?; | ||||
m.add_class::<DirstateMap>(py)?; | |||||
m.add(py, "AlreadyBorrowed", py.get_type::<AlreadyBorrowed>())?; | m.add(py, "AlreadyBorrowed", py.get_type::<AlreadyBorrowed>())?; | ||||
let sys = PyModule::import(py, "sys")?; | let sys = PyModule::import(py, "sys")?; | ||||
let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?; | let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?; | ||||
sys_modules.set_item(py, dotted_name, &m)?; | sys_modules.set_item(py, dotted_name, &m)?; | ||||
Ok(m) | Ok(m) | ||||
} | } |