Mercurial > public > mercurial-scm > hg
comparison rust/pyo3-sharedref/src/lib.rs @ 52612:a945845137b1
rust-pyo3-sharedref: share/map methods on PyShareable
The pattern to borrow (with owner) for the sole purpose of calling
`share_immutable`, and then `map()` is pretty common, being exactly
what is needed in the constructors of derived Python objects.
we therefore introduce new helpers doing exactly that. We keep the
intermediate `share()` and `try_share()` that are used in integration
tests, but is is possible that consumers of the API never need it.
A nice feature of the new `share_map()` helper is that it collapses
all the unsafety in constructors of derived object to one call. It makes
sense, since the reason for unsafety is the same all along the call stack:
the `owner` object, that cannot be guessed from `PyShareable` itself, must
be the right one.
It is remarkable that it is only at this point that the compiler insists
that `T` should be `'static`, which is actually very reasonable, as it
encompasses owned data. We could have set it since the beginning, but the
added value is low, as PyO3 would not let us use some `PyShareable<&'a T>`
as a Python object data field (with `'a` not outliving `'static` of course)
author | Georges Racinet <georges.racinet@cloudcrane.io> |
---|---|
date | Sun, 15 Dec 2024 15:36:11 +0100 |
parents | 4a73eb3923ac |
children | 76a0bdb0e4ca |
comparison
equal
deleted
inserted
replaced
52611:4a73eb3923ac | 52612:a945845137b1 |
---|---|
108 /// impl SetIterator { | 108 /// impl SetIterator { |
109 /// #[new] | 109 /// #[new] |
110 /// fn new(s: &Bound<'_, Set>) -> Self { | 110 /// fn new(s: &Bound<'_, Set>) -> Self { |
111 /// let py = s.py(); | 111 /// let py = s.py(); |
112 /// let rust_set = &s.borrow().rust_set; | 112 /// let rust_set = &s.borrow().rust_set; |
113 /// let shareable_ref = unsafe { rust_set.borrow_with_owner(s) }; | 113 /// let iter = unsafe { rust_set.share_map(s, |o| o.iter()) }; |
114 /// let shared_set = shareable_ref.share_immutable(); | |
115 /// let iter = unsafe { shared_set.map(py, |o| o.iter()) }; | |
116 /// Self { | 114 /// Self { |
117 /// rust_iter: iter.into(), | 115 /// rust_iter: iter.into(), |
118 /// } | 116 /// } |
119 /// } | 117 /// } |
120 /// | 118 /// |
175 pub struct PyShareable<T: ?Sized> { | 173 pub struct PyShareable<T: ?Sized> { |
176 state: PySharedState, | 174 state: PySharedState, |
177 data: RwLock<T>, | 175 data: RwLock<T>, |
178 } | 176 } |
179 | 177 |
180 impl<T> PyShareable<T> { | 178 impl<T: 'static> PyShareable<T> { |
181 /// Borrows the shared data and its state, keeping a reference | 179 /// Borrows the shared data and its state, keeping a reference |
182 /// on the owner Python object. | 180 /// on the owner Python object. |
183 /// | 181 /// |
184 /// # Safety | 182 /// # Safety |
185 /// | 183 /// |
193 PyShareableRef { | 191 PyShareableRef { |
194 owner, | 192 owner, |
195 state: &self.state, | 193 state: &self.state, |
196 data: &self.data, | 194 data: &self.data, |
197 } | 195 } |
196 } | |
197 | |
198 /// Share for other Python objects | |
199 /// | |
200 /// # Safety | |
201 /// | |
202 /// The `data` must be owned by the `owner`. Otherwise, the resulting | |
203 /// [`SharedByPyObject`] would contain an invalid reference. | |
204 pub unsafe fn share<'py>( | |
205 &'py self, | |
206 owner: &'py Bound<'py, PyAny>, | |
207 ) -> SharedByPyObject<&'static T> { | |
208 self.borrow_with_owner(owner).share_immutable() | |
209 } | |
210 | |
211 /// Share for other Python objects, transforming the inner data | |
212 /// with a closure | |
213 /// | |
214 /// # Safety | |
215 /// | |
216 /// The `data` must be owned by the `owner`. Otherwise, the resulting | |
217 /// [`SharedByPyObject`] would contain an invalid reference. | |
218 pub unsafe fn share_map<'py, U>( | |
219 &'py self, | |
220 owner: &'py Bound<'py, PyAny>, | |
221 f: impl FnOnce(&'static T) -> U, | |
222 ) -> SharedByPyObject<U> { | |
223 self.share(owner).map(owner.py(), f) | |
224 } | |
225 | |
226 /// # Safety | |
227 /// | |
228 /// The `data` must be owned by the `owner`. Otherwise, the resulting | |
229 /// [`SharedByPyObject`] would contain an invalid reference. | |
230 pub unsafe fn try_share<'py>( | |
231 &'py self, | |
232 owner: &'py Bound<'py, PyAny>, | |
233 ) -> Result<SharedByPyObject<&'static T>, TryShareError> { | |
234 self.borrow_with_owner(owner).try_share_immutable() | |
235 } | |
236 | |
237 /// # Safety | |
238 /// | |
239 /// The `data` must be owned by the `owner`. Otherwise, the resulting | |
240 /// [`SharedByPyObject`] would contain an invalid reference. | |
241 pub unsafe fn try_share_map<'py, U>( | |
242 &'py self, | |
243 owner: &'py Bound<'py, PyAny>, | |
244 f: impl FnOnce(&'static T) -> U, | |
245 ) -> Result<SharedByPyObject<U>, TryShareError> { | |
246 Ok(self.try_share(owner)?.map(owner.py(), f)) | |
198 } | 247 } |
199 } | 248 } |
200 | 249 |
201 impl<T> From<T> for PyShareable<T> { | 250 impl<T> From<T> for PyShareable<T> { |
202 fn from(value: T) -> Self { | 251 fn from(value: T) -> Self { |