Show More
@@ -0,0 +1,12 | |||
|
1 | [package] | |
|
2 | name = "hgdirectffi" | |
|
3 | version = "0.1.0" | |
|
4 | authors = ["Georges Racinet <gracinet@anybox.fr>"] | |
|
5 | description = "Low level Python bindings for hg-core, going through existing C extensions" | |
|
6 | ||
|
7 | [dependencies] | |
|
8 | libc = "*" | |
|
9 | hg-core = { path = "../hg-core" } | |
|
10 | ||
|
11 | [lib] | |
|
12 | crate-type = ["staticlib"] |
@@ -0,0 +1,229 | |||
|
1 | // Copyright 2018 Georges Racinet <gracinet@anybox.fr> | |
|
2 | // | |
|
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. | |
|
5 | ||
|
6 | //! Bindings for CPython extension code | |
|
7 | //! | |
|
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 | |
|
10 | //! from the caller at instantiation. | |
|
11 | ||
|
12 | use hg::AncestorsIterator; | |
|
13 | use hg::{Graph, GraphError, Revision, NULL_REVISION}; | |
|
14 | use libc::{c_int, c_long, c_void, ssize_t}; | |
|
15 | use std::ptr::null_mut; | |
|
16 | use std::slice; | |
|
17 | ||
|
18 | type IndexPtr = *mut c_void; | |
|
19 | type IndexParentsFn = | |
|
20 | unsafe extern "C" fn(index: IndexPtr, rev: ssize_t, ps: *mut [c_int; 2], max_rev: c_int) | |
|
21 | -> c_int; | |
|
22 | ||
|
23 | /// A Graph backed up by objects and functions from revlog.c | |
|
24 | /// | |
|
25 | /// This implementation of the Graph trait, relies on (pointers to) | |
|
26 | /// - the C index object (`index` member) | |
|
27 | /// - the `index_get_parents()` function (`parents` member) | |
|
28 | pub struct Index { | |
|
29 | index: IndexPtr, | |
|
30 | parents: IndexParentsFn, | |
|
31 | } | |
|
32 | ||
|
33 | impl Index { | |
|
34 | pub fn new(index: IndexPtr, parents: IndexParentsFn) -> Self { | |
|
35 | Index { | |
|
36 | index: index, | |
|
37 | parents: parents, | |
|
38 | } | |
|
39 | } | |
|
40 | } | |
|
41 | ||
|
42 | impl Graph for Index { | |
|
43 | /// wrap a call to the C extern parents function | |
|
44 | fn parents(&self, rev: Revision) -> Result<(Revision, Revision), GraphError> { | |
|
45 | let mut res: [c_int; 2] = [0; 2]; | |
|
46 | let code = | |
|
47 | unsafe { (self.parents)(self.index, rev as ssize_t, &mut res as *mut [c_int; 2], rev) }; | |
|
48 | match code { | |
|
49 | 0 => Ok((res[0], res[1])), | |
|
50 | _ => Err(GraphError::ParentOutOfRange(rev)), | |
|
51 | } | |
|
52 | } | |
|
53 | } | |
|
54 | ||
|
55 | /// Wrapping of AncestorsIterator<Index> constructor, for C callers. | |
|
56 | /// | |
|
57 | /// Besides `initrevs`, `stoprev` and `inclusive`, that are converted | |
|
58 | /// we receive the index and the parents function as pointers | |
|
59 | #[no_mangle] | |
|
60 | pub extern "C" fn rustlazyancestors_init( | |
|
61 | index: IndexPtr, | |
|
62 | parents: IndexParentsFn, | |
|
63 | initrevslen: usize, | |
|
64 | initrevs: *mut c_long, | |
|
65 | stoprev: c_long, | |
|
66 | inclusive: c_int, | |
|
67 | ) -> *mut AncestorsIterator<Index> { | |
|
68 | unsafe { | |
|
69 | raw_init( | |
|
70 | Index::new(index, parents), | |
|
71 | initrevslen, | |
|
72 | initrevs, | |
|
73 | stoprev, | |
|
74 | inclusive, | |
|
75 | ) | |
|
76 | } | |
|
77 | } | |
|
78 | ||
|
79 | /// Testable (for any Graph) version of rustlazyancestors_init | |
|
80 | #[inline] | |
|
81 | unsafe fn raw_init<G: Graph>( | |
|
82 | graph: G, | |
|
83 | initrevslen: usize, | |
|
84 | initrevs: *mut c_long, | |
|
85 | stoprev: c_long, | |
|
86 | inclusive: c_int, | |
|
87 | ) -> *mut AncestorsIterator<G> { | |
|
88 | let inclb = match inclusive { | |
|
89 | 0 => false, | |
|
90 | 1 => true, | |
|
91 | _ => { | |
|
92 | return null_mut(); | |
|
93 | } | |
|
94 | }; | |
|
95 | ||
|
96 | let slice = slice::from_raw_parts(initrevs, initrevslen); | |
|
97 | ||
|
98 | Box::into_raw(Box::new(match AncestorsIterator::new( | |
|
99 | graph, | |
|
100 | slice.into_iter().map(|&r| r as Revision), | |
|
101 | stoprev as Revision, | |
|
102 | inclb, | |
|
103 | ) { | |
|
104 | Ok(it) => it, | |
|
105 | Err(_) => { | |
|
106 | return null_mut(); | |
|
107 | } | |
|
108 | })) | |
|
109 | } | |
|
110 | ||
|
111 | /// Deallocator to be called from C code | |
|
112 | #[no_mangle] | |
|
113 | pub extern "C" fn rustlazyancestors_drop(raw_iter: *mut AncestorsIterator<Index>) { | |
|
114 | raw_drop(raw_iter); | |
|
115 | } | |
|
116 | ||
|
117 | /// Testable (for any Graph) version of rustlazayancestors_drop | |
|
118 | #[inline] | |
|
119 | fn raw_drop<G: Graph>(raw_iter: *mut AncestorsIterator<G>) { | |
|
120 | unsafe { | |
|
121 | Box::from_raw(raw_iter); | |
|
122 | } | |
|
123 | } | |
|
124 | ||
|
125 | /// Iteration main method to be called from C code | |
|
126 | /// | |
|
127 | /// We convert the end of iteration into NULL_REVISION, | |
|
128 | /// it will be up to the C wrapper to convert that back into a Python end of | |
|
129 | /// iteration | |
|
130 | #[no_mangle] | |
|
131 | pub extern "C" fn rustlazyancestors_next(raw: *mut AncestorsIterator<Index>) -> c_long { | |
|
132 | raw_next(raw) | |
|
133 | } | |
|
134 | ||
|
135 | /// Testable (for any Graph) version of rustlazayancestors_next | |
|
136 | #[inline] | |
|
137 | fn raw_next<G: Graph>(raw: *mut AncestorsIterator<G>) -> c_long { | |
|
138 | let as_ref = unsafe { &mut *raw }; | |
|
139 | as_ref.next().unwrap_or(NULL_REVISION) as c_long | |
|
140 | } | |
|
141 | ||
|
142 | #[cfg(test)] | |
|
143 | mod tests { | |
|
144 | use super::*; | |
|
145 | use std::thread; | |
|
146 | ||
|
147 | #[derive(Clone, Debug)] | |
|
148 | struct Stub; | |
|
149 | ||
|
150 | impl Graph for Stub { | |
|
151 | fn parents(&self, r: Revision) -> Result<(Revision, Revision), GraphError> { | |
|
152 | match r { | |
|
153 | 25 => Err(GraphError::ParentOutOfRange(25)), | |
|
154 | _ => Ok((1, 2)), | |
|
155 | } | |
|
156 | } | |
|
157 | } | |
|
158 | ||
|
159 | /// Helper for test_init_next() | |
|
160 | fn stub_raw_init( | |
|
161 | initrevslen: usize, | |
|
162 | initrevs: usize, | |
|
163 | stoprev: c_long, | |
|
164 | inclusive: c_int, | |
|
165 | ) -> usize { | |
|
166 | unsafe { | |
|
167 | raw_init( | |
|
168 | Stub, | |
|
169 | initrevslen, | |
|
170 | initrevs as *mut c_long, | |
|
171 | stoprev, | |
|
172 | inclusive, | |
|
173 | ) as usize | |
|
174 | } | |
|
175 | } | |
|
176 | ||
|
177 | fn stub_raw_init_from_vec( | |
|
178 | mut initrevs: Vec<c_long>, | |
|
179 | stoprev: c_long, | |
|
180 | inclusive: c_int, | |
|
181 | ) -> *mut AncestorsIterator<Stub> { | |
|
182 | unsafe { | |
|
183 | raw_init( | |
|
184 | Stub, | |
|
185 | initrevs.len(), | |
|
186 | initrevs.as_mut_ptr(), | |
|
187 | stoprev, | |
|
188 | inclusive, | |
|
189 | ) | |
|
190 | } | |
|
191 | } | |
|
192 | ||
|
193 | #[test] | |
|
194 | // Test what happens when we init an Iterator as with the exposed C ABI | |
|
195 | // and try to use it afterwards | |
|
196 | // We spawn new threads, in order to make memory consistency harder | |
|
197 | // but this forces us to convert the pointers into shareable usizes. | |
|
198 | fn test_init_next() { | |
|
199 | let mut initrevs: Vec<c_long> = vec![11, 13]; | |
|
200 | let initrevs_len = initrevs.len(); | |
|
201 | let initrevs_ptr = initrevs.as_mut_ptr() as usize; | |
|
202 | let handler = thread::spawn(move || stub_raw_init(initrevs_len, initrevs_ptr, 0, 1)); | |
|
203 | let raw = handler.join().unwrap() as *mut AncestorsIterator<Stub>; | |
|
204 | ||
|
205 | assert_eq!(raw_next(raw), 13); | |
|
206 | assert_eq!(raw_next(raw), 11); | |
|
207 | assert_eq!(raw_next(raw), 2); | |
|
208 | assert_eq!(raw_next(raw), 1); | |
|
209 | assert_eq!(raw_next(raw), NULL_REVISION as c_long); | |
|
210 | raw_drop(raw); | |
|
211 | } | |
|
212 | ||
|
213 | #[test] | |
|
214 | fn test_init_wrong_bool() { | |
|
215 | assert_eq!(stub_raw_init_from_vec(vec![11, 13], 0, 2), null_mut()); | |
|
216 | } | |
|
217 | ||
|
218 | #[test] | |
|
219 | fn test_empty() { | |
|
220 | let raw = stub_raw_init_from_vec(vec![], 0, 1); | |
|
221 | assert_eq!(raw_next(raw), NULL_REVISION as c_long); | |
|
222 | raw_drop(raw); | |
|
223 | } | |
|
224 | ||
|
225 | #[test] | |
|
226 | fn test_init_err_out_of_range() { | |
|
227 | assert!(stub_raw_init_from_vec(vec![25], 0, 0).is_null()); | |
|
228 | } | |
|
229 | } |
@@ -0,0 +1,16 | |||
|
1 | // Copyright 2018 Georges Racinet <gracinet@anybox.fr> | |
|
2 | // | |
|
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. | |
|
5 | ||
|
6 | //! Bindings for CPython extension code | |
|
7 | //! | |
|
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 | |
|
10 | //! from the caller at instantiation. | |
|
11 | ||
|
12 | extern crate hg; | |
|
13 | extern crate libc; | |
|
14 | ||
|
15 | mod ancestors; | |
|
16 | pub use ancestors::{rustlazyancestors_drop, rustlazyancestors_init, rustlazyancestors_next}; |
@@ -1,131 +1,139 | |||
|
1 | 1 | [[package]] |
|
2 | 2 | name = "aho-corasick" |
|
3 | 3 | version = "0.5.3" |
|
4 | 4 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
5 | 5 | dependencies = [ |
|
6 | 6 | "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", |
|
7 | 7 | ] |
|
8 | 8 | |
|
9 | 9 | [[package]] |
|
10 | 10 | name = "cpython" |
|
11 | 11 | version = "0.1.0" |
|
12 | 12 | source = "git+https://github.com/indygreg/rust-cpython.git?rev=c90d65cf84abfffce7ef54476bbfed56017a2f52#c90d65cf84abfffce7ef54476bbfed56017a2f52" |
|
13 | 13 | dependencies = [ |
|
14 | 14 | "libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)", |
|
15 | 15 | "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", |
|
16 | 16 | "python27-sys 0.1.2 (git+https://github.com/indygreg/rust-cpython.git?rev=c90d65cf84abfffce7ef54476bbfed56017a2f52)", |
|
17 | 17 | ] |
|
18 | 18 | |
|
19 | 19 | [[package]] |
|
20 | 20 | name = "hg-core" |
|
21 | 21 | version = "0.1.0" |
|
22 | 22 | |
|
23 | 23 | [[package]] |
|
24 | 24 | name = "hgcli" |
|
25 | 25 | version = "0.1.0" |
|
26 | 26 | dependencies = [ |
|
27 | 27 | "cpython 0.1.0 (git+https://github.com/indygreg/rust-cpython.git?rev=c90d65cf84abfffce7ef54476bbfed56017a2f52)", |
|
28 | 28 | "libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)", |
|
29 | 29 | "python27-sys 0.1.2 (git+https://github.com/indygreg/rust-cpython.git?rev=c90d65cf84abfffce7ef54476bbfed56017a2f52)", |
|
30 | 30 | ] |
|
31 | 31 | |
|
32 | 32 | [[package]] |
|
33 | name = "hgdirectffi" | |
|
34 | version = "0.1.0" | |
|
35 | dependencies = [ | |
|
36 | "hg-core 0.1.0", | |
|
37 | "libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)", | |
|
38 | ] | |
|
39 | ||
|
40 | [[package]] | |
|
33 | 41 | name = "kernel32-sys" |
|
34 | 42 | version = "0.2.2" |
|
35 | 43 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
36 | 44 | dependencies = [ |
|
37 | 45 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", |
|
38 | 46 | "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", |
|
39 | 47 | ] |
|
40 | 48 | |
|
41 | 49 | [[package]] |
|
42 | 50 | name = "libc" |
|
43 | 51 | version = "0.2.35" |
|
44 | 52 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
45 | 53 | |
|
46 | 54 | [[package]] |
|
47 | 55 | name = "memchr" |
|
48 | 56 | version = "0.1.11" |
|
49 | 57 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
50 | 58 | dependencies = [ |
|
51 | 59 | "libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)", |
|
52 | 60 | ] |
|
53 | 61 | |
|
54 | 62 | [[package]] |
|
55 | 63 | name = "num-traits" |
|
56 | 64 | version = "0.1.41" |
|
57 | 65 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
58 | 66 | |
|
59 | 67 | [[package]] |
|
60 | 68 | name = "python27-sys" |
|
61 | 69 | version = "0.1.2" |
|
62 | 70 | source = "git+https://github.com/indygreg/rust-cpython.git?rev=c90d65cf84abfffce7ef54476bbfed56017a2f52#c90d65cf84abfffce7ef54476bbfed56017a2f52" |
|
63 | 71 | dependencies = [ |
|
64 | 72 | "libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)", |
|
65 | 73 | "regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)", |
|
66 | 74 | ] |
|
67 | 75 | |
|
68 | 76 | [[package]] |
|
69 | 77 | name = "regex" |
|
70 | 78 | version = "0.1.80" |
|
71 | 79 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
72 | 80 | dependencies = [ |
|
73 | 81 | "aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", |
|
74 | 82 | "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", |
|
75 | 83 | "regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", |
|
76 | 84 | "thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", |
|
77 | 85 | "utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", |
|
78 | 86 | ] |
|
79 | 87 | |
|
80 | 88 | [[package]] |
|
81 | 89 | name = "regex-syntax" |
|
82 | 90 | version = "0.3.9" |
|
83 | 91 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
84 | 92 | |
|
85 | 93 | [[package]] |
|
86 | 94 | name = "thread-id" |
|
87 | 95 | version = "2.0.0" |
|
88 | 96 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
89 | 97 | dependencies = [ |
|
90 | 98 | "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", |
|
91 | 99 | "libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)", |
|
92 | 100 | ] |
|
93 | 101 | |
|
94 | 102 | [[package]] |
|
95 | 103 | name = "thread_local" |
|
96 | 104 | version = "0.2.7" |
|
97 | 105 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
98 | 106 | dependencies = [ |
|
99 | 107 | "thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", |
|
100 | 108 | ] |
|
101 | 109 | |
|
102 | 110 | [[package]] |
|
103 | 111 | name = "utf8-ranges" |
|
104 | 112 | version = "0.1.3" |
|
105 | 113 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
106 | 114 | |
|
107 | 115 | [[package]] |
|
108 | 116 | name = "winapi" |
|
109 | 117 | version = "0.2.8" |
|
110 | 118 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
111 | 119 | |
|
112 | 120 | [[package]] |
|
113 | 121 | name = "winapi-build" |
|
114 | 122 | version = "0.1.1" |
|
115 | 123 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
116 | 124 | |
|
117 | 125 | [metadata] |
|
118 | 126 | "checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66" |
|
119 | 127 | "checksum cpython 0.1.0 (git+https://github.com/indygreg/rust-cpython.git?rev=c90d65cf84abfffce7ef54476bbfed56017a2f52)" = "<none>" |
|
120 | 128 | "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" |
|
121 | 129 | "checksum libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)" = "96264e9b293e95d25bfcbbf8a88ffd1aedc85b754eba8b7d78012f638ba220eb" |
|
122 | 130 | "checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20" |
|
123 | 131 | "checksum num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cacfcab5eb48250ee7d0c7896b51a2c5eec99c1feea5f32025635f5ae4b00070" |
|
124 | 132 | "checksum python27-sys 0.1.2 (git+https://github.com/indygreg/rust-cpython.git?rev=c90d65cf84abfffce7ef54476bbfed56017a2f52)" = "<none>" |
|
125 | 133 | "checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f" |
|
126 | 134 | "checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957" |
|
127 | 135 | "checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" |
|
128 | 136 | "checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5" |
|
129 | 137 | "checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f" |
|
130 | 138 | "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" |
|
131 | 139 | "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" |
General Comments 0
You need to be logged in to leave comments.
Login now