annotate rust/hg-cpython/src/ref_sharing.rs @ 43285:ffc1fbd7d1f5

rust-cpython: make PyLeakedRef operations relatively safe This patch encapsulates the access to the leaked reference to make most leaked-ref operations safe. The only exception is leaked_ref.map(). I couldn't figure out how to allow arbitrary map operation safely over an unsafe static reference. See the docstring and inline comment for details. Now leak_immutable() can be safely implemented as the PyLeakedRef owns its inner data.
author Yuya Nishihara <yuya@tcha.org>
date Sun, 15 Sep 2019 22:19:10 +0900
parents ce6dd1cee4c8
children f8c114f20d2d
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: 42943
diff changeset
1 // ref_sharing.rs
42768
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: 42943
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: 42943
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: 42943
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: 42943
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: 42943
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: 42943
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: 42943
diff changeset
11 //
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42943
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: 42943
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: 42943
diff changeset
14 //
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42943
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: 42943
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: 42943
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: 42943
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: 42943
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: 42943
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: 42943
diff changeset
21 // IN THE SOFTWARE.
42768
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};
42855
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
27 use std::cell::{Cell, Ref, RefCell, RefMut};
42768
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)]
42768
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
42768
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.
42768
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.
42857
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42856
diff changeset
80 ///
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42856
diff changeset
81 /// # Safety
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42856
diff changeset
82 ///
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42856
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: 42856
diff changeset
84 /// extended. Do not call this function directly.
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42856
diff changeset
85 pub unsafe fn leak_immutable<T>(
42768
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,
42855
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
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)> {
42768
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?
42768
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;
42768
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))
42768
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
42857
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42856
diff changeset
105 /// # Safety
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42856
diff changeset
106 ///
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42856
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: 42856
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: 42856
diff changeset
109 pub unsafe fn decrease_leak_count(&self, _py: Python, mutable: bool) {
42768
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
110 if mutable {
42943
06080afd0565 rust-cpython: add sanity check to PySharedState::decrease_leak_count()
Yuya Nishihara <yuya@tcha.org>
parents: 42897
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: 42897
diff changeset
112 assert!(self.mutably_borrowed.get());
42768
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
113 self.mutably_borrowed.replace(false);
42943
06080afd0565 rust-cpython: add sanity check to PySharedState::decrease_leak_count()
Yuya Nishihara <yuya@tcha.org>
parents: 42897
diff changeset
114 } else {
06080afd0565 rust-cpython: add sanity check to PySharedState::decrease_leak_count()
Yuya Nishihara <yuya@tcha.org>
parents: 42897
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: 42897
diff changeset
116 assert!(count > 0);
06080afd0565 rust-cpython: add sanity check to PySharedState::decrease_leak_count()
Yuya Nishihara <yuya@tcha.org>
parents: 42897
diff changeset
117 self.leak_count.replace(count - 1);
42768
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
42855
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
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: 42849
diff changeset
123 ///
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
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: 42849
diff changeset
125 #[derive(Debug)]
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
126 pub struct PySharedRefCell<T> {
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
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,
42855
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
129 }
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
130
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
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> {
42855
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
133 Self {
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
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(),
42855
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
136 }
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
137 }
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
138
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
139 pub fn borrow(&self) -> Ref<T> {
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
140 // py_shared_state isn't involved since
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
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: 42849
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: 42849
diff changeset
143 self.inner.borrow()
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
144 }
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
145
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
146 pub fn as_ptr(&self) -> *mut T {
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
147 self.inner.as_ptr()
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
148 }
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
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())
42855
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
159 }
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
160 }
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
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> {
43178
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
183 self.data.borrow()
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
42768
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> {
42857
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42856
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: 42856
diff changeset
214 // Otherwise, drop() would incorrectly update the state.
42768
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();
42857
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42856
diff changeset
244 unsafe {
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42856
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: 42856
diff changeset
246 }
42768
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.
42768
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| {
42855
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
282 /// data inner: PySharedRefCell<MyStruct>;
42768
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);
42768
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
42768
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 }
42768
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 }
42768
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 }
42768
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,
42768
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 }
42768
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);
42768
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 }
42768
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.
42894
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
401 ///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
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: 42893
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: 42893
diff changeset
404 ///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
405 /// # Parameters
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
406 ///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
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: 42893
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: 42893
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: 42893
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: 42893
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: 42893
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: 42893
diff changeset
413 ///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
414 /// # Example
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
415 ///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
416 /// ```
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
417 /// struct MyStruct {
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
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: 42893
diff changeset
419 /// }
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
420 ///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
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: 42893
diff changeset
422 /// data inner: PySharedRefCell<MyStruct>;
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
423 ///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
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()?;
42897
5ccc08d02280 rust-cpython: leverage py_shared_iterator::from_inner() where appropriate
Yuya Nishihara <yuya@tcha.org>
parents: 42896
diff changeset
426 /// MyTypeItemsIterator::from_inner(
42894
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
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()) },
42894
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
429 /// )
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
430 /// }
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
431 /// });
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
432 ///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
433 /// impl MyType {
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
434 /// fn translate_key_value(
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
435 /// py: Python,
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
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: 42893
diff changeset
437 /// ) -> PyResult<Option<(PyBytes, PyBytes)>> {
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
438 /// let (f, entry) = res;
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
439 /// Ok(Some((
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
440 /// PyBytes::new(py, f),
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
441 /// PyBytes::new(py, entry),
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
442 /// )))
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
443 /// }
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
444 /// }
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
445 ///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
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: 42893
diff changeset
447 ///
42895
ea91a126c803 rust-cpython: rename py_shared_iterator_impl to py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 42894
diff changeset
448 /// py_shared_iterator!(
42894
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
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>>>,
42894
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
451 /// MyType::translate_key_value,
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
452 /// Option<(PyBytes, PyBytes)>
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
453 /// );
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
454 /// ```
42895
ea91a126c803 rust-cpython: rename py_shared_iterator_impl to py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 42894
diff changeset
455 macro_rules! py_shared_iterator {
42768
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,
42768
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() {
42768
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,
42896
74d67c645278 rust-cpython: remove Option<_> from interface of py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 42895
diff changeset
491 leaked: $leaked,
42768
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,
42896
74d67c645278 rust-cpython: remove Option<_> from interface of py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 42895
diff changeset
495 RefCell::new(Some(leaked)),
42768
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 }