##// END OF EJS Templates
rust-cpython: fix signature of make_dirstate_tuple()...
Yuya Nishihara -
r43481:3fec5244 default
parent child Browse files
Show More
@@ -1,130 +1,132
1 // dirstate.rs
1 // dirstate.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` module provided by the
8 //! Bindings for the `hg::dirstate` module provided by the
9 //! `hg-core` package.
9 //! `hg-core` package.
10 //!
10 //!
11 //! From Python, this will be seen as `mercurial.rustext.dirstate`
11 //! From Python, this will be seen as `mercurial.rustext.dirstate`
12 mod copymap;
12 mod copymap;
13 mod dirs_multiset;
13 mod dirs_multiset;
14 mod dirstate_map;
14 mod dirstate_map;
15 use crate::dirstate::{dirs_multiset::Dirs, dirstate_map::DirstateMap};
15 use crate::dirstate::{dirs_multiset::Dirs, dirstate_map::DirstateMap};
16 use cpython::{
16 use cpython::{
17 exc, PyBytes, PyDict, PyErr, PyModule, PyObject, PyResult, PySequence,
17 exc, PyBytes, PyDict, PyErr, PyModule, PyObject, PyResult, PySequence,
18 Python,
18 Python,
19 };
19 };
20 use hg::{
20 use hg::{
21 utils::hg_path::HgPathBuf, DirstateEntry, DirstateParseError, EntryState,
21 utils::hg_path::HgPathBuf, DirstateEntry, DirstateParseError, EntryState,
22 StateMap,
22 StateMap,
23 };
23 };
24 use libc::{c_char, c_int};
24 use libc::{c_char, c_int};
25 #[cfg(feature = "python27")]
25 #[cfg(feature = "python27")]
26 use python27_sys::PyCapsule_Import;
26 use python27_sys as python_sys;
27 #[cfg(feature = "python3")]
27 #[cfg(feature = "python3")]
28 use python3_sys::PyCapsule_Import;
28 use python3_sys as python_sys;
29 use python_sys::PyCapsule_Import;
29 use std::convert::TryFrom;
30 use std::convert::TryFrom;
30 use std::ffi::CStr;
31 use std::ffi::CStr;
31 use std::mem::transmute;
32 use std::mem::transmute;
32
33
33 /// C code uses a custom `dirstate_tuple` type, checks in multiple instances
34 /// C code uses a custom `dirstate_tuple` type, checks in multiple instances
34 /// for this type, and raises a Python `Exception` if the check does not pass.
35 /// for this type, and raises a Python `Exception` if the check does not pass.
35 /// Because this type differs only in name from the regular Python tuple, it
36 /// Because this type differs only in name from the regular Python tuple, it
36 /// would be a good idea in the near future to remove it entirely to allow
37 /// would be a good idea in the near future to remove it entirely to allow
37 /// for a pure Python tuple of the same effective structure to be used,
38 /// for a pure Python tuple of the same effective structure to be used,
38 /// rendering this type and the capsule below useless.
39 /// rendering this type and the capsule below useless.
39 type MakeDirstateTupleFn = unsafe extern "C" fn(
40 type MakeDirstateTupleFn = unsafe extern "C" fn(
40 state: c_char,
41 state: c_char,
41 mode: c_int,
42 mode: c_int,
42 size: c_int,
43 size: c_int,
43 mtime: c_int,
44 mtime: c_int,
44 ) -> PyObject;
45 ) -> *mut python_sys::PyObject;
45
46
46 /// This is largely a copy/paste from cindex.rs, pending the merge of a
47 /// This is largely a copy/paste from cindex.rs, pending the merge of a
47 /// `py_capsule_fn!` macro in the rust-cpython project:
48 /// `py_capsule_fn!` macro in the rust-cpython project:
48 /// https://github.com/dgrunwald/rust-cpython/pull/169
49 /// https://github.com/dgrunwald/rust-cpython/pull/169
49 fn decapsule_make_dirstate_tuple(py: Python) -> PyResult<MakeDirstateTupleFn> {
50 fn decapsule_make_dirstate_tuple(py: Python) -> PyResult<MakeDirstateTupleFn> {
50 unsafe {
51 unsafe {
51 let caps_name = CStr::from_bytes_with_nul_unchecked(
52 let caps_name = CStr::from_bytes_with_nul_unchecked(
52 b"mercurial.cext.parsers.make_dirstate_tuple_CAPI\0",
53 b"mercurial.cext.parsers.make_dirstate_tuple_CAPI\0",
53 );
54 );
54 let from_caps = PyCapsule_Import(caps_name.as_ptr(), 0);
55 let from_caps = PyCapsule_Import(caps_name.as_ptr(), 0);
55 if from_caps.is_null() {
56 if from_caps.is_null() {
56 return Err(PyErr::fetch(py));
57 return Err(PyErr::fetch(py));
57 }
58 }
58 Ok(transmute(from_caps))
59 Ok(transmute(from_caps))
59 }
60 }
60 }
61 }
61
62
62 pub fn make_dirstate_tuple(
63 pub fn make_dirstate_tuple(
63 py: Python,
64 py: Python,
64 entry: &DirstateEntry,
65 entry: &DirstateEntry,
65 ) -> PyResult<PyObject> {
66 ) -> PyResult<PyObject> {
66 let make = decapsule_make_dirstate_tuple(py)?;
67 let make = decapsule_make_dirstate_tuple(py)?;
67
68
68 let &DirstateEntry {
69 let &DirstateEntry {
69 state,
70 state,
70 mode,
71 mode,
71 size,
72 size,
72 mtime,
73 mtime,
73 } = entry;
74 } = entry;
74 // Explicitly go through u8 first, then cast to platform-specific `c_char`
75 // Explicitly go through u8 first, then cast to platform-specific `c_char`
75 // because Into<u8> has a specific implementation while `as c_char` would
76 // because Into<u8> has a specific implementation while `as c_char` would
76 // just do a naive enum cast.
77 // just do a naive enum cast.
77 let state_code: u8 = state.into();
78 let state_code: u8 = state.into();
78
79
79 unsafe {
80 let maybe_obj = unsafe {
80 let ptr = make(state_code as c_char, mode, size, mtime);
81 let ptr = make(state_code as c_char, mode, size, mtime);
81 Ok(ptr)
82 PyObject::from_owned_ptr_opt(py, ptr)
82 }
83 };
84 maybe_obj.ok_or_else(|| PyErr::fetch(py))
83 }
85 }
84
86
85 pub fn extract_dirstate(py: Python, dmap: &PyDict) -> Result<StateMap, PyErr> {
87 pub fn extract_dirstate(py: Python, dmap: &PyDict) -> Result<StateMap, PyErr> {
86 dmap.items(py)
88 dmap.items(py)
87 .iter()
89 .iter()
88 .map(|(filename, stats)| {
90 .map(|(filename, stats)| {
89 let stats = stats.extract::<PySequence>(py)?;
91 let stats = stats.extract::<PySequence>(py)?;
90 let state = stats.get_item(py, 0)?.extract::<PyBytes>(py)?;
92 let state = stats.get_item(py, 0)?.extract::<PyBytes>(py)?;
91 let state = EntryState::try_from(state.data(py)[0]).map_err(
93 let state = EntryState::try_from(state.data(py)[0]).map_err(
92 |e: DirstateParseError| {
94 |e: DirstateParseError| {
93 PyErr::new::<exc::ValueError, _>(py, e.to_string())
95 PyErr::new::<exc::ValueError, _>(py, e.to_string())
94 },
96 },
95 )?;
97 )?;
96 let mode = stats.get_item(py, 1)?.extract(py)?;
98 let mode = stats.get_item(py, 1)?.extract(py)?;
97 let size = stats.get_item(py, 2)?.extract(py)?;
99 let size = stats.get_item(py, 2)?.extract(py)?;
98 let mtime = stats.get_item(py, 3)?.extract(py)?;
100 let mtime = stats.get_item(py, 3)?.extract(py)?;
99 let filename = filename.extract::<PyBytes>(py)?;
101 let filename = filename.extract::<PyBytes>(py)?;
100 let filename = filename.data(py);
102 let filename = filename.data(py);
101 Ok((
103 Ok((
102 HgPathBuf::from(filename.to_owned()),
104 HgPathBuf::from(filename.to_owned()),
103 DirstateEntry {
105 DirstateEntry {
104 state,
106 state,
105 mode,
107 mode,
106 size,
108 size,
107 mtime,
109 mtime,
108 },
110 },
109 ))
111 ))
110 })
112 })
111 .collect()
113 .collect()
112 }
114 }
113
115
114 /// Create the module, with `__package__` given from parent
116 /// Create the module, with `__package__` given from parent
115 pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> {
117 pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> {
116 let dotted_name = &format!("{}.dirstate", package);
118 let dotted_name = &format!("{}.dirstate", package);
117 let m = PyModule::new(py, dotted_name)?;
119 let m = PyModule::new(py, dotted_name)?;
118
120
119 m.add(py, "__package__", package)?;
121 m.add(py, "__package__", package)?;
120 m.add(py, "__doc__", "Dirstate - Rust implementation")?;
122 m.add(py, "__doc__", "Dirstate - Rust implementation")?;
121
123
122 m.add_class::<Dirs>(py)?;
124 m.add_class::<Dirs>(py)?;
123 m.add_class::<DirstateMap>(py)?;
125 m.add_class::<DirstateMap>(py)?;
124
126
125 let sys = PyModule::import(py, "sys")?;
127 let sys = PyModule::import(py, "sys")?;
126 let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?;
128 let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?;
127 sys_modules.set_item(py, dotted_name, &m)?;
129 sys_modules.set_item(py, dotted_name, &m)?;
128
130
129 Ok(m)
131 Ok(m)
130 }
132 }
General Comments 0
You need to be logged in to leave comments. Login now