dirstate.rs
106 lines
| 3.6 KiB
| application/rls-services+xml
|
RustLexer
Raphaël Gomès
|
r42489 | // dirstate.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` module provided by the | ||||
//! `hg-core` package. | ||||
//! | ||||
//! From Python, this will be seen as `mercurial.rustext.dirstate` | ||||
Raphaël Gomès
|
r42999 | mod copymap; | ||
Raphaël Gomès
|
r42991 | mod dirs_multiset; | ||
Raphaël Gomès
|
r42999 | mod dirstate_map; | ||
use crate::dirstate::{dirs_multiset::Dirs, dirstate_map::DirstateMap}; | ||||
Raphaël Gomès
|
r42489 | use cpython::{ | ||
Raphaël Gomès
|
r42994 | exc, PyBytes, PyDict, PyErr, PyModule, PyObject, PyResult, PySequence, | ||
Python, | ||||
Raphaël Gomès
|
r42489 | }; | ||
Raphaël Gomès
|
r42994 | use hg::{DirstateEntry, DirstateParseError, EntryState, StateMap}; | ||
Raphaël Gomès
|
r42828 | use libc::{c_char, c_int}; | ||
#[cfg(feature = "python27")] | ||||
use python27_sys::PyCapsule_Import; | ||||
#[cfg(feature = "python3")] | ||||
use python3_sys::PyCapsule_Import; | ||||
Raphaël Gomès
|
r42994 | use std::convert::TryFrom; | ||
Raphaël Gomès
|
r42489 | use std::ffi::CStr; | ||
use std::mem::transmute; | ||||
/// 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. | ||||
/// 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 | ||||
/// for a pure Python tuple of the same effective structure to be used, | ||||
/// rendering this type and the capsule below useless. | ||||
type MakeDirstateTupleFn = extern "C" fn( | ||||
state: c_char, | ||||
mode: c_int, | ||||
size: c_int, | ||||
mtime: c_int, | ||||
) -> PyObject; | ||||
/// This is largely a copy/paste from cindex.rs, pending the merge of a | ||||
/// `py_capsule_fn!` macro in the rust-cpython project: | ||||
/// https://github.com/dgrunwald/rust-cpython/pull/169 | ||||
Raphaël Gomès
|
r42992 | pub fn decapsule_make_dirstate_tuple( | ||
py: Python, | ||||
) -> PyResult<MakeDirstateTupleFn> { | ||||
Raphaël Gomès
|
r42489 | unsafe { | ||
let caps_name = CStr::from_bytes_with_nul_unchecked( | ||||
b"mercurial.cext.parsers.make_dirstate_tuple_CAPI\0", | ||||
); | ||||
let from_caps = PyCapsule_Import(caps_name.as_ptr(), 0); | ||||
if from_caps.is_null() { | ||||
return Err(PyErr::fetch(py)); | ||||
} | ||||
Ok(transmute(from_caps)) | ||||
} | ||||
} | ||||
Raphaël Gomès
|
r42993 | pub fn extract_dirstate(py: Python, dmap: &PyDict) -> Result<StateMap, PyErr> { | ||
Raphaël Gomès
|
r42737 | dmap.items(py) | ||
Raphaël Gomès
|
r42489 | .iter() | ||
.map(|(filename, stats)| { | ||||
let stats = stats.extract::<PySequence>(py)?; | ||||
let state = stats.get_item(py, 0)?.extract::<PyBytes>(py)?; | ||||
Raphaël Gomès
|
r42994 | let state = EntryState::try_from(state.data(py)[0]).map_err( | ||
|e: DirstateParseError| { | ||||
PyErr::new::<exc::ValueError, _>(py, e.to_string()) | ||||
}, | ||||
)?; | ||||
Raphaël Gomès
|
r42489 | let mode = stats.get_item(py, 1)?.extract(py)?; | ||
let size = stats.get_item(py, 2)?.extract(py)?; | ||||
let mtime = stats.get_item(py, 3)?.extract(py)?; | ||||
let filename = filename.extract::<PyBytes>(py)?; | ||||
let filename = filename.data(py); | ||||
Ok(( | ||||
filename.to_owned(), | ||||
DirstateEntry { | ||||
state, | ||||
mode, | ||||
size, | ||||
mtime, | ||||
}, | ||||
)) | ||||
}) | ||||
Raphaël Gomès
|
r42737 | .collect() | ||
} | ||||
Raphaël Gomès
|
r42489 | /// Create the module, with `__package__` given from parent | ||
pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> { | ||||
let dotted_name = &format!("{}.dirstate", package); | ||||
let m = PyModule::new(py, dotted_name)?; | ||||
Raphaël Gomès
|
r42737 | |||
Raphaël Gomès
|
r42489 | m.add(py, "__package__", package)?; | ||
m.add(py, "__doc__", "Dirstate - Rust implementation")?; | ||||
Raphaël Gomès
|
r42737 | m.add_class::<Dirs>(py)?; | ||
Raphaël Gomès
|
r42999 | m.add_class::<DirstateMap>(py)?; | ||
Raphaël Gomès
|
r42737 | |||
Raphaël Gomès
|
r42489 | let sys = PyModule::import(py, "sys")?; | ||
let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?; | ||||
sys_modules.set_item(py, dotted_name, &m)?; | ||||
Ok(m) | ||||
} | ||||