# HG changeset patch
# User Yuya Nishihara
# Date 1570953317 -32400
# Sun Oct 13 16:55:17 2019 +0900
# Node ID 083f70b7b5899755bb28ce16d6fc45eee46e84e4
# Parent dbe969ca04b9711aa3b244b2dcea9b9925bab960
rust-cpython: add wrapper around decapsule_make_dirstate_tuple()
There are a couple of safety issues. First, the returned function pointer
must be unsafe. Second, its return value must be a raw pointer (i.e.
python27_sys::PyObject), not a cpython::PyObject. The wrapper function will
address these issues.
diff --git a/rust/hg-cpython/src/dirstate.rs b/rust/hg-cpython/src/dirstate.rs
--- a/rust/hg-cpython/src/dirstate.rs
+++ b/rust/hg-cpython/src/dirstate.rs
@@ -46,9 +46,7 @@ type MakeDirstateTupleFn = extern "C" fn
/// 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
-pub fn decapsule_make_dirstate_tuple(
-py: Python,
-) -> PyResult {
+fn decapsule_make_dirstate_tuple(py: Python) -> PyResult {
unsafe {
let caps_name = CStr::from_bytes_with_nul_unchecked(
b"mercurial.cext.parsers.make_dirstate_tuple_CAPI\0",
@@ -61,6 +59,25 @@ pub fn decapsule_make_dirstate_tuple(
}
}
+pub fn make_dirstate_tuple(
+py: Python,
+entry: ,
+) -> PyResult {
+let make = decapsule_make_dirstate_tuple(py)?;
+
+let {
+state,
+mode,
+size,
+mtime,
+} = entry;
+// Explicitly go through u8 first, then cast to platform-specific `c_char`
+// because Into has a specific implementation while `as c_char` would
+// just do a naive enum cast.
+let state_code: u8 = state.into();
+Ok(make(state_code as c_char, mode, size, mtime))
+}
+
pub fn extract_dirstate(py: Python, dmap: ) -> Result {
dmap.items(py)
.iter()
diff --git a/rust/hg-cpython/src/dirstate/dirstate_map.rs
b/rust/hg-cpython/src/dirstate/dirstate_map.rs
--- a/rust/hg-cpython/src/dirstate/dirstate_map.rs
+++ b/rust/hg-cpython/src/dirstate/dirstate_map.rs
@@ -16,11 +16,10 @@ use cpython::{
exc, ObjectProtocol, PyBool, PyBytes, PyClone, PyDict, PyErr, PyObject,
PyResult, PyTuple, Python, PythonObject, ToPyObject,
};
-use libc::c_char;
use crate::{
dirstate::copymap::{CopyMap, CopyMapItemsIterator, CopyMapKeysIterator},
-dirstate::{decapsule_make_dirstate_tuple, dirs_multiset::Dirs},
+dirstate::{dirs_multiset::Dirs, make_dirstate_tuple},
ref_sharing::{PyLeakedRef, PySharedRefCell},
};
use hg::{
@@ -66,15 +65,7 @@ py_class!(pub class DirstateMap |py| {
let key = key.extract::(py)?;
match self.inner_shared(py).borrow().get(HgPath::new(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,
-)))
+Ok(Some(make_dirstate_tuple(py, entry)?))
},
None => Ok(default)
}
@@ -303,15 +294,7 @@ py_class!(pub class DirstateMap |py| {
let key = HgPath::new(key.data(py));
match self.inner_shared(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,
-))
+Ok(make_dirstate_tuple(py, entry)?)
},
None => Err(PyErr::new::(
py,
@@ -483,18 +466,9 @@ impl DirstateMap {
res: (, ),
) -> PyResult> {
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.as_ref()),
-decapsule_make_dirstate_tuple(py)?(
-state as c_char,
-entry.mode,
-entry.size,
-entry.mtime,
-),
+make_dirstate_tuple(py, entry)?,
)))
}
}
diff --git a/rust/hg-cpython/src/parsers.rs b/rust/hg-cpython/src/parsers.rs
--- a/rust/hg-cpython/src/parsers.rs
+++ b/rust/hg-cpython/src/parsers.rs
@@ -15,15 +15,13 @@ use cpython::{
PythonObject, ToPyObject,
};
use hg::{
-pack_dirstate, parse_dirstate, utils::hg_path::HgPathBuf, DirstateEntry,
+pack_dirstate, parse_dirstate, utils::hg_path::HgPathBuf,
DirstatePackError, DirstateParents,