##// END OF EJS Templates
rust-cpython: store leaked reference to PySharedState in $leaked struct...
Yuya Nishihara -
r43446:aaec70a5 default
parent child Browse files
Show More
@@ -1,415 +1,430 b''
1 // ref_sharing.rs
1 // ref_sharing.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 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to
6 // of this software and associated documentation files (the "Software"), to
7 // deal in the Software without restriction, including without limitation the
7 // deal in the Software without restriction, including without limitation the
8 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 // sell copies of the Software, and to permit persons to whom the Software is
9 // sell copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
10 // furnished to do so, subject to the following conditions:
11 //
11 //
12 // The above copyright notice and this permission notice shall be included in
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
13 // all copies or substantial portions of the Software.
14 //
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 // IN THE SOFTWARE.
21 // IN THE SOFTWARE.
22
22
23 //! Macros for use in the `hg-cpython` bridge library.
23 //! Macros for use in the `hg-cpython` bridge library.
24
24
25 use crate::exceptions::AlreadyBorrowed;
25 use crate::exceptions::AlreadyBorrowed;
26 use cpython::{PyResult, Python};
26 use cpython::{PyResult, Python};
27 use std::cell::{Cell, Ref, RefCell, RefMut};
27 use std::cell::{Cell, Ref, RefCell, RefMut};
28
28
29 /// Manages the shared state between Python and Rust
29 /// Manages the shared state between Python and Rust
30 #[derive(Debug, Default)]
30 #[derive(Debug, Default)]
31 pub struct PySharedState {
31 pub struct PySharedState {
32 leak_count: Cell<usize>,
32 leak_count: Cell<usize>,
33 mutably_borrowed: Cell<bool>,
33 mutably_borrowed: Cell<bool>,
34 }
34 }
35
35
36 // &PySharedState can be Send because any access to inner cells is
36 // &PySharedState can be Send because any access to inner cells is
37 // synchronized by the GIL.
37 // synchronized by the GIL.
38 unsafe impl Sync for PySharedState {}
38 unsafe impl Sync for PySharedState {}
39
39
40 impl PySharedState {
40 impl PySharedState {
41 pub fn borrow_mut<'a, T>(
41 pub fn borrow_mut<'a, T>(
42 &'a self,
42 &'a self,
43 py: Python<'a>,
43 py: Python<'a>,
44 pyrefmut: RefMut<'a, T>,
44 pyrefmut: RefMut<'a, T>,
45 ) -> PyResult<PyRefMut<'a, T>> {
45 ) -> PyResult<PyRefMut<'a, T>> {
46 if self.mutably_borrowed.get() {
46 if self.mutably_borrowed.get() {
47 return Err(AlreadyBorrowed::new(
47 return Err(AlreadyBorrowed::new(
48 py,
48 py,
49 "Cannot borrow mutably while there exists another \
49 "Cannot borrow mutably while there exists another \
50 mutable reference in a Python object",
50 mutable reference in a Python object",
51 ));
51 ));
52 }
52 }
53 match self.leak_count.get() {
53 match self.leak_count.get() {
54 0 => {
54 0 => {
55 self.mutably_borrowed.replace(true);
55 self.mutably_borrowed.replace(true);
56 Ok(PyRefMut::new(py, pyrefmut, self))
56 Ok(PyRefMut::new(py, pyrefmut, self))
57 }
57 }
58 // TODO
58 // TODO
59 // For now, this works differently than Python references
59 // For now, this works differently than Python references
60 // in the case of iterators.
60 // in the case of iterators.
61 // Python does not complain when the data an iterator
61 // Python does not complain when the data an iterator
62 // points to is modified if the iterator is never used
62 // points to is modified if the iterator is never used
63 // afterwards.
63 // afterwards.
64 // Here, we are stricter than this by refusing to give a
64 // Here, we are stricter than this by refusing to give a
65 // mutable reference if it is already borrowed.
65 // mutable reference if it is already borrowed.
66 // While the additional safety might be argued for, it
66 // While the additional safety might be argued for, it
67 // breaks valid programming patterns in Python and we need
67 // breaks valid programming patterns in Python and we need
68 // to fix this issue down the line.
68 // to fix this issue down the line.
69 _ => Err(AlreadyBorrowed::new(
69 _ => Err(AlreadyBorrowed::new(
70 py,
70 py,
71 "Cannot borrow mutably while there are \
71 "Cannot borrow mutably while there are \
72 immutable references in Python objects",
72 immutable references in Python objects",
73 )),
73 )),
74 }
74 }
75 }
75 }
76
76
77 /// Return a reference to the wrapped data with an artificial static
77 /// Return a reference to the wrapped data and its state with an
78 /// lifetime.
78 /// artificial static lifetime.
79 /// We need to be protected by the GIL for thread-safety.
79 /// We need to be protected by the GIL for thread-safety.
80 ///
80 ///
81 /// # Safety
81 /// # Safety
82 ///
82 ///
83 /// This is highly unsafe since the lifetime of the given data can be
83 /// This is highly unsafe since the lifetime of the given data can be
84 /// extended. Do not call this function directly.
84 /// extended. Do not call this function directly.
85 pub unsafe fn leak_immutable<T>(
85 pub unsafe fn leak_immutable<T>(
86 &self,
86 &self,
87 py: Python,
87 py: Python,
88 data: &PySharedRefCell<T>,
88 data: &PySharedRefCell<T>,
89 ) -> PyResult<&'static T> {
89 ) -> PyResult<(&'static T, &'static PySharedState)> {
90 if self.mutably_borrowed.get() {
90 if self.mutably_borrowed.get() {
91 return Err(AlreadyBorrowed::new(
91 return Err(AlreadyBorrowed::new(
92 py,
92 py,
93 "Cannot borrow immutably while there is a \
93 "Cannot borrow immutably while there is a \
94 mutable reference in Python objects",
94 mutable reference in Python objects",
95 ));
95 ));
96 }
96 }
97 // TODO: it's weird that self is data.py_shared_state. Maybe we
98 // can move stuff to PySharedRefCell?
97 let ptr = data.as_ptr();
99 let ptr = data.as_ptr();
100 let state_ptr: *const PySharedState = &data.py_shared_state;
98 self.leak_count.replace(self.leak_count.get() + 1);
101 self.leak_count.replace(self.leak_count.get() + 1);
99 Ok(&*ptr)
102 Ok((&*ptr, &*state_ptr))
100 }
103 }
101
104
102 /// # Safety
105 /// # Safety
103 ///
106 ///
104 /// It's unsafe to update the reference count without knowing the
107 /// It's unsafe to update the reference count without knowing the
105 /// reference is deleted. Do not call this function directly.
108 /// reference is deleted. Do not call this function directly.
106 pub unsafe fn decrease_leak_count(&self, _py: Python, mutable: bool) {
109 pub unsafe fn decrease_leak_count(&self, _py: Python, mutable: bool) {
107 if mutable {
110 if mutable {
108 assert_eq!(self.leak_count.get(), 0);
111 assert_eq!(self.leak_count.get(), 0);
109 assert!(self.mutably_borrowed.get());
112 assert!(self.mutably_borrowed.get());
110 self.mutably_borrowed.replace(false);
113 self.mutably_borrowed.replace(false);
111 } else {
114 } else {
112 let count = self.leak_count.get();
115 let count = self.leak_count.get();
113 assert!(count > 0);
116 assert!(count > 0);
114 self.leak_count.replace(count - 1);
117 self.leak_count.replace(count - 1);
115 }
118 }
116 }
119 }
117 }
120 }
118
121
119 /// `RefCell` wrapper to be safely used in conjunction with `PySharedState`.
122 /// `RefCell` wrapper to be safely used in conjunction with `PySharedState`.
120 ///
123 ///
121 /// Only immutable operation is allowed through this interface.
124 /// Only immutable operation is allowed through this interface.
122 #[derive(Debug)]
125 #[derive(Debug)]
123 pub struct PySharedRefCell<T> {
126 pub struct PySharedRefCell<T> {
124 inner: RefCell<T>,
127 inner: RefCell<T>,
125 pub py_shared_state: PySharedState, // TODO: remove pub
128 pub py_shared_state: PySharedState, // TODO: remove pub
126 }
129 }
127
130
128 impl<T> PySharedRefCell<T> {
131 impl<T> PySharedRefCell<T> {
129 pub fn new(value: T) -> PySharedRefCell<T> {
132 pub fn new(value: T) -> PySharedRefCell<T> {
130 Self {
133 Self {
131 inner: RefCell::new(value),
134 inner: RefCell::new(value),
132 py_shared_state: PySharedState::default(),
135 py_shared_state: PySharedState::default(),
133 }
136 }
134 }
137 }
135
138
136 pub fn borrow(&self) -> Ref<T> {
139 pub fn borrow(&self) -> Ref<T> {
137 // py_shared_state isn't involved since
140 // py_shared_state isn't involved since
138 // - inner.borrow() would fail if self is mutably borrowed,
141 // - inner.borrow() would fail if self is mutably borrowed,
139 // - and inner.borrow_mut() would fail while self is borrowed.
142 // - and inner.borrow_mut() would fail while self is borrowed.
140 self.inner.borrow()
143 self.inner.borrow()
141 }
144 }
142
145
143 pub fn as_ptr(&self) -> *mut T {
146 pub fn as_ptr(&self) -> *mut T {
144 self.inner.as_ptr()
147 self.inner.as_ptr()
145 }
148 }
146
149
147 // TODO: maybe this should be named as try_borrow_mut(), and use
150 // TODO: maybe this should be named as try_borrow_mut(), and use
148 // inner.try_borrow_mut(). The current implementation panics if
151 // inner.try_borrow_mut(). The current implementation panics if
149 // self.inner has been borrowed, but returns error if py_shared_state
152 // self.inner has been borrowed, but returns error if py_shared_state
150 // refuses to borrow.
153 // refuses to borrow.
151 pub fn borrow_mut<'a>(
154 pub fn borrow_mut<'a>(
152 &'a self,
155 &'a self,
153 py: Python<'a>,
156 py: Python<'a>,
154 ) -> PyResult<PyRefMut<'a, T>> {
157 ) -> PyResult<PyRefMut<'a, T>> {
155 self.py_shared_state.borrow_mut(py, self.inner.borrow_mut())
158 self.py_shared_state.borrow_mut(py, self.inner.borrow_mut())
156 }
159 }
157 }
160 }
158
161
159 /// Holds a mutable reference to data shared between Python and Rust.
162 /// Holds a mutable reference to data shared between Python and Rust.
160 pub struct PyRefMut<'a, T> {
163 pub struct PyRefMut<'a, T> {
161 inner: RefMut<'a, T>,
164 inner: RefMut<'a, T>,
162 py_shared_state: &'a PySharedState,
165 py_shared_state: &'a PySharedState,
163 }
166 }
164
167
165 impl<'a, T> PyRefMut<'a, T> {
168 impl<'a, T> PyRefMut<'a, T> {
166 // Must be constructed by PySharedState after checking its leak_count.
169 // Must be constructed by PySharedState after checking its leak_count.
167 // Otherwise, drop() would incorrectly update the state.
170 // Otherwise, drop() would incorrectly update the state.
168 fn new(
171 fn new(
169 _py: Python<'a>,
172 _py: Python<'a>,
170 inner: RefMut<'a, T>,
173 inner: RefMut<'a, T>,
171 py_shared_state: &'a PySharedState,
174 py_shared_state: &'a PySharedState,
172 ) -> Self {
175 ) -> Self {
173 Self {
176 Self {
174 inner,
177 inner,
175 py_shared_state,
178 py_shared_state,
176 }
179 }
177 }
180 }
178 }
181 }
179
182
180 impl<'a, T> std::ops::Deref for PyRefMut<'a, T> {
183 impl<'a, T> std::ops::Deref for PyRefMut<'a, T> {
181 type Target = RefMut<'a, T>;
184 type Target = RefMut<'a, T>;
182
185
183 fn deref(&self) -> &Self::Target {
186 fn deref(&self) -> &Self::Target {
184 &self.inner
187 &self.inner
185 }
188 }
186 }
189 }
187 impl<'a, T> std::ops::DerefMut for PyRefMut<'a, T> {
190 impl<'a, T> std::ops::DerefMut for PyRefMut<'a, T> {
188 fn deref_mut(&mut self) -> &mut Self::Target {
191 fn deref_mut(&mut self) -> &mut Self::Target {
189 &mut self.inner
192 &mut self.inner
190 }
193 }
191 }
194 }
192
195
193 impl<'a, T> Drop for PyRefMut<'a, T> {
196 impl<'a, T> Drop for PyRefMut<'a, T> {
194 fn drop(&mut self) {
197 fn drop(&mut self) {
195 let gil = Python::acquire_gil();
198 let gil = Python::acquire_gil();
196 let py = gil.python();
199 let py = gil.python();
197 unsafe {
200 unsafe {
198 self.py_shared_state.decrease_leak_count(py, true);
201 self.py_shared_state.decrease_leak_count(py, true);
199 }
202 }
200 }
203 }
201 }
204 }
202
205
203 /// Allows a `py_class!` generated struct to share references to one of its
206 /// Allows a `py_class!` generated struct to share references to one of its
204 /// data members with Python.
207 /// data members with Python.
205 ///
208 ///
206 /// # Warning
209 /// # Warning
207 ///
210 ///
208 /// TODO allow Python container types: for now, integration with the garbage
211 /// TODO allow Python container types: for now, integration with the garbage
209 /// collector does not extend to Rust structs holding references to Python
212 /// collector does not extend to Rust structs holding references to Python
210 /// objects. Should the need surface, `__traverse__` and `__clear__` will
213 /// objects. Should the need surface, `__traverse__` and `__clear__` will
211 /// need to be written as per the `rust-cpython` docs on GC integration.
214 /// need to be written as per the `rust-cpython` docs on GC integration.
212 ///
215 ///
213 /// # Parameters
216 /// # Parameters
214 ///
217 ///
215 /// * `$name` is the same identifier used in for `py_class!` macro call.
218 /// * `$name` is the same identifier used in for `py_class!` macro call.
216 /// * `$inner_struct` is the identifier of the underlying Rust struct
219 /// * `$inner_struct` is the identifier of the underlying Rust struct
217 /// * `$data_member` is the identifier of the data member of `$inner_struct`
220 /// * `$data_member` is the identifier of the data member of `$inner_struct`
218 /// that will be shared.
221 /// that will be shared.
219 /// * `$leaked` is the identifier to give to the struct that will manage
222 /// * `$leaked` is the identifier to give to the struct that will manage
220 /// references to `$name`, to be used for example in other macros like
223 /// references to `$name`, to be used for example in other macros like
221 /// `py_shared_iterator`.
224 /// `py_shared_iterator`.
222 ///
225 ///
223 /// # Example
226 /// # Example
224 ///
227 ///
225 /// ```
228 /// ```
226 /// struct MyStruct {
229 /// struct MyStruct {
227 /// inner: Vec<u32>;
230 /// inner: Vec<u32>;
228 /// }
231 /// }
229 ///
232 ///
230 /// py_class!(pub class MyType |py| {
233 /// py_class!(pub class MyType |py| {
231 /// data inner: PySharedRefCell<MyStruct>;
234 /// data inner: PySharedRefCell<MyStruct>;
232 /// });
235 /// });
233 ///
236 ///
234 /// py_shared_ref!(MyType, MyStruct, inner, MyTypeLeakedRef);
237 /// py_shared_ref!(MyType, MyStruct, inner, MyTypeLeakedRef);
235 /// ```
238 /// ```
236 macro_rules! py_shared_ref {
239 macro_rules! py_shared_ref {
237 (
240 (
238 $name: ident,
241 $name: ident,
239 $inner_struct: ident,
242 $inner_struct: ident,
240 $data_member: ident,
243 $data_member: ident,
241 $leaked: ident,
244 $leaked: ident,
242 ) => {
245 ) => {
243 impl $name {
246 impl $name {
244 // TODO: remove this function in favor of inner(py).borrow_mut()
247 // TODO: remove this function in favor of inner(py).borrow_mut()
245 fn borrow_mut<'a>(
248 fn borrow_mut<'a>(
246 &'a self,
249 &'a self,
247 py: Python<'a>,
250 py: Python<'a>,
248 ) -> PyResult<crate::ref_sharing::PyRefMut<'a, $inner_struct>>
251 ) -> PyResult<crate::ref_sharing::PyRefMut<'a, $inner_struct>>
249 {
252 {
250 // assert $data_member type
253 // assert $data_member type
251 use crate::ref_sharing::PySharedRefCell;
254 use crate::ref_sharing::PySharedRefCell;
252 let data: &PySharedRefCell<_> = self.$data_member(py);
255 let data: &PySharedRefCell<_> = self.$data_member(py);
253 data.borrow_mut(py)
256 data.borrow_mut(py)
254 }
257 }
255
258
256 /// Returns a leaked reference and its management object.
259 /// Returns a leaked reference and its management object.
257 ///
260 ///
258 /// # Safety
261 /// # Safety
259 ///
262 ///
260 /// It's up to you to make sure that the management object lives
263 /// It's up to you to make sure that the management object lives
261 /// longer than the leaked reference. Otherwise, you'll get a
264 /// longer than the leaked reference. Otherwise, you'll get a
262 /// dangling reference.
265 /// dangling reference.
263 unsafe fn leak_immutable<'a>(
266 unsafe fn leak_immutable<'a>(
264 &'a self,
267 &'a self,
265 py: Python<'a>,
268 py: Python<'a>,
266 ) -> PyResult<($leaked, &'static $inner_struct)> {
269 ) -> PyResult<($leaked, &'static $inner_struct)> {
267 // assert $data_member type
270 // assert $data_member type
268 use crate::ref_sharing::PySharedRefCell;
271 use crate::ref_sharing::PySharedRefCell;
269 let data: &PySharedRefCell<_> = self.$data_member(py);
272 let data: &PySharedRefCell<_> = self.$data_member(py);
270 let static_ref =
273 let (static_ref, static_state_ref) =
271 data.py_shared_state.leak_immutable(py, data)?;
274 data.py_shared_state.leak_immutable(py, data)?;
272 let leak_handle = $leaked::new(py, self);
275 let leak_handle = $leaked::new(py, self, static_state_ref);
273 Ok((leak_handle, static_ref))
276 Ok((leak_handle, static_ref))
274 }
277 }
275 }
278 }
276
279
277 /// Manage immutable references to `$name` leaked into Python
280 /// Manage immutable references to `$name` leaked into Python
278 /// iterators.
281 /// iterators.
279 ///
282 ///
280 /// In truth, this does not represent leaked references themselves;
283 /// In truth, this does not represent leaked references themselves;
281 /// it is instead useful alongside them to manage them.
284 /// it is instead useful alongside them to manage them.
282 pub struct $leaked {
285 pub struct $leaked {
283 inner: $name,
286 _inner: $name,
287 py_shared_state: &'static crate::ref_sharing::PySharedState,
284 }
288 }
285
289
286 impl $leaked {
290 impl $leaked {
291 /// # Safety
292 ///
293 /// The `py_shared_state` must be owned by the `inner` Python
294 /// object.
287 // Marked as unsafe so client code wouldn't construct $leaked
295 // Marked as unsafe so client code wouldn't construct $leaked
288 // struct by mistake. Its drop() is unsafe.
296 // struct by mistake. Its drop() is unsafe.
289 unsafe fn new(py: Python, inner: &$name) -> Self {
297 unsafe fn new(
298 py: Python,
299 inner: &$name,
300 py_shared_state: &'static crate::ref_sharing::PySharedState,
301 ) -> Self {
290 Self {
302 Self {
291 inner: inner.clone_ref(py),
303 _inner: inner.clone_ref(py),
304 py_shared_state,
292 }
305 }
293 }
306 }
294 }
307 }
295
308
296 impl Drop for $leaked {
309 impl Drop for $leaked {
297 fn drop(&mut self) {
310 fn drop(&mut self) {
311 // py_shared_state should be alive since we do have
312 // a Python reference to the owner object. Taking GIL makes
313 // sure that the state is only accessed by this thread.
298 let gil = Python::acquire_gil();
314 let gil = Python::acquire_gil();
299 let py = gil.python();
315 let py = gil.python();
300 let state = &self.inner.$data_member(py).py_shared_state;
301 unsafe {
316 unsafe {
302 state.decrease_leak_count(py, false);
317 self.py_shared_state.decrease_leak_count(py, false);
303 }
318 }
304 }
319 }
305 }
320 }
306 };
321 };
307 }
322 }
308
323
309 /// Defines a `py_class!` that acts as a Python iterator over a Rust iterator.
324 /// Defines a `py_class!` that acts as a Python iterator over a Rust iterator.
310 ///
325 ///
311 /// TODO: this is a bit awkward to use, and a better (more complicated)
326 /// TODO: this is a bit awkward to use, and a better (more complicated)
312 /// procedural macro would simplify the interface a lot.
327 /// procedural macro would simplify the interface a lot.
313 ///
328 ///
314 /// # Parameters
329 /// # Parameters
315 ///
330 ///
316 /// * `$name` is the identifier to give to the resulting Rust struct.
331 /// * `$name` is the identifier to give to the resulting Rust struct.
317 /// * `$leaked` corresponds to `$leaked` in the matching `py_shared_ref!` call.
332 /// * `$leaked` corresponds to `$leaked` in the matching `py_shared_ref!` call.
318 /// * `$iterator_type` is the type of the Rust iterator.
333 /// * `$iterator_type` is the type of the Rust iterator.
319 /// * `$success_func` is a function for processing the Rust `(key, value)`
334 /// * `$success_func` is a function for processing the Rust `(key, value)`
320 /// tuple on iteration success, turning it into something Python understands.
335 /// tuple on iteration success, turning it into something Python understands.
321 /// * `$success_func` is the return type of `$success_func`
336 /// * `$success_func` is the return type of `$success_func`
322 ///
337 ///
323 /// # Example
338 /// # Example
324 ///
339 ///
325 /// ```
340 /// ```
326 /// struct MyStruct {
341 /// struct MyStruct {
327 /// inner: HashMap<Vec<u8>, Vec<u8>>;
342 /// inner: HashMap<Vec<u8>, Vec<u8>>;
328 /// }
343 /// }
329 ///
344 ///
330 /// py_class!(pub class MyType |py| {
345 /// py_class!(pub class MyType |py| {
331 /// data inner: PySharedRefCell<MyStruct>;
346 /// data inner: PySharedRefCell<MyStruct>;
332 ///
347 ///
333 /// def __iter__(&self) -> PyResult<MyTypeItemsIterator> {
348 /// def __iter__(&self) -> PyResult<MyTypeItemsIterator> {
334 /// let (leak_handle, leaked_ref) = unsafe { self.leak_immutable(py)? };
349 /// let (leak_handle, leaked_ref) = unsafe { self.leak_immutable(py)? };
335 /// MyTypeItemsIterator::from_inner(
350 /// MyTypeItemsIterator::from_inner(
336 /// py,
351 /// py,
337 /// leak_handle,
352 /// leak_handle,
338 /// leaked_ref.iter(),
353 /// leaked_ref.iter(),
339 /// )
354 /// )
340 /// }
355 /// }
341 /// });
356 /// });
342 ///
357 ///
343 /// impl MyType {
358 /// impl MyType {
344 /// fn translate_key_value(
359 /// fn translate_key_value(
345 /// py: Python,
360 /// py: Python,
346 /// res: (&Vec<u8>, &Vec<u8>),
361 /// res: (&Vec<u8>, &Vec<u8>),
347 /// ) -> PyResult<Option<(PyBytes, PyBytes)>> {
362 /// ) -> PyResult<Option<(PyBytes, PyBytes)>> {
348 /// let (f, entry) = res;
363 /// let (f, entry) = res;
349 /// Ok(Some((
364 /// Ok(Some((
350 /// PyBytes::new(py, f),
365 /// PyBytes::new(py, f),
351 /// PyBytes::new(py, entry),
366 /// PyBytes::new(py, entry),
352 /// )))
367 /// )))
353 /// }
368 /// }
354 /// }
369 /// }
355 ///
370 ///
356 /// py_shared_ref!(MyType, MyStruct, inner, MyTypeLeakedRef);
371 /// py_shared_ref!(MyType, MyStruct, inner, MyTypeLeakedRef);
357 ///
372 ///
358 /// py_shared_iterator!(
373 /// py_shared_iterator!(
359 /// MyTypeItemsIterator,
374 /// MyTypeItemsIterator,
360 /// MyTypeLeakedRef,
375 /// MyTypeLeakedRef,
361 /// HashMap<'static, Vec<u8>, Vec<u8>>,
376 /// HashMap<'static, Vec<u8>, Vec<u8>>,
362 /// MyType::translate_key_value,
377 /// MyType::translate_key_value,
363 /// Option<(PyBytes, PyBytes)>
378 /// Option<(PyBytes, PyBytes)>
364 /// );
379 /// );
365 /// ```
380 /// ```
366 macro_rules! py_shared_iterator {
381 macro_rules! py_shared_iterator {
367 (
382 (
368 $name: ident,
383 $name: ident,
369 $leaked: ident,
384 $leaked: ident,
370 $iterator_type: ty,
385 $iterator_type: ty,
371 $success_func: expr,
386 $success_func: expr,
372 $success_type: ty
387 $success_type: ty
373 ) => {
388 ) => {
374 py_class!(pub class $name |py| {
389 py_class!(pub class $name |py| {
375 data inner: RefCell<Option<$leaked>>;
390 data inner: RefCell<Option<$leaked>>;
376 data it: RefCell<$iterator_type>;
391 data it: RefCell<$iterator_type>;
377
392
378 def __next__(&self) -> PyResult<$success_type> {
393 def __next__(&self) -> PyResult<$success_type> {
379 let mut inner_opt = self.inner(py).borrow_mut();
394 let mut inner_opt = self.inner(py).borrow_mut();
380 if inner_opt.is_some() {
395 if inner_opt.is_some() {
381 match self.it(py).borrow_mut().next() {
396 match self.it(py).borrow_mut().next() {
382 None => {
397 None => {
383 // replace Some(inner) by None, drop $leaked
398 // replace Some(inner) by None, drop $leaked
384 inner_opt.take();
399 inner_opt.take();
385 Ok(None)
400 Ok(None)
386 }
401 }
387 Some(res) => {
402 Some(res) => {
388 $success_func(py, res)
403 $success_func(py, res)
389 }
404 }
390 }
405 }
391 } else {
406 } else {
392 Ok(None)
407 Ok(None)
393 }
408 }
394 }
409 }
395
410
396 def __iter__(&self) -> PyResult<Self> {
411 def __iter__(&self) -> PyResult<Self> {
397 Ok(self.clone_ref(py))
412 Ok(self.clone_ref(py))
398 }
413 }
399 });
414 });
400
415
401 impl $name {
416 impl $name {
402 pub fn from_inner(
417 pub fn from_inner(
403 py: Python,
418 py: Python,
404 leaked: $leaked,
419 leaked: $leaked,
405 it: $iterator_type
420 it: $iterator_type
406 ) -> PyResult<Self> {
421 ) -> PyResult<Self> {
407 Self::create_instance(
422 Self::create_instance(
408 py,
423 py,
409 RefCell::new(Some(leaked)),
424 RefCell::new(Some(leaked)),
410 RefCell::new(it)
425 RefCell::new(it)
411 )
426 )
412 }
427 }
413 }
428 }
414 };
429 };
415 }
430 }
General Comments 0
You need to be logged in to leave comments. Login now