annotate rust/hg-cpython/src/ref_sharing.rs @ 43286:f8c114f20d2d

rust-cpython: require GIL to borrow immutable reference from PySharedRefCell Since the inner value may be leaked, we probably need GIL to guarantee that there's no data race. inner(py).borrow() is replaced with inner_shared(py).borrow(), which basically means any PySharedRefCell data should be accessed through PySharedRef wrapper.
author Yuya Nishihara <yuya@tcha.org>
date Sat, 21 Sep 2019 17:15:50 +0900
parents ffc1fbd7d1f5
children 0df8312463ae
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
43082
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42939
diff changeset
1 // ref_sharing.rs
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
2 //
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
4 //
43082
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42939
diff changeset
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42939
diff changeset
6 // of this software and associated documentation files (the "Software"), to
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42939
diff changeset
7 // deal in the Software without restriction, including without limitation the
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42939
diff changeset
8 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42939
diff changeset
9 // sell copies of the Software, and to permit persons to whom the Software is
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42939
diff changeset
10 // furnished to do so, subject to the following conditions:
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42939
diff changeset
11 //
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42939
diff changeset
12 // The above copyright notice and this permission notice shall be included in
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42939
diff changeset
13 // all copies or substantial portions of the Software.
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42939
diff changeset
14 //
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42939
diff changeset
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42939
diff changeset
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42939
diff changeset
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42939
diff changeset
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42939
diff changeset
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42939
diff changeset
20 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42939
diff changeset
21 // IN THE SOFTWARE.
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
22
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
23 //! Macros for use in the `hg-cpython` bridge library.
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
24
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
25 use crate::exceptions::AlreadyBorrowed;
43177
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
26 use cpython::{PyClone, PyObject, PyResult, Python};
42849
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
27 use std::cell::{Cell, Ref, RefCell, RefMut};
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
28
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
29 /// Manages the shared state between Python and Rust
43173
070a38737334 rust-cpython: move py_shared_state to PySharedRefCell object
Yuya Nishihara <yuya@tcha.org>
parents: 43082
diff changeset
30 #[derive(Debug, Default)]
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
31 pub struct PySharedState {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
32 leak_count: Cell<usize>,
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
33 mutably_borrowed: Cell<bool>,
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
34 }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
35
43175
a1908eb08342 rust-cpython: mark PySharedState as Sync so &'PySharedState can be Send
Yuya Nishihara <yuya@tcha.org>
parents: 43174
diff changeset
36 // &PySharedState can be Send because any access to inner cells is
a1908eb08342 rust-cpython: mark PySharedState as Sync so &'PySharedState can be Send
Yuya Nishihara <yuya@tcha.org>
parents: 43174
diff changeset
37 // synchronized by the GIL.
a1908eb08342 rust-cpython: mark PySharedState as Sync so &'PySharedState can be Send
Yuya Nishihara <yuya@tcha.org>
parents: 43174
diff changeset
38 unsafe impl Sync for PySharedState {}
a1908eb08342 rust-cpython: mark PySharedState as Sync so &'PySharedState can be Send
Yuya Nishihara <yuya@tcha.org>
parents: 43174
diff changeset
39
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
40 impl PySharedState {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
41 pub fn borrow_mut<'a, T>(
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
42 &'a self,
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
43 py: Python<'a>,
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
44 pyrefmut: RefMut<'a, T>,
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
45 ) -> PyResult<PyRefMut<'a, T>> {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
46 if self.mutably_borrowed.get() {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
47 return Err(AlreadyBorrowed::new(
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
48 py,
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
49 "Cannot borrow mutably while there exists another \
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
50 mutable reference in a Python object",
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
51 ));
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
52 }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
53 match self.leak_count.get() {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
54 0 => {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
55 self.mutably_borrowed.replace(true);
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
56 Ok(PyRefMut::new(py, pyrefmut, self))
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
57 }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
58 // TODO
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
59 // For now, this works differently than Python references
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
60 // in the case of iterators.
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
61 // Python does not complain when the data an iterator
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
62 // points to is modified if the iterator is never used
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
63 // afterwards.
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
64 // Here, we are stricter than this by refusing to give a
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
65 // mutable reference if it is already borrowed.
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
66 // While the additional safety might be argued for, it
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
67 // breaks valid programming patterns in Python and we need
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
68 // to fix this issue down the line.
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
69 _ => Err(AlreadyBorrowed::new(
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
70 py,
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
71 "Cannot borrow mutably while there are \
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
72 immutable references in Python objects",
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
73 )),
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
74 }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
75 }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
76
43176
aaec70a5f9a8 rust-cpython: store leaked reference to PySharedState in $leaked struct
Yuya Nishihara <yuya@tcha.org>
parents: 43175
diff changeset
77 /// Return a reference to the wrapped data and its state with an
aaec70a5f9a8 rust-cpython: store leaked reference to PySharedState in $leaked struct
Yuya Nishihara <yuya@tcha.org>
parents: 43175
diff changeset
78 /// artificial static lifetime.
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
79 /// We need to be protected by the GIL for thread-safety.
42851
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42850
diff changeset
80 ///
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42850
diff changeset
81 /// # Safety
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42850
diff changeset
82 ///
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42850
diff changeset
83 /// This is highly unsafe since the lifetime of the given data can be
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42850
diff changeset
84 /// extended. Do not call this function directly.
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42850
diff changeset
85 pub unsafe fn leak_immutable<T>(
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
86 &self,
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
87 py: Python,
42849
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
88 data: &PySharedRefCell<T>,
43176
aaec70a5f9a8 rust-cpython: store leaked reference to PySharedState in $leaked struct
Yuya Nishihara <yuya@tcha.org>
parents: 43175
diff changeset
89 ) -> PyResult<(&'static T, &'static PySharedState)> {
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
90 if self.mutably_borrowed.get() {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
91 return Err(AlreadyBorrowed::new(
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
92 py,
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
93 "Cannot borrow immutably while there is a \
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
94 mutable reference in Python objects",
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
95 ));
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
96 }
43176
aaec70a5f9a8 rust-cpython: store leaked reference to PySharedState in $leaked struct
Yuya Nishihara <yuya@tcha.org>
parents: 43175
diff changeset
97 // TODO: it's weird that self is data.py_shared_state. Maybe we
aaec70a5f9a8 rust-cpython: store leaked reference to PySharedState in $leaked struct
Yuya Nishihara <yuya@tcha.org>
parents: 43175
diff changeset
98 // can move stuff to PySharedRefCell?
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
99 let ptr = data.as_ptr();
43176
aaec70a5f9a8 rust-cpython: store leaked reference to PySharedState in $leaked struct
Yuya Nishihara <yuya@tcha.org>
parents: 43175
diff changeset
100 let state_ptr: *const PySharedState = &data.py_shared_state;
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
101 self.leak_count.replace(self.leak_count.get() + 1);
43176
aaec70a5f9a8 rust-cpython: store leaked reference to PySharedState in $leaked struct
Yuya Nishihara <yuya@tcha.org>
parents: 43175
diff changeset
102 Ok((&*ptr, &*state_ptr))
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
103 }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
104
42851
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42850
diff changeset
105 /// # Safety
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42850
diff changeset
106 ///
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42850
diff changeset
107 /// It's unsafe to update the reference count without knowing the
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42850
diff changeset
108 /// reference is deleted. Do not call this function directly.
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42850
diff changeset
109 pub unsafe fn decrease_leak_count(&self, _py: Python, mutable: bool) {
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
110 if mutable {
42939
06080afd0565 rust-cpython: add sanity check to PySharedState::decrease_leak_count()
Yuya Nishihara <yuya@tcha.org>
parents: 42891
diff changeset
111 assert_eq!(self.leak_count.get(), 0);
06080afd0565 rust-cpython: add sanity check to PySharedState::decrease_leak_count()
Yuya Nishihara <yuya@tcha.org>
parents: 42891
diff changeset
112 assert!(self.mutably_borrowed.get());
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
113 self.mutably_borrowed.replace(false);
42939
06080afd0565 rust-cpython: add sanity check to PySharedState::decrease_leak_count()
Yuya Nishihara <yuya@tcha.org>
parents: 42891
diff changeset
114 } else {
06080afd0565 rust-cpython: add sanity check to PySharedState::decrease_leak_count()
Yuya Nishihara <yuya@tcha.org>
parents: 42891
diff changeset
115 let count = self.leak_count.get();
06080afd0565 rust-cpython: add sanity check to PySharedState::decrease_leak_count()
Yuya Nishihara <yuya@tcha.org>
parents: 42891
diff changeset
116 assert!(count > 0);
06080afd0565 rust-cpython: add sanity check to PySharedState::decrease_leak_count()
Yuya Nishihara <yuya@tcha.org>
parents: 42891
diff changeset
117 self.leak_count.replace(count - 1);
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
118 }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
119 }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
120 }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
121
42849
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
122 /// `RefCell` wrapper to be safely used in conjunction with `PySharedState`.
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
123 ///
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
124 /// Only immutable operation is allowed through this interface.
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
125 #[derive(Debug)]
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
126 pub struct PySharedRefCell<T> {
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
127 inner: RefCell<T>,
43178
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
128 py_shared_state: PySharedState,
42849
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
129 }
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
130
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
131 impl<T> PySharedRefCell<T> {
43173
070a38737334 rust-cpython: move py_shared_state to PySharedRefCell object
Yuya Nishihara <yuya@tcha.org>
parents: 43082
diff changeset
132 pub fn new(value: T) -> PySharedRefCell<T> {
42849
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
133 Self {
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
134 inner: RefCell::new(value),
43173
070a38737334 rust-cpython: move py_shared_state to PySharedRefCell object
Yuya Nishihara <yuya@tcha.org>
parents: 43082
diff changeset
135 py_shared_state: PySharedState::default(),
42849
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
136 }
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
137 }
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
138
43286
f8c114f20d2d rust-cpython: require GIL to borrow immutable reference from PySharedRefCell
Yuya Nishihara <yuya@tcha.org>
parents: 43285
diff changeset
139 pub fn borrow<'a>(&'a self, _py: Python<'a>) -> Ref<'a, T> {
42849
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
140 // py_shared_state isn't involved since
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
141 // - inner.borrow() would fail if self is mutably borrowed,
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
142 // - and inner.borrow_mut() would fail while self is borrowed.
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
143 self.inner.borrow()
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
144 }
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
145
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
146 pub fn as_ptr(&self) -> *mut T {
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
147 self.inner.as_ptr()
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
148 }
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
149
43174
1c675c5fe5fe rust-cpython: move borrow_mut() to PySharedRefCell
Yuya Nishihara <yuya@tcha.org>
parents: 43173
diff changeset
150 // TODO: maybe this should be named as try_borrow_mut(), and use
1c675c5fe5fe rust-cpython: move borrow_mut() to PySharedRefCell
Yuya Nishihara <yuya@tcha.org>
parents: 43173
diff changeset
151 // inner.try_borrow_mut(). The current implementation panics if
1c675c5fe5fe rust-cpython: move borrow_mut() to PySharedRefCell
Yuya Nishihara <yuya@tcha.org>
parents: 43173
diff changeset
152 // self.inner has been borrowed, but returns error if py_shared_state
1c675c5fe5fe rust-cpython: move borrow_mut() to PySharedRefCell
Yuya Nishihara <yuya@tcha.org>
parents: 43173
diff changeset
153 // refuses to borrow.
1c675c5fe5fe rust-cpython: move borrow_mut() to PySharedRefCell
Yuya Nishihara <yuya@tcha.org>
parents: 43173
diff changeset
154 pub fn borrow_mut<'a>(
1c675c5fe5fe rust-cpython: move borrow_mut() to PySharedRefCell
Yuya Nishihara <yuya@tcha.org>
parents: 43173
diff changeset
155 &'a self,
1c675c5fe5fe rust-cpython: move borrow_mut() to PySharedRefCell
Yuya Nishihara <yuya@tcha.org>
parents: 43173
diff changeset
156 py: Python<'a>,
1c675c5fe5fe rust-cpython: move borrow_mut() to PySharedRefCell
Yuya Nishihara <yuya@tcha.org>
parents: 43173
diff changeset
157 ) -> PyResult<PyRefMut<'a, T>> {
1c675c5fe5fe rust-cpython: move borrow_mut() to PySharedRefCell
Yuya Nishihara <yuya@tcha.org>
parents: 43173
diff changeset
158 self.py_shared_state.borrow_mut(py, self.inner.borrow_mut())
42849
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
159 }
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
160 }
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
161
43178
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
162 /// Sharable data member of type `T` borrowed from the `PyObject`.
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
163 pub struct PySharedRef<'a, T> {
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
164 py: Python<'a>,
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
165 owner: &'a PyObject,
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
166 data: &'a PySharedRefCell<T>,
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
167 }
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
168
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
169 impl<'a, T> PySharedRef<'a, T> {
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
170 /// # Safety
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
171 ///
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
172 /// The `data` must be owned by the `owner`. Otherwise, the leak count
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
173 /// would get wrong.
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
174 pub unsafe fn new(
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
175 py: Python<'a>,
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
176 owner: &'a PyObject,
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
177 data: &'a PySharedRefCell<T>,
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
178 ) -> Self {
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
179 Self { py, owner, data }
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
180 }
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
181
43272
00222775d59b rust-refsharing: add missing lifetime parameter in ref_sharing
Raphaël Gomès <rgomes@octobus.net>
parents: 43180
diff changeset
182 pub fn borrow(&self) -> Ref<'a, T> {
43286
f8c114f20d2d rust-cpython: require GIL to borrow immutable reference from PySharedRefCell
Yuya Nishihara <yuya@tcha.org>
parents: 43285
diff changeset
183 self.data.borrow(self.py)
43178
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
184 }
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
185
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
186 pub fn borrow_mut(&self) -> PyResult<PyRefMut<'a, T>> {
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
187 self.data.borrow_mut(self.py)
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
188 }
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
189
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
190 /// Returns a leaked reference.
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
191 pub fn leak_immutable(&self) -> PyResult<PyLeakedRef<&'static T>> {
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
192 let state = &self.data.py_shared_state;
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
193 unsafe {
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
194 let (static_ref, static_state_ref) =
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
195 state.leak_immutable(self.py, self.data)?;
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
196 Ok(PyLeakedRef::new(
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
197 self.py,
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
198 self.owner,
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
199 static_ref,
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
200 static_state_ref,
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
201 ))
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
202 }
43178
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
203 }
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
204 }
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
205
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
206 /// Holds a mutable reference to data shared between Python and Rust.
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
207 pub struct PyRefMut<'a, T> {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
208 inner: RefMut<'a, T>,
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
209 py_shared_state: &'a PySharedState,
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
210 }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
211
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
212 impl<'a, T> PyRefMut<'a, T> {
42851
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42850
diff changeset
213 // Must be constructed by PySharedState after checking its leak_count.
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42850
diff changeset
214 // Otherwise, drop() would incorrectly update the state.
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
215 fn new(
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
216 _py: Python<'a>,
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
217 inner: RefMut<'a, T>,
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
218 py_shared_state: &'a PySharedState,
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
219 ) -> Self {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
220 Self {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
221 inner,
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
222 py_shared_state,
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
223 }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
224 }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
225 }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
226
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
227 impl<'a, T> std::ops::Deref for PyRefMut<'a, T> {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
228 type Target = RefMut<'a, T>;
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
229
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
230 fn deref(&self) -> &Self::Target {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
231 &self.inner
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
232 }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
233 }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
234 impl<'a, T> std::ops::DerefMut for PyRefMut<'a, T> {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
235 fn deref_mut(&mut self) -> &mut Self::Target {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
236 &mut self.inner
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
237 }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
238 }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
239
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
240 impl<'a, T> Drop for PyRefMut<'a, T> {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
241 fn drop(&mut self) {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
242 let gil = Python::acquire_gil();
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
243 let py = gil.python();
42851
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42850
diff changeset
244 unsafe {
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42850
diff changeset
245 self.py_shared_state.decrease_leak_count(py, true);
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42850
diff changeset
246 }
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
247 }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
248 }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
249
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
250 /// Allows a `py_class!` generated struct to share references to one of its
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
251 /// data members with Python.
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
252 ///
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
253 /// # Warning
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
254 ///
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
255 /// TODO allow Python container types: for now, integration with the garbage
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
256 /// collector does not extend to Rust structs holding references to Python
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
257 /// objects. Should the need surface, `__traverse__` and `__clear__` will
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
258 /// need to be written as per the `rust-cpython` docs on GC integration.
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
259 ///
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
260 /// # Parameters
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
261 ///
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
262 /// * `$name` is the same identifier used in for `py_class!` macro call.
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
263 /// * `$inner_struct` is the identifier of the underlying Rust struct
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
264 /// * `$data_member` is the identifier of the data member of `$inner_struct`
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
265 /// that will be shared.
43178
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
266 /// * `$shared_accessor` is the function name to be generated, which allows
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
267 /// safe access to the data member.
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
268 ///
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
269 /// # Safety
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
270 ///
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
271 /// `$data_member` must persist while the `$name` object is alive. In other
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
272 /// words, it must be an accessor to a data field of the Python object.
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
273 ///
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
274 /// # Example
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
275 ///
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
276 /// ```
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
277 /// struct MyStruct {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
278 /// inner: Vec<u32>;
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
279 /// }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
280 ///
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
281 /// py_class!(pub class MyType |py| {
42849
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
282 /// data inner: PySharedRefCell<MyStruct>;
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
283 /// });
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
284 ///
43178
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
285 /// py_shared_ref!(MyType, MyStruct, inner, inner_shared);
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
286 /// ```
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
287 macro_rules! py_shared_ref {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
288 (
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
289 $name: ident,
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
290 $inner_struct: ident,
43178
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
291 $data_member: ident,
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
292 $shared_accessor: ident
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
293 ) => {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
294 impl $name {
43178
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
295 /// Returns a safe reference to the shared `$data_member`.
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
296 ///
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
297 /// This function guarantees that `PySharedRef` is created with
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
298 /// the valid `self` and `self.$data_member(py)` pair.
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
299 fn $shared_accessor<'a>(
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
300 &'a self,
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
301 py: Python<'a>,
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
302 ) -> $crate::ref_sharing::PySharedRef<'a, $inner_struct> {
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
303 use cpython::PythonObject;
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
304 use $crate::ref_sharing::PySharedRef;
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
305 let owner = self.as_object();
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
306 let data = self.$data_member(py);
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
307 unsafe { PySharedRef::new(py, owner, data) }
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
308 }
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
309 }
43177
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
310 };
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
311 }
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
312
43177
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
313 /// Manage immutable references to `PyObject` leaked into Python iterators.
43284
ce6dd1cee4c8 rust-cpython: put leaked reference in PyLeakedRef
Yuya Nishihara <yuya@tcha.org>
parents: 43272
diff changeset
314 pub struct PyLeakedRef<T> {
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
315 inner: PyObject,
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
316 data: Option<T>,
43177
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
317 py_shared_state: &'static PySharedState,
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
318 }
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
319
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
320 // DO NOT implement Deref for PyLeakedRef<T>! Dereferencing PyLeakedRef
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
321 // without taking Python GIL wouldn't be safe.
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
322
43284
ce6dd1cee4c8 rust-cpython: put leaked reference in PyLeakedRef
Yuya Nishihara <yuya@tcha.org>
parents: 43272
diff changeset
323 impl<T> PyLeakedRef<T> {
43177
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
324 /// # Safety
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
325 ///
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
326 /// The `py_shared_state` must be owned by the `inner` Python object.
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
327 // Marked as unsafe so client code wouldn't construct PyLeakedRef
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
328 // struct by mistake. Its drop() is unsafe.
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
329 pub unsafe fn new(
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
330 py: Python,
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
331 inner: &PyObject,
43284
ce6dd1cee4c8 rust-cpython: put leaked reference in PyLeakedRef
Yuya Nishihara <yuya@tcha.org>
parents: 43272
diff changeset
332 data: T,
43177
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
333 py_shared_state: &'static PySharedState,
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
334 ) -> Self {
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
335 Self {
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
336 inner: inner.clone_ref(py),
43284
ce6dd1cee4c8 rust-cpython: put leaked reference in PyLeakedRef
Yuya Nishihara <yuya@tcha.org>
parents: 43272
diff changeset
337 data: Some(data),
43177
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
338 py_shared_state,
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
339 }
43177
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
340 }
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
341
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
342 /// Returns an immutable reference to the inner value.
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
343 pub fn get_ref<'a>(&'a self, _py: Python<'a>) -> &'a T {
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
344 self.data.as_ref().unwrap()
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
345 }
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
346
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
347 /// Returns a mutable reference to the inner value.
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
348 ///
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
349 /// Typically `T` is an iterator. If `T` is an immutable reference,
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
350 /// `get_mut()` is useless since the inner value can't be mutated.
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
351 pub fn get_mut<'a>(&'a mut self, _py: Python<'a>) -> &'a mut T {
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
352 self.data.as_mut().unwrap()
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
353 }
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
354
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
355 /// Converts the inner value by the given function.
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
356 ///
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
357 /// Typically `T` is a static reference to a container, and `U` is an
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
358 /// iterator of that container.
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
359 ///
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
360 /// # Safety
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
361 ///
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
362 /// The lifetime of the object passed in to the function `f` is cheated.
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
363 /// It's typically a static reference, but is valid only while the
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
364 /// corresponding `PyLeakedRef` is alive. Do not copy it out of the
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
365 /// function call.
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
366 pub unsafe fn map<U>(
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
367 mut self,
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
368 py: Python,
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
369 f: impl FnOnce(T) -> U,
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
370 ) -> PyLeakedRef<U> {
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
371 // f() could make the self.data outlive. That's why map() is unsafe.
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
372 // In order to make this function safe, maybe we'll need a way to
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
373 // temporarily restrict the lifetime of self.data and translate the
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
374 // returned object back to Something<'static>.
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
375 let new_data = f(self.data.take().unwrap());
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
376 PyLeakedRef {
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
377 inner: self.inner.clone_ref(py),
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
378 data: Some(new_data),
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
379 py_shared_state: self.py_shared_state,
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
380 }
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
381 }
43177
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
382 }
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
383
43284
ce6dd1cee4c8 rust-cpython: put leaked reference in PyLeakedRef
Yuya Nishihara <yuya@tcha.org>
parents: 43272
diff changeset
384 impl<T> Drop for PyLeakedRef<T> {
43177
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
385 fn drop(&mut self) {
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
386 // py_shared_state should be alive since we do have
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
387 // a Python reference to the owner object. Taking GIL makes
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
388 // sure that the state is only accessed by this thread.
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
389 let gil = Python::acquire_gil();
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
390 let py = gil.python();
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
391 if self.data.is_none() {
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
392 return; // moved to another PyLeakedRef
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
393 }
43177
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
394 unsafe {
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
395 self.py_shared_state.decrease_leak_count(py, false);
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
396 }
43177
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
397 }
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
398 }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
399
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
400 /// Defines a `py_class!` that acts as a Python iterator over a Rust iterator.
42888
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
401 ///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
402 /// TODO: this is a bit awkward to use, and a better (more complicated)
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
403 /// procedural macro would simplify the interface a lot.
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
404 ///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
405 /// # Parameters
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
406 ///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
407 /// * `$name` is the identifier to give to the resulting Rust struct.
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
408 /// * `$leaked` corresponds to `$leaked` in the matching `py_shared_ref!` call.
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
409 /// * `$iterator_type` is the type of the Rust iterator.
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
410 /// * `$success_func` is a function for processing the Rust `(key, value)`
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
411 /// tuple on iteration success, turning it into something Python understands.
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
412 /// * `$success_func` is the return type of `$success_func`
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
413 ///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
414 /// # Example
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
415 ///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
416 /// ```
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
417 /// struct MyStruct {
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
418 /// inner: HashMap<Vec<u8>, Vec<u8>>;
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
419 /// }
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
420 ///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
421 /// py_class!(pub class MyType |py| {
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
422 /// data inner: PySharedRefCell<MyStruct>;
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
423 ///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
424 /// def __iter__(&self) -> PyResult<MyTypeItemsIterator> {
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
425 /// let leaked_ref = self.inner_shared(py).leak_immutable()?;
42891
5ccc08d02280 rust-cpython: leverage py_shared_iterator::from_inner() where appropriate
Yuya Nishihara <yuya@tcha.org>
parents: 42890
diff changeset
426 /// MyTypeItemsIterator::from_inner(
42888
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
427 /// py,
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
428 /// unsafe { leaked_ref.map(py, |o| o.iter()) },
42888
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
429 /// )
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
430 /// }
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
431 /// });
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
432 ///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
433 /// impl MyType {
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
434 /// fn translate_key_value(
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
435 /// py: Python,
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
436 /// res: (&Vec<u8>, &Vec<u8>),
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
437 /// ) -> PyResult<Option<(PyBytes, PyBytes)>> {
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
438 /// let (f, entry) = res;
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
439 /// Ok(Some((
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
440 /// PyBytes::new(py, f),
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
441 /// PyBytes::new(py, entry),
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
442 /// )))
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
443 /// }
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
444 /// }
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
445 ///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
446 /// py_shared_ref!(MyType, MyStruct, inner, MyTypeLeakedRef);
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
447 ///
42889
ea91a126c803 rust-cpython: rename py_shared_iterator_impl to py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 42888
diff changeset
448 /// py_shared_iterator!(
42888
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
449 /// MyTypeItemsIterator,
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
450 /// PyLeakedRef<HashMap<'static, Vec<u8>, Vec<u8>>>,
42888
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
451 /// MyType::translate_key_value,
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
452 /// Option<(PyBytes, PyBytes)>
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
453 /// );
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
454 /// ```
42889
ea91a126c803 rust-cpython: rename py_shared_iterator_impl to py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 42888
diff changeset
455 macro_rules! py_shared_iterator {
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
456 (
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
457 $name: ident,
43177
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
458 $leaked: ty,
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
459 $success_func: expr,
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
460 $success_type: ty
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
461 ) => {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
462 py_class!(pub class $name |py| {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
463 data inner: RefCell<Option<$leaked>>;
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
464
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
465 def __next__(&self) -> PyResult<$success_type> {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
466 let mut inner_opt = self.inner(py).borrow_mut();
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
467 if let Some(leaked) = inner_opt.as_mut() {
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
468 match leaked.get_mut(py).next() {
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
469 None => {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
470 // replace Some(inner) by None, drop $leaked
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
471 inner_opt.take();
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
472 Ok(None)
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
473 }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
474 Some(res) => {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
475 $success_func(py, res)
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
476 }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
477 }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
478 } else {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
479 Ok(None)
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
480 }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
481 }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
482
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
483 def __iter__(&self) -> PyResult<Self> {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
484 Ok(self.clone_ref(py))
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
485 }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
486 });
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
487
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
488 impl $name {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
489 pub fn from_inner(
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
490 py: Python,
42890
74d67c645278 rust-cpython: remove Option<_> from interface of py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 42889
diff changeset
491 leaked: $leaked,
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
492 ) -> PyResult<Self> {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
493 Self::create_instance(
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
494 py,
42890
74d67c645278 rust-cpython: remove Option<_> from interface of py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 42889
diff changeset
495 RefCell::new(Some(leaked)),
42752
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
496 )
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
497 }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
498 }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
499 };
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
500 }