##// END OF EJS Templates
rust-parsers: fix unboxing of PyInt on Python 3...
Yuya Nishihara -
r43061:98901eb1 default
parent child Browse files
Show More
@@ -1,207 +1,207 b''
1 // parsers.rs
1 // parsers.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::parsers` module provided by the
8 //! Bindings for the `hg::dirstate::parsers` module provided by the
9 //! `hg-core` package.
9 //! `hg-core` package.
10 //!
10 //!
11 //! From Python, this will be seen as `mercurial.rustext.parsers`
11 //! From Python, this will be seen as `mercurial.rustext.parsers`
12 //!
12 //!
13 use cpython::{
13 use cpython::{
14 exc, PyBytes, PyDict, PyErr, PyInt, PyModule, PyResult, PyTuple, Python,
14 exc, PyBytes, PyDict, PyErr, PyInt, PyModule, PyResult, PyTuple, Python,
15 ToPyObject,
15 PythonObject, ToPyObject,
16 };
16 };
17 use hg::{
17 use hg::{
18 pack_dirstate, parse_dirstate, utils::copy_into_array, DirstateEntry,
18 pack_dirstate, parse_dirstate, utils::copy_into_array, DirstateEntry,
19 DirstatePackError, DirstateParents, DirstateParseError, PARENT_SIZE,
19 DirstatePackError, DirstateParents, DirstateParseError, PARENT_SIZE,
20 };
20 };
21 use std::collections::HashMap;
21 use std::collections::HashMap;
22
22
23 use libc::c_char;
23 use libc::c_char;
24
24
25 use crate::dirstate::{decapsule_make_dirstate_tuple, extract_dirstate};
25 use crate::dirstate::{decapsule_make_dirstate_tuple, extract_dirstate};
26 use std::time::Duration;
26 use std::time::Duration;
27
27
28 fn parse_dirstate_wrapper(
28 fn parse_dirstate_wrapper(
29 py: Python,
29 py: Python,
30 dmap: PyDict,
30 dmap: PyDict,
31 copymap: PyDict,
31 copymap: PyDict,
32 st: PyBytes,
32 st: PyBytes,
33 ) -> PyResult<PyTuple> {
33 ) -> PyResult<PyTuple> {
34 let mut dirstate_map = HashMap::new();
34 let mut dirstate_map = HashMap::new();
35 let mut copies = HashMap::new();
35 let mut copies = HashMap::new();
36
36
37 match parse_dirstate(&mut dirstate_map, &mut copies, st.data(py)) {
37 match parse_dirstate(&mut dirstate_map, &mut copies, st.data(py)) {
38 Ok(parents) => {
38 Ok(parents) => {
39 for (filename, entry) in dirstate_map {
39 for (filename, entry) in dirstate_map {
40 // Explicitly go through u8 first, then cast to
40 // Explicitly go through u8 first, then cast to
41 // platform-specific `c_char` because Into<u8> has a specific
41 // platform-specific `c_char` because Into<u8> has a specific
42 // implementation while `as c_char` would just do a naive enum
42 // implementation while `as c_char` would just do a naive enum
43 // cast.
43 // cast.
44 let state: u8 = entry.state.into();
44 let state: u8 = entry.state.into();
45
45
46 dmap.set_item(
46 dmap.set_item(
47 py,
47 py,
48 PyBytes::new(py, &filename),
48 PyBytes::new(py, &filename),
49 decapsule_make_dirstate_tuple(py)?(
49 decapsule_make_dirstate_tuple(py)?(
50 state as c_char,
50 state as c_char,
51 entry.mode,
51 entry.mode,
52 entry.size,
52 entry.size,
53 entry.mtime,
53 entry.mtime,
54 ),
54 ),
55 )?;
55 )?;
56 }
56 }
57 for (path, copy_path) in copies {
57 for (path, copy_path) in copies {
58 copymap.set_item(
58 copymap.set_item(
59 py,
59 py,
60 PyBytes::new(py, &path),
60 PyBytes::new(py, &path),
61 PyBytes::new(py, &copy_path),
61 PyBytes::new(py, &copy_path),
62 )?;
62 )?;
63 }
63 }
64 Ok(
64 Ok(
65 (PyBytes::new(py, &parents.p1), PyBytes::new(py, &parents.p2))
65 (PyBytes::new(py, &parents.p1), PyBytes::new(py, &parents.p2))
66 .to_py_object(py),
66 .to_py_object(py),
67 )
67 )
68 }
68 }
69 Err(e) => Err(PyErr::new::<exc::ValueError, _>(
69 Err(e) => Err(PyErr::new::<exc::ValueError, _>(
70 py,
70 py,
71 match e {
71 match e {
72 DirstateParseError::TooLittleData => {
72 DirstateParseError::TooLittleData => {
73 "too little data for parents".to_string()
73 "too little data for parents".to_string()
74 }
74 }
75 DirstateParseError::Overflow => {
75 DirstateParseError::Overflow => {
76 "overflow in dirstate".to_string()
76 "overflow in dirstate".to_string()
77 }
77 }
78 DirstateParseError::CorruptedEntry(e) => e,
78 DirstateParseError::CorruptedEntry(e) => e,
79 DirstateParseError::Damaged => {
79 DirstateParseError::Damaged => {
80 "dirstate appears to be damaged".to_string()
80 "dirstate appears to be damaged".to_string()
81 }
81 }
82 },
82 },
83 )),
83 )),
84 }
84 }
85 }
85 }
86
86
87 fn pack_dirstate_wrapper(
87 fn pack_dirstate_wrapper(
88 py: Python,
88 py: Python,
89 dmap: PyDict,
89 dmap: PyDict,
90 copymap: PyDict,
90 copymap: PyDict,
91 pl: PyTuple,
91 pl: PyTuple,
92 now: PyInt,
92 now: PyInt,
93 ) -> PyResult<PyBytes> {
93 ) -> PyResult<PyBytes> {
94 let p1 = pl.get_item(py, 0).extract::<PyBytes>(py)?;
94 let p1 = pl.get_item(py, 0).extract::<PyBytes>(py)?;
95 let p1: &[u8] = p1.data(py);
95 let p1: &[u8] = p1.data(py);
96 let p2 = pl.get_item(py, 1).extract::<PyBytes>(py)?;
96 let p2 = pl.get_item(py, 1).extract::<PyBytes>(py)?;
97 let p2: &[u8] = p2.data(py);
97 let p2: &[u8] = p2.data(py);
98
98
99 let mut dirstate_map = extract_dirstate(py, &dmap)?;
99 let mut dirstate_map = extract_dirstate(py, &dmap)?;
100
100
101 let copies: Result<HashMap<Vec<u8>, Vec<u8>>, PyErr> = copymap
101 let copies: Result<HashMap<Vec<u8>, Vec<u8>>, PyErr> = copymap
102 .items(py)
102 .items(py)
103 .iter()
103 .iter()
104 .map(|(key, value)| {
104 .map(|(key, value)| {
105 Ok((
105 Ok((
106 key.extract::<PyBytes>(py)?.data(py).to_owned(),
106 key.extract::<PyBytes>(py)?.data(py).to_owned(),
107 value.extract::<PyBytes>(py)?.data(py).to_owned(),
107 value.extract::<PyBytes>(py)?.data(py).to_owned(),
108 ))
108 ))
109 })
109 })
110 .collect();
110 .collect();
111
111
112 if p1.len() != PARENT_SIZE || p2.len() != PARENT_SIZE {
112 if p1.len() != PARENT_SIZE || p2.len() != PARENT_SIZE {
113 return Err(PyErr::new::<exc::ValueError, _>(
113 return Err(PyErr::new::<exc::ValueError, _>(
114 py,
114 py,
115 "expected a 20-byte hash".to_string(),
115 "expected a 20-byte hash".to_string(),
116 ));
116 ));
117 }
117 }
118
118
119 match pack_dirstate(
119 match pack_dirstate(
120 &mut dirstate_map,
120 &mut dirstate_map,
121 &copies?,
121 &copies?,
122 DirstateParents {
122 DirstateParents {
123 p1: copy_into_array(&p1),
123 p1: copy_into_array(&p1),
124 p2: copy_into_array(&p2),
124 p2: copy_into_array(&p2),
125 },
125 },
126 Duration::from_secs(now.value(py) as u64),
126 Duration::from_secs(now.as_object().extract::<u64>(py)?),
127 ) {
127 ) {
128 Ok(packed) => {
128 Ok(packed) => {
129 for (
129 for (
130 filename,
130 filename,
131 DirstateEntry {
131 DirstateEntry {
132 state,
132 state,
133 mode,
133 mode,
134 size,
134 size,
135 mtime,
135 mtime,
136 },
136 },
137 ) in dirstate_map
137 ) in dirstate_map
138 {
138 {
139 // Explicitly go through u8 first, then cast to
139 // Explicitly go through u8 first, then cast to
140 // platform-specific `c_char` because Into<u8> has a specific
140 // platform-specific `c_char` because Into<u8> has a specific
141 // implementation while `as c_char` would just do a naive enum
141 // implementation while `as c_char` would just do a naive enum
142 // cast.
142 // cast.
143 let state: u8 = state.into();
143 let state: u8 = state.into();
144 dmap.set_item(
144 dmap.set_item(
145 py,
145 py,
146 PyBytes::new(py, &filename[..]),
146 PyBytes::new(py, &filename[..]),
147 decapsule_make_dirstate_tuple(py)?(
147 decapsule_make_dirstate_tuple(py)?(
148 state as c_char,
148 state as c_char,
149 mode,
149 mode,
150 size,
150 size,
151 mtime,
151 mtime,
152 ),
152 ),
153 )?;
153 )?;
154 }
154 }
155 Ok(PyBytes::new(py, &packed))
155 Ok(PyBytes::new(py, &packed))
156 }
156 }
157 Err(error) => Err(PyErr::new::<exc::ValueError, _>(
157 Err(error) => Err(PyErr::new::<exc::ValueError, _>(
158 py,
158 py,
159 match error {
159 match error {
160 DirstatePackError::CorruptedParent => {
160 DirstatePackError::CorruptedParent => {
161 "expected a 20-byte hash".to_string()
161 "expected a 20-byte hash".to_string()
162 }
162 }
163 DirstatePackError::CorruptedEntry(e) => e,
163 DirstatePackError::CorruptedEntry(e) => e,
164 DirstatePackError::BadSize(expected, actual) => {
164 DirstatePackError::BadSize(expected, actual) => {
165 format!("bad dirstate size: {} != {}", actual, expected)
165 format!("bad dirstate size: {} != {}", actual, expected)
166 }
166 }
167 },
167 },
168 )),
168 )),
169 }
169 }
170 }
170 }
171
171
172 /// Create the module, with `__package__` given from parent
172 /// Create the module, with `__package__` given from parent
173 pub fn init_parsers_module(py: Python, package: &str) -> PyResult<PyModule> {
173 pub fn init_parsers_module(py: Python, package: &str) -> PyResult<PyModule> {
174 let dotted_name = &format!("{}.parsers", package);
174 let dotted_name = &format!("{}.parsers", package);
175 let m = PyModule::new(py, dotted_name)?;
175 let m = PyModule::new(py, dotted_name)?;
176
176
177 m.add(py, "__package__", package)?;
177 m.add(py, "__package__", package)?;
178 m.add(py, "__doc__", "Parsers - Rust implementation")?;
178 m.add(py, "__doc__", "Parsers - Rust implementation")?;
179
179
180 m.add(
180 m.add(
181 py,
181 py,
182 "parse_dirstate",
182 "parse_dirstate",
183 py_fn!(
183 py_fn!(
184 py,
184 py,
185 parse_dirstate_wrapper(dmap: PyDict, copymap: PyDict, st: PyBytes)
185 parse_dirstate_wrapper(dmap: PyDict, copymap: PyDict, st: PyBytes)
186 ),
186 ),
187 )?;
187 )?;
188 m.add(
188 m.add(
189 py,
189 py,
190 "pack_dirstate",
190 "pack_dirstate",
191 py_fn!(
191 py_fn!(
192 py,
192 py,
193 pack_dirstate_wrapper(
193 pack_dirstate_wrapper(
194 dmap: PyDict,
194 dmap: PyDict,
195 copymap: PyDict,
195 copymap: PyDict,
196 pl: PyTuple,
196 pl: PyTuple,
197 now: PyInt
197 now: PyInt
198 )
198 )
199 ),
199 ),
200 )?;
200 )?;
201
201
202 let sys = PyModule::import(py, "sys")?;
202 let sys = PyModule::import(py, "sys")?;
203 let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?;
203 let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?;
204 sys_modules.set_item(py, dotted_name, &m)?;
204 sys_modules.set_item(py, dotted_name, &m)?;
205
205
206 Ok(m)
206 Ok(m)
207 }
207 }
General Comments 0
You need to be logged in to leave comments. Login now