##// END OF EJS Templates
rust: run cargo fmt
Raphaël Gomès -
r43087:6a551a2d default
parent child Browse files
Show More
@@ -1,73 +1,73 b''
1 // lib.rs
1 // lib.rs
2 //
2 //
3 // Copyright 2018 Georges Racinet <gracinet@anybox.fr>
3 // Copyright 2018 Georges Racinet <gracinet@anybox.fr>
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 //! Python bindings of `hg-core` objects using the `cpython` crate.
8 //! Python bindings of `hg-core` objects using the `cpython` crate.
9 //! Once compiled, the resulting single shared library object can be placed in
9 //! Once compiled, the resulting single shared library object can be placed in
10 //! the `mercurial` package directly as `rustext.so` or `rustext.dll`.
10 //! the `mercurial` package directly as `rustext.so` or `rustext.dll`.
11 //! It holds several modules, so that from the point of view of Python,
11 //! It holds several modules, so that from the point of view of Python,
12 //! it behaves as the `cext` package.
12 //! it behaves as the `cext` package.
13 //!
13 //!
14 //! Example:
14 //! Example:
15 //!
15 //!
16 //! ```text
16 //! ```text
17 //! >>> from mercurial.rustext import ancestor
17 //! >>> from mercurial.rustext import ancestor
18 //! >>> ancestor.__doc__
18 //! >>> ancestor.__doc__
19 //! 'Generic DAG ancestor algorithms - Rust implementation'
19 //! 'Generic DAG ancestor algorithms - Rust implementation'
20 //! ```
20 //! ```
21
21
22 /// This crate uses nested private macros, `extern crate` is still needed in
22 /// This crate uses nested private macros, `extern crate` is still needed in
23 /// 2018 edition.
23 /// 2018 edition.
24 #[macro_use]
24 #[macro_use]
25 extern crate cpython;
25 extern crate cpython;
26
26
27 pub mod ancestors;
27 pub mod ancestors;
28 mod cindex;
28 mod cindex;
29 mod conversion;
29 mod conversion;
30 #[macro_use]
30 #[macro_use]
31 pub mod ref_sharing;
31 pub mod ref_sharing;
32 pub mod dagops;
32 pub mod dagops;
33 pub mod dirstate;
33 pub mod dirstate;
34 pub mod parsers;
35 pub mod discovery;
34 pub mod discovery;
36 pub mod exceptions;
35 pub mod exceptions;
37 pub mod filepatterns;
36 pub mod filepatterns;
37 pub mod parsers;
38
38
39 py_module_initializer!(rustext, initrustext, PyInit_rustext, |py, m| {
39 py_module_initializer!(rustext, initrustext, PyInit_rustext, |py, m| {
40 m.add(
40 m.add(
41 py,
41 py,
42 "__doc__",
42 "__doc__",
43 "Mercurial core concepts - Rust implementation",
43 "Mercurial core concepts - Rust implementation",
44 )?;
44 )?;
45
45
46 let dotted_name: String = m.get(py, "__name__")?.extract(py)?;
46 let dotted_name: String = m.get(py, "__name__")?.extract(py)?;
47 m.add(py, "ancestor", ancestors::init_module(py, &dotted_name)?)?;
47 m.add(py, "ancestor", ancestors::init_module(py, &dotted_name)?)?;
48 m.add(py, "dagop", dagops::init_module(py, &dotted_name)?)?;
48 m.add(py, "dagop", dagops::init_module(py, &dotted_name)?)?;
49 m.add(py, "discovery", discovery::init_module(py, &dotted_name)?)?;
49 m.add(py, "discovery", discovery::init_module(py, &dotted_name)?)?;
50 m.add(py, "dirstate", dirstate::init_module(py, &dotted_name)?)?;
50 m.add(py, "dirstate", dirstate::init_module(py, &dotted_name)?)?;
51 m.add(
51 m.add(
52 py,
52 py,
53 "filepatterns",
53 "filepatterns",
54 filepatterns::init_module(py, &dotted_name)?,
54 filepatterns::init_module(py, &dotted_name)?,
55 )?;
55 )?;
56 m.add(
56 m.add(
57 py,
57 py,
58 "parsers",
58 "parsers",
59 parsers::init_parsers_module(py, &dotted_name)?,
59 parsers::init_parsers_module(py, &dotted_name)?,
60 )?;
60 )?;
61 m.add(py, "GraphError", py.get_type::<exceptions::GraphError>())?;
61 m.add(py, "GraphError", py.get_type::<exceptions::GraphError>())?;
62 m.add(
62 m.add(
63 py,
63 py,
64 "PatternFileError",
64 "PatternFileError",
65 py.get_type::<exceptions::PatternFileError>(),
65 py.get_type::<exceptions::PatternFileError>(),
66 )?;
66 )?;
67 m.add(
67 m.add(
68 py,
68 py,
69 "PatternError",
69 "PatternError",
70 py.get_type::<exceptions::PatternError>(),
70 py.get_type::<exceptions::PatternError>(),
71 )?;
71 )?;
72 Ok(())
72 Ok(())
73 });
73 });
@@ -1,271 +1,282 b''
1 // Copyright 2018 Georges Racinet <gracinet@anybox.fr>
1 // Copyright 2018 Georges Racinet <gracinet@anybox.fr>
2 //
2 //
3 // This software may be used and distributed according to the terms of the
3 // This software may be used and distributed according to the terms of the
4 // GNU General Public License version 2 or any later version.
4 // GNU General Public License version 2 or any later version.
5
5
6 //! Bindings for CPython extension code
6 //! Bindings for CPython extension code
7 //!
7 //!
8 //! This exposes methods to build and use a `rustlazyancestors` iterator
8 //! This exposes methods to build and use a `rustlazyancestors` iterator
9 //! from C code, using an index and its parents function that are passed
9 //! from C code, using an index and its parents function that are passed
10 //! from the caller at instantiation.
10 //! from the caller at instantiation.
11
11
12 use hg::AncestorsIterator;
12 use hg::AncestorsIterator;
13 use hg::{Graph, GraphError, Revision, NULL_REVISION};
13 use hg::{Graph, GraphError, Revision, NULL_REVISION};
14 use libc::{c_int, c_long, c_void, ssize_t};
14 use libc::{c_int, c_long, c_void, ssize_t};
15 use std::ptr::null_mut;
15 use std::ptr::null_mut;
16 use std::slice;
16 use std::slice;
17
17
18 type IndexPtr = *mut c_void;
18 type IndexPtr = *mut c_void;
19
19
20 extern "C" {
20 extern "C" {
21 fn HgRevlogIndex_GetParents(
21 fn HgRevlogIndex_GetParents(
22 op: IndexPtr,
22 op: IndexPtr,
23 rev: c_int,
23 rev: c_int,
24 parents: *mut [c_int; 2],
24 parents: *mut [c_int; 2],
25 ) -> c_int;
25 ) -> c_int;
26 }
26 }
27
27
28 /// A Graph backed up by objects and functions from revlog.c
28 /// A Graph backed up by objects and functions from revlog.c
29 ///
29 ///
30 /// This implementation of the Graph trait, relies on (pointers to)
30 /// This implementation of the Graph trait, relies on (pointers to)
31 /// - the C index object (`index` member)
31 /// - the C index object (`index` member)
32 /// - the `index_get_parents()` function (`parents` member)
32 /// - the `index_get_parents()` function (`parents` member)
33 pub struct Index {
33 pub struct Index {
34 index: IndexPtr,
34 index: IndexPtr,
35 }
35 }
36
36
37 impl Index {
37 impl Index {
38 pub fn new(index: IndexPtr) -> Self {
38 pub fn new(index: IndexPtr) -> Self {
39 Index {
39 Index { index: index }
40 index: index,
41 }
42 }
40 }
43 }
41 }
44
42
45 impl Graph for Index {
43 impl Graph for Index {
46 /// wrap a call to the C extern parents function
44 /// wrap a call to the C extern parents function
47 fn parents(&self, rev: Revision) -> Result<[Revision; 2], GraphError> {
45 fn parents(&self, rev: Revision) -> Result<[Revision; 2], GraphError> {
48 let mut res: [c_int; 2] = [0; 2];
46 let mut res: [c_int; 2] = [0; 2];
49 let code =
47 let code = unsafe {
50 unsafe { HgRevlogIndex_GetParents(self.index, rev, &mut res as *mut [c_int; 2]) };
48 HgRevlogIndex_GetParents(
49 self.index,
50 rev,
51 &mut res as *mut [c_int; 2],
52 )
53 };
51 match code {
54 match code {
52 0 => Ok(res),
55 0 => Ok(res),
53 _ => Err(GraphError::ParentOutOfRange(rev)),
56 _ => Err(GraphError::ParentOutOfRange(rev)),
54 }
57 }
55 }
58 }
56 }
59 }
57
60
58 /// Wrapping of AncestorsIterator<Index> constructor, for C callers.
61 /// Wrapping of AncestorsIterator<Index> constructor, for C callers.
59 ///
62 ///
60 /// Besides `initrevs`, `stoprev` and `inclusive`, that are converted
63 /// Besides `initrevs`, `stoprev` and `inclusive`, that are converted
61 /// we receive the index and the parents function as pointers
64 /// we receive the index and the parents function as pointers
62 #[no_mangle]
65 #[no_mangle]
63 pub extern "C" fn rustlazyancestors_init(
66 pub extern "C" fn rustlazyancestors_init(
64 index: IndexPtr,
67 index: IndexPtr,
65 initrevslen: ssize_t,
68 initrevslen: ssize_t,
66 initrevs: *mut c_long,
69 initrevs: *mut c_long,
67 stoprev: c_long,
70 stoprev: c_long,
68 inclusive: c_int,
71 inclusive: c_int,
69 ) -> *mut AncestorsIterator<Index> {
72 ) -> *mut AncestorsIterator<Index> {
70 assert!(initrevslen >= 0);
73 assert!(initrevslen >= 0);
71 unsafe {
74 unsafe {
72 raw_init(
75 raw_init(
73 Index::new(index),
76 Index::new(index),
74 initrevslen as usize,
77 initrevslen as usize,
75 initrevs,
78 initrevs,
76 stoprev,
79 stoprev,
77 inclusive,
80 inclusive,
78 )
81 )
79 }
82 }
80 }
83 }
81
84
82 /// Testable (for any Graph) version of rustlazyancestors_init
85 /// Testable (for any Graph) version of rustlazyancestors_init
83 #[inline]
86 #[inline]
84 unsafe fn raw_init<G: Graph>(
87 unsafe fn raw_init<G: Graph>(
85 graph: G,
88 graph: G,
86 initrevslen: usize,
89 initrevslen: usize,
87 initrevs: *mut c_long,
90 initrevs: *mut c_long,
88 stoprev: c_long,
91 stoprev: c_long,
89 inclusive: c_int,
92 inclusive: c_int,
90 ) -> *mut AncestorsIterator<G> {
93 ) -> *mut AncestorsIterator<G> {
91 let inclb = match inclusive {
94 let inclb = match inclusive {
92 0 => false,
95 0 => false,
93 1 => true,
96 1 => true,
94 _ => {
97 _ => {
95 return null_mut();
98 return null_mut();
96 }
99 }
97 };
100 };
98
101
99 let slice = slice::from_raw_parts(initrevs, initrevslen);
102 let slice = slice::from_raw_parts(initrevs, initrevslen);
100
103
101 Box::into_raw(Box::new(match AncestorsIterator::new(
104 Box::into_raw(Box::new(
102 graph,
105 match AncestorsIterator::new(
103 slice.into_iter().map(|&r| r as Revision),
106 graph,
104 stoprev as Revision,
107 slice.into_iter().map(|&r| r as Revision),
105 inclb,
108 stoprev as Revision,
106 ) {
109 inclb,
107 Ok(it) => it,
110 ) {
108 Err(_) => {
111 Ok(it) => it,
109 return null_mut();
112 Err(_) => {
110 }
113 return null_mut();
111 }))
114 }
115 },
116 ))
112 }
117 }
113
118
114 /// Deallocator to be called from C code
119 /// Deallocator to be called from C code
115 #[no_mangle]
120 #[no_mangle]
116 pub extern "C" fn rustlazyancestors_drop(raw_iter: *mut AncestorsIterator<Index>) {
121 pub extern "C" fn rustlazyancestors_drop(
122 raw_iter: *mut AncestorsIterator<Index>,
123 ) {
117 raw_drop(raw_iter);
124 raw_drop(raw_iter);
118 }
125 }
119
126
120 /// Testable (for any Graph) version of rustlazayancestors_drop
127 /// Testable (for any Graph) version of rustlazayancestors_drop
121 #[inline]
128 #[inline]
122 fn raw_drop<G: Graph>(raw_iter: *mut AncestorsIterator<G>) {
129 fn raw_drop<G: Graph>(raw_iter: *mut AncestorsIterator<G>) {
123 unsafe {
130 unsafe {
124 Box::from_raw(raw_iter);
131 Box::from_raw(raw_iter);
125 }
132 }
126 }
133 }
127
134
128 /// Iteration main method to be called from C code
135 /// Iteration main method to be called from C code
129 ///
136 ///
130 /// We convert the end of iteration into NULL_REVISION,
137 /// We convert the end of iteration into NULL_REVISION,
131 /// it will be up to the C wrapper to convert that back into a Python end of
138 /// it will be up to the C wrapper to convert that back into a Python end of
132 /// iteration
139 /// iteration
133 #[no_mangle]
140 #[no_mangle]
134 pub extern "C" fn rustlazyancestors_next(raw: *mut AncestorsIterator<Index>) -> c_long {
141 pub extern "C" fn rustlazyancestors_next(
142 raw: *mut AncestorsIterator<Index>,
143 ) -> c_long {
135 raw_next(raw)
144 raw_next(raw)
136 }
145 }
137
146
138 /// Testable (for any Graph) version of rustlazayancestors_next
147 /// Testable (for any Graph) version of rustlazayancestors_next
139 #[inline]
148 #[inline]
140 fn raw_next<G: Graph>(raw: *mut AncestorsIterator<G>) -> c_long {
149 fn raw_next<G: Graph>(raw: *mut AncestorsIterator<G>) -> c_long {
141 let as_ref = unsafe { &mut *raw };
150 let as_ref = unsafe { &mut *raw };
142 let rev = match as_ref.next() {
151 let rev = match as_ref.next() {
143 Some(Ok(rev)) => rev,
152 Some(Ok(rev)) => rev,
144 Some(Err(_)) | None => NULL_REVISION,
153 Some(Err(_)) | None => NULL_REVISION,
145 };
154 };
146 rev as c_long
155 rev as c_long
147 }
156 }
148
157
149 #[no_mangle]
158 #[no_mangle]
150 pub extern "C" fn rustlazyancestors_contains(
159 pub extern "C" fn rustlazyancestors_contains(
151 raw: *mut AncestorsIterator<Index>,
160 raw: *mut AncestorsIterator<Index>,
152 target: c_long,
161 target: c_long,
153 ) -> c_int {
162 ) -> c_int {
154 raw_contains(raw, target)
163 raw_contains(raw, target)
155 }
164 }
156
165
157 /// Testable (for any Graph) version of rustlazayancestors_next
166 /// Testable (for any Graph) version of rustlazayancestors_next
158 #[inline]
167 #[inline]
159 fn raw_contains<G: Graph>(
168 fn raw_contains<G: Graph>(
160 raw: *mut AncestorsIterator<G>,
169 raw: *mut AncestorsIterator<G>,
161 target: c_long,
170 target: c_long,
162 ) -> c_int {
171 ) -> c_int {
163 let as_ref = unsafe { &mut *raw };
172 let as_ref = unsafe { &mut *raw };
164 match as_ref.contains(target as Revision) {
173 match as_ref.contains(target as Revision) {
165 Ok(r) => r as c_int,
174 Ok(r) => r as c_int,
166 Err(_) => -1,
175 Err(_) => -1,
167 }
176 }
168 }
177 }
169
178
170 #[cfg(test)]
179 #[cfg(test)]
171 mod tests {
180 mod tests {
172 use super::*;
181 use super::*;
173 use std::thread;
182 use std::thread;
174
183
175 #[derive(Clone, Debug)]
184 #[derive(Clone, Debug)]
176 struct Stub;
185 struct Stub;
177
186
178 impl Graph for Stub {
187 impl Graph for Stub {
179 fn parents(&self, r: Revision) -> Result<[Revision; 2], GraphError> {
188 fn parents(&self, r: Revision) -> Result<[Revision; 2], GraphError> {
180 match r {
189 match r {
181 25 => Err(GraphError::ParentOutOfRange(25)),
190 25 => Err(GraphError::ParentOutOfRange(25)),
182 _ => Ok([1, 2]),
191 _ => Ok([1, 2]),
183 }
192 }
184 }
193 }
185 }
194 }
186
195
187 /// Helper for test_init_next()
196 /// Helper for test_init_next()
188 fn stub_raw_init(
197 fn stub_raw_init(
189 initrevslen: usize,
198 initrevslen: usize,
190 initrevs: usize,
199 initrevs: usize,
191 stoprev: c_long,
200 stoprev: c_long,
192 inclusive: c_int,
201 inclusive: c_int,
193 ) -> usize {
202 ) -> usize {
194 unsafe {
203 unsafe {
195 raw_init(
204 raw_init(
196 Stub,
205 Stub,
197 initrevslen,
206 initrevslen,
198 initrevs as *mut c_long,
207 initrevs as *mut c_long,
199 stoprev,
208 stoprev,
200 inclusive,
209 inclusive,
201 ) as usize
210 ) as usize
202 }
211 }
203 }
212 }
204
213
205 fn stub_raw_init_from_vec(
214 fn stub_raw_init_from_vec(
206 mut initrevs: Vec<c_long>,
215 mut initrevs: Vec<c_long>,
207 stoprev: c_long,
216 stoprev: c_long,
208 inclusive: c_int,
217 inclusive: c_int,
209 ) -> *mut AncestorsIterator<Stub> {
218 ) -> *mut AncestorsIterator<Stub> {
210 unsafe {
219 unsafe {
211 raw_init(
220 raw_init(
212 Stub,
221 Stub,
213 initrevs.len(),
222 initrevs.len(),
214 initrevs.as_mut_ptr(),
223 initrevs.as_mut_ptr(),
215 stoprev,
224 stoprev,
216 inclusive,
225 inclusive,
217 )
226 )
218 }
227 }
219 }
228 }
220
229
221 #[test]
230 #[test]
222 // Test what happens when we init an Iterator as with the exposed C ABI
231 // Test what happens when we init an Iterator as with the exposed C ABI
223 // and try to use it afterwards
232 // and try to use it afterwards
224 // We spawn new threads, in order to make memory consistency harder
233 // We spawn new threads, in order to make memory consistency harder
225 // but this forces us to convert the pointers into shareable usizes.
234 // but this forces us to convert the pointers into shareable usizes.
226 fn test_init_next() {
235 fn test_init_next() {
227 let mut initrevs: Vec<c_long> = vec![11, 13];
236 let mut initrevs: Vec<c_long> = vec![11, 13];
228 let initrevs_len = initrevs.len();
237 let initrevs_len = initrevs.len();
229 let initrevs_ptr = initrevs.as_mut_ptr() as usize;
238 let initrevs_ptr = initrevs.as_mut_ptr() as usize;
230 let handler = thread::spawn(move || stub_raw_init(initrevs_len, initrevs_ptr, 0, 1));
239 let handler = thread::spawn(move || {
240 stub_raw_init(initrevs_len, initrevs_ptr, 0, 1)
241 });
231 let raw = handler.join().unwrap() as *mut AncestorsIterator<Stub>;
242 let raw = handler.join().unwrap() as *mut AncestorsIterator<Stub>;
232
243
233 assert_eq!(raw_next(raw), 13);
244 assert_eq!(raw_next(raw), 13);
234 assert_eq!(raw_next(raw), 11);
245 assert_eq!(raw_next(raw), 11);
235 assert_eq!(raw_next(raw), 2);
246 assert_eq!(raw_next(raw), 2);
236 assert_eq!(raw_next(raw), 1);
247 assert_eq!(raw_next(raw), 1);
237 assert_eq!(raw_next(raw), NULL_REVISION as c_long);
248 assert_eq!(raw_next(raw), NULL_REVISION as c_long);
238 raw_drop(raw);
249 raw_drop(raw);
239 }
250 }
240
251
241 #[test]
252 #[test]
242 fn test_init_wrong_bool() {
253 fn test_init_wrong_bool() {
243 assert_eq!(stub_raw_init_from_vec(vec![11, 13], 0, 2), null_mut());
254 assert_eq!(stub_raw_init_from_vec(vec![11, 13], 0, 2), null_mut());
244 }
255 }
245
256
246 #[test]
257 #[test]
247 fn test_empty() {
258 fn test_empty() {
248 let raw = stub_raw_init_from_vec(vec![], 0, 1);
259 let raw = stub_raw_init_from_vec(vec![], 0, 1);
249 assert_eq!(raw_next(raw), NULL_REVISION as c_long);
260 assert_eq!(raw_next(raw), NULL_REVISION as c_long);
250 raw_drop(raw);
261 raw_drop(raw);
251 }
262 }
252
263
253 #[test]
264 #[test]
254 fn test_init_err_out_of_range() {
265 fn test_init_err_out_of_range() {
255 assert!(stub_raw_init_from_vec(vec![25], 0, 0).is_null());
266 assert!(stub_raw_init_from_vec(vec![25], 0, 0).is_null());
256 }
267 }
257
268
258 #[test]
269 #[test]
259 fn test_contains() {
270 fn test_contains() {
260 let raw = stub_raw_init_from_vec(vec![5, 6], 0, 1);
271 let raw = stub_raw_init_from_vec(vec![5, 6], 0, 1);
261 assert_eq!(raw_contains(raw, 5), 1);
272 assert_eq!(raw_contains(raw, 5), 1);
262 assert_eq!(raw_contains(raw, 2), 1);
273 assert_eq!(raw_contains(raw, 2), 1);
263 }
274 }
264
275
265 #[test]
276 #[test]
266 fn test_contains_exclusive() {
277 fn test_contains_exclusive() {
267 let raw = stub_raw_init_from_vec(vec![5, 6], 0, 0);
278 let raw = stub_raw_init_from_vec(vec![5, 6], 0, 0);
268 assert_eq!(raw_contains(raw, 5), 0);
279 assert_eq!(raw_contains(raw, 5), 0);
269 assert_eq!(raw_contains(raw, 2), 1);
280 assert_eq!(raw_contains(raw, 2), 1);
270 }
281 }
271 }
282 }
General Comments 0
You need to be logged in to leave comments. Login now